@醉裏挑燈看劍,夢迴吹角連營
最近在學習單鏈表時,對於單鏈表的頭節點指針的創建,以及如何給一個鏈表存入數據,這塊理解不是很到位。雖然明白鏈表的基本操作,創建、插入、刪除、索引,但用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 的節點…
鏈表爲空
通過代碼實現及畫圖分析,會對單鏈表的一些操作更容易理解一些