從頭擼一個單鏈表

@醉裏挑燈看劍,夢迴吹角連營

  最近在學習單鏈表時,對於單鏈表的頭節點指針的創建,以及如何給一個鏈表存入數據,這塊理解不是很到位。雖然明白鏈表的基本操作,創建、插入、刪除、索引,但用C實現還是遇到一些問題難以理解,故寫一些代碼進行分析,終於弄清楚其實現過程,在此作一小結。

單鏈表操作分析

  分析單鏈表中,節點的建立、插入、刪除等過程

定義鏈表結構

//本文鏈表存儲int型數據爲例
typedef struct Signal_Node {
	int data;
	struct Signal_Node *next;
}Node;

節點的建立

通過malloc函數在堆中開闢節點空間,用來存放數據及指向下一個節點空間的結構體指針變量,結構如下:
單鏈表節點的建立

頭節點的建立

建立頭節點,必須先定義一個指向頭節點的結構體指針變量Node *hp = NULL,便於之後對鏈表進行操作
單鏈表頭節點的建立

插入新的節點

從鏈表頭插入節點

先生成新的節點空間 Node *newnd,作爲要插入的新節點元素
從鏈表頭插入新節點

從鏈表尾部插入

與從頭節點插入一樣,只是指向下一個節點的指針爲空
1、遍歷鏈表,直到 p -> next = NULL   // p爲最後一個節點指針
2、p -> next = newnd;
3、newnd -> next = NULL;        //已插入節點

從指定位置插入

從指定位置插入節點
1、遍歷鏈表,找到要插入的鏈表位置p,if(p -> data == index) return p;
2、newnd -> next = p -> next -> next;
3、p -> next = newnd;

刪除節點分析

  刪除節點的過程,即與插入節點的過程相反。需要注意的是,刪除某個節點,必須知道上一個節點的指針,即上一個節點中存放將要刪除節點中的指針。每刪除一個節點,需要將該節點空間賦空NULL,並且釋放該空間free()

找到刪除節點的上一個節點指針 *p

1、int temp_data = p -> next -> data ,臨時存放被刪除節點中的數據
2、遍歷鏈表直到 temp_data == index,對比索引數據,找到上一個節點指針 p
3、返回 p

刪除節點 p -> next

1、Node *temp = p -> next // 將需要刪除的節點指針暫存,供之後釋放該空間所用
2、p -> next = p -> next -> next   // 刪除該節點 p -> next
3、temp = NULL && free(temp) // 將該節點空間賦空,並且釋放該空間

代碼實現

  本代碼使用基本數據類型int,從main函數開始,一步步實現鏈表的建立,鏈表中節點的插入,以及向節點中輸入數據,最後一個個刪除釋放節點空間在等操作,方便加深對鏈表創建及操作的理解。完整代碼如下:

/**
* @file Signal_node_base.c
* @author mahuiming, [email protected]
* @date 2019-04-01
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define LINK_NODE_NUM 5

typedef struct SignalNode {

    int data;
    struct SignalNode *next;
}Node;

/* 創建節點 */
Node *Sig_CreateNode(int data, int dataSize) {

    Node *p = (Node *)malloc(sizeof(Node));
    static int i = 0;
    if(NULL == p)
        printf("開闢節點空間失敗!\n");
    p -> next = NULL;
    p -> data = data;
    printf("成功創建節點 %d\n",i);
    i++;
    return p;
}
/* 插入一個新的節點 */
void InsertNode(Node *p, Node *newnd) {

    newnd -> next = p -> next;
    p -> next = newnd;
}
/* 將節點從鏈表頭部插入 */
void HeadInsertNode(Node *hp, Node *newnd) {

    InsertNode(hp,newnd);
}
/* 將節點從鏈表尾部插入 */
void TailInsertNode(Node *hp, Node *newnd) {

    Node *p = hp; 
    while(1) {

        if(p -> next == NULL){
            InsertNode(p, newnd);
            break;
        }
        p = p -> next;
    }   
}
/* 創建一個鏈表 */
void createList(Node **hpp) {

    //創建一個數據爲int類型的頭節點,傳入參數0 和 sizeof(int)
    *hpp = Sig_CreateNode(0, 4);
    (*hpp) -> next = NULL;
}
/* 向鏈表中存值,建立鏈表 */
void setList(Node *hp, int data) {

        Node *newnd = Sig_CreateNode(data, sizeof(data));
    //  HeadInsertNode(hp, newnd);     
        TailInsertNode(hp, newnd);
}
/* 打印鏈表中的數據 */
void ShowList(Node *hp) {

    Node *p = hp -> next;
    if(NULL == p)
        printf("鏈表爲空\n");
    else {
        while(1) {
            if(NULL == p)
                break;
            printf("鏈表中的數據爲:%d \n",p -> data);
            p = p -> next;
        }
    }
}
/* 找到被刪除節點的上一個節點 */
Node *Find_Delnode_Prev(Node *hp, int index) {

    Node *p = hp;
    static int temp_data = 0;
    while(1) {
        temp_data = p -> next -> data;
        if(temp_data == index) {
            printf("將要刪除數據爲 %d 的節點...\n",temp_data);
            printf("\n");
            break;
        }
        p = p -> next;
    }
    return p;
}
/* 刪除節點 */
void Delete_Node(Node *del_node) {
    Node *temp = del_node -> next;
    del_node -> next = del_node -> next -> next;
    temp = NULL;
    free(temp);
}

int main() {
    int a = 0, i = 0, index = 0;
    Node *hp = NULL;
    Node *prev_node = NULL;
    /* 創建空鏈表*/
    createList(&hp);
    /* 向鏈表中寫入數據 */
    for(i = 0; i < LINK_NODE_NUM; i++) {

        printf("Insert data:\n");
        scanf("%d",&a);
        setList(hp, a);
    }
    /* 顯示所有鏈表信息 */
    ShowList(hp);
    printf("顯示所有鏈表數據結束!\n");
    printf("\n");
    printf("開始刪除鏈表中的節點~\n");
    for(i = 0; i < LINK_NODE_NUM; i++) {
        printf("輸入要刪除節點中的數據:");
        scanf("%d",&index);
        prev_node = Find_Delnode_Prev(hp, index);
        Delete_Node(prev_node);
        ShowList(hp);
    }
    /* 釋放頭節點指針 */
    free(hp);
    return 0;
}

程序運行過程:

成功創建節點 0
Insert data:
100
成功創建節點 1
Insert data:
200
成功創建節點 2
Insert data:
300
成功創建節點 3
Insert data:
400
成功創建節點 4
Insert data:
500
成功創建節點 5
鏈表中的數據爲:100
鏈表中的數據爲:200
鏈表中的數據爲:300
鏈表中的數據爲:400
鏈表中的數據爲:500
顯示所有鏈表數據結束!
開始刪除鏈表中的節點~
輸入要刪除節點中的數據:300
將要刪除數據爲 300 的節點…
鏈表中的數據爲:100
鏈表中的數據爲:200
鏈表中的數據爲:400
鏈表中的數據爲:500
輸入要刪除節點中的數據:200
將要刪除數據爲 200 的節點…
鏈表中的數據爲:100
鏈表中的數據爲:400
鏈表中的數據爲:500
輸入要刪除節點中的數據:100
將要刪除數據爲 100 的節點…
鏈表中的數據爲:400
鏈表中的數據爲:500
輸入要刪除節點中的數據:500
將要刪除數據爲 500 的節點…
鏈表中的數據爲:400
輸入要刪除節點中的數據:400
將要刪除數據爲 400 的節點…
鏈表爲空

  通過代碼實現及畫圖分析,會對單鏈表的一些操作更容易理解一些

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章