1. 程式人生 > 其它 >bilibiliclass22-28_資料結構與演算法_線性表的鏈式表示和實現

bilibiliclass22-28_資料結構與演算法_線性表的鏈式表示和實現

技術標籤:資料結構與演算法_嗶哩嗶哩課堂筆記

知識回顧

順序表的特點:以物理位置相鄰表示邏輯關係。

順序表的優點:任一元素均可隨機存取。

順序表的缺點:進行插入和刪除操作時,需移動大量的元素。儲存空間不靈活

鏈式儲存結構

結點在儲存器中的位置是任意的,即邏輯上相鄰的資料元素在物理上不一定相鄰

這組儲存單元既可以是連續的,也可以是不連續的,甚至是零散分佈在記憶體中的任意位置上的。

例子1

線性表:(趙,錢,孫,李,周,吳,鄭,王)

例子2

例:26個英文小寫字母表的鏈式儲存結構
邏輯結構:( a, b,... ,y,z)

與鏈式儲存有關的術語

1、結點:資料元素的儲存映象。由資料域和指標域兩部分組成

資料域:儲存元素數值資料
指標域:儲存直接後繼結點的儲存位置

2、連結串列:n個結點由指標鏈組成一個連結串列。

單鏈表、雙鏈表、迴圈連結串列:

結點只有一個指標域的連結串列,稱為單鏈表或線性連結串列

單鏈表是由頭指標唯一確定,因此單鏈表可以用頭指標的名字來命名。


結點有兩個指標域的連結串列,稱為L為雙鏈表


首尾相接的連結串列稱為迴圈連結串列

頭指標 頭結點 首元結點


頭指標:是指向連結串列中第一個結點的指標

首元結點:是指連結串列中儲存第一個資料元素a1的結點

頭結點:是在連結串列的首元結點之前附設的一個結點;

前面的例子中的連結串列的儲存結構示意圖有以下兩種形式:

①不帶頭結點


②帶頭結點

頭結點好處

1便於首元結點的處理
首元結點的地址儲存在頭結點的指標域中,所以在連結串列的第一個位置上的操作和其它位置一致,無須進行特殊處理;
2便於空表和非空表的統一處理
無論連結串列是否為空,頭指標都是指向頭結點的非空指標,因此空表和非空表的處理也就統一了。

3.頭結點的資料域可以為空,也可存放線性表長度等附加資訊,但此結點不能計入連結串列長度值

空表

無頭結點時,頭指標為空時表示空表

有頭結點時,當頭結點的指標域為空時表示空表

連結串列(鏈式儲存結構)的特點

(1)結點在儲存器中的位置是任意的,即邏輯上相鄰的資料元素在物理上不一定相鄰。
(2)訪問時只能通過頭指標進入連結串列,並通過每個結點的指標域依次向後順序掃描其餘結點,所以尋找第一個結點和最後一個結點所花費的時間不等

知識回顧

線性表的鏈式儲存結構
線性表中資料元素(結點)在儲存器中的位置是任意的,即邏輯上相鄰的資料元素在物理位置上不一定相鄰。
結點
資料│指標
連結串列 n個結點由指標鏈組成一個連結串列。連結串列是順序存取的。
單鏈表:每個結點只有一個指標域
雙鏈表:每個結點有兩個指標域

迴圈連結串列:連結串列結點首尾相接

單鏈表基本操作的實現

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//連結串列的資料域
struct student
{
    char name[20];
    int num;
};


//連結串列的樣子
struct Node {
    struct student data;
    struct Node* next;
};

//建立表頭,即單鏈表的初始化
struct Node* creatList()
{
    struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
    //headNode 成為了結構體變數
    //headNode->next=1;
    headNode->next = NULL;
    return headNode;
}

//建立節點
struct Node* creatNode(struct student data)
{
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

//列印節點,遍歷節點
void printList(struct Node* headNode)
{
    struct Node* pMove = headNode->next;
    printf("name\tnum\n");
    while (pMove)
    {
        printf("%s\t%d\n",pMove->data.name, pMove->data.num);
        pMove = pMove->next;
    }
    printf("\n");
}


//表頭法插入
void insertNodeByHead(struct Node* headNode, struct student data)
{
    //1.建立插入的結點
    struct Node* newNode = creatNode(data);
    newNode->next = headNode->next;
    headNode->next = newNode;
}

//連結串列的刪除:指定位置的刪除
void deleteNodeByAppoinNum(struct Node* headNode, int num)
{
    struct Node* posNode = headNode->next;
    struct Node* posNodeFront = headNode;
    if (posNode == NULL)
        printf("無法刪除,連結串列為空\n");
    else
    {
        while (posNode->data.num != num)
        {
            posNodeFront = posNode;
            posNode = posNodeFront->next;
            if (posNode == NULL)
            {
                printf("沒有找到相關資訊,無法刪除\n");
                return;
            }
        }
        posNodeFront->next = posNode->next;
        free(posNode);
    }
}

//判斷連結串列是否為空
//空表:連結串列中無元素,稱為空連結串列(頭指標和頭結點仍然在)
//若L為空表,則返回1,否則返回0
int ListEmpty(struct Node* list) 
{
    if (list->next)//非空
        return 0;
    else
        return 1;
}


//銷燬單鏈表
void DestroyList_L(struct Node* list) 
{
    struct Node* p;
    while (list)
    {
        p = list;
        list = list->next;
        free(p);
    }
    return 1;
}

//清空連結串列:連結串列-->空表
void ClearList(struct Node* list)
{
    struct Node* p,*q;
    p = list->next;
    while (p)//沒有到表尾
    {
        q = p->next;
        free(p);
        p = q;
    }
    //頭指標設定為空
    list->next = NULL;
    return 1;
}

//求單鏈表的表長
int countList(struct Node* list)
{
    struct Node* p = list->next;//p指向第一個節點
    int count = 0;
    while (p!=NULL)//遍歷
    {
        p = p->next;
        count++;
    }
    return count;
}


int main()
{
    struct Node* list = creatList();
    struct student info;
    while (1)
    {
        printf("請輸入學生的姓名 學號:>");
        setbuf(stdin, NULL);
        scanf("%s%d",&info.name,&info.num);
        insertNodeByHead(list,info);
        printf("continue(Y/N)");
        setbuf(stdin,NULL);
        int choice = getchar();
        if (choice == 'N' || choice == 'n')
        {
            break;
        }
    }
    printList(list);
    printf("請輸入要刪除學生的學號:>");
    scanf("%d", &info.num);
    deleteNodeByAppoinNum(list, info.num);
    printList(list);
    ClearList(list);
    printList(list);
    return 0;
}