寫在前面的話:
- 版權聲明:本文爲博主原創文章,轉載請註明出處!
- 博主是一個小菜鳥,並且非常玻璃心!如果文中有什麼問題,請友好地指出來,博主查證後會進行更正,啾咪~~
- 每篇文章都是博主現階段的理解,如果理解的更深入的話,博主會不定時更新文章。
- 本文最後更新時間:2020.4.27
什麼是鏈表
鏈表是程序設計中一種重要的動態數據結構,它是動態地進行存儲分配的一種結構。
分爲三種:
- 單鏈表
- 循環鏈表
- 雙向鏈表
動態性體現在:
- 鏈表中的元素個數可以根據需要增加和減少,不像數組,在聲明之後就固定不變。
- 元素的位置可以變化,即可以從某個位置刪除,然後再插入到一個新的地方。
結點裏的指針存放下一個結點的地址
- 鏈表中的元素稱爲“結點”,每個結點包括兩個域:數據域和指針域。
- 單向鏈表通常有一個頭指針(head),用於指向鏈表頭,也是指向鏈表在內存的首地址。
- 單向鏈表有一個尾結點,該結點的指針部分指向一個空節點(NULL)。
代碼示例
1. 定義鏈表的數據結構
/* =================
定義鏈表數據結構
================= */
struct node
{
int num;
struct node *next; //next存放下一個結點的地址
};
一個指針類型的成員既可指向其他類型的結構體數據,也可以指向自己所在的結構體類型的數據。
next 是 struct node 類型中的一個成員,它又指向 struct node 類型的數據。
2. 創建頭指針
#include <stdio.h>
#include <stdlib.h>
/* =================
定義鏈表數據結構
================= */
struct node
{
int num;
struct node *next; //next存放下一個結點的地址
};
typedef struct node Node;
typedef Node * Link;
/* ===================
功能:初始化頭指針
返回:void
=================== */
void init_head_node(Link *head)
{
*head = NULL; //頭指針置空
}
int main()
{
Link head; //創建頭指針
init_head_node(&head); //初始化頭指針
return 0;
}
3. 插入節點
3.1 頭插
從鏈表的頭部插入新的節點。
#include <stdio.h>
#include <stdlib.h>
/* =================
定義鏈表數據結構
================= */
struct node
{
int num;
struct node *next; //next存放下一個結點的地址
};
typedef struct node Node;
typedef Node * Link;
/* ===================
功能:初始化頭指針
返回:void
=================== */
void init_head_node(Link *head)
{
*head = NULL; //頭指針置空
}
/* =========================
功能:從鏈表頭部插入結點
返回:void
========================= */
void insert_head_node(Link newnode, Link *head)
{
newnode->next = *head;
*head = newnode;
}
/* =================
功能:打印鏈表
返回:void
================= */
void display_link(Link head)
{
Link temp = head;
while (temp != NULL) //遍歷鏈表
{
printf("%d\n", temp->num);
temp = temp->next;
}
}
int main()
{
Link head; //創建頭指針
Link newnode; //創建新結點
init_head_node(&head); //初始化頭指針
for (int i = 0; i < 10; i++)
{
newnode = (Link)malloc(sizeof(Node)); //逐一爲結點分配空間
newnode->num = i + 1; //逐一爲結點數據域賦值
insert_head_node(newnode,&head); //頭插
}
printf("頭插後的鏈表爲:\n");
display_link(head); //打印鏈表
return 0;
}
運行結果:
頭插後的鏈表爲:
10
9
8
7
6
5
4
3
2
1
3.2 尾插
從鏈表的尾部插入新的節點。
#include <stdio.h>
#include <stdlib.h>
/* =================
定義鏈表數據結構
================= */
struct node
{
int num;
struct node *next; //next存放下一個結點的地址
};
typedef struct node Node;
typedef Node * Link;
/* ===================
功能:初始化頭指針
返回:void
=================== */
void init_head_node(Link *head)
{
*head = NULL; //頭指針置空
}
/* =========================
功能:從鏈表尾部插入結點
返回:void
========================= */
void insert_tail_node(Link newnode, Link *head)
{
if (NULL == *head) //判斷是否爲空表
{
newnode->next = NULL;
*head = newnode;
}
else
{
Link temp = *head;
while (temp->next != NULL) //找到最後一個結點
{
temp = temp->next;
}
temp->next = newnode; //插入結點
newnode->next = NULL;
}
}
/* =================
功能:打印鏈表
返回:void
================= */
void display_link(Link head)
{
Link temp = head;
while (temp != NULL) //遍歷鏈表
{
printf("%d\n", temp->num);
temp = temp->next;
}
}
int main()
{
Link head; //創建頭指針
Link newnode; //創建新結點
init_head_node(&head); //初始化頭指針
for (int i = 0; i < 10; i++)
{
newnode = (Link)malloc(sizeof(Node)); //逐一爲結點分配空間
newnode->num = i + 1; //逐一爲結點數據域賦值
insert_tail_node(newnode,&head); //尾插
}
printf("尾插後的鏈表爲:\n");
display_link(head); //打印鏈表
return 0;
}
運行結果:
尾插後的鏈表爲:
1
2
3
4
5
6
7
8
9
10
3.3 中間插入
從鏈表的中間插入新的節點。
#include <stdio.h>
#include <stdlib.h>
/* =================
定義鏈表數據結構
================= */
struct node
{
int num;
struct node *next; //next存放下一個結點的地址
};
typedef struct node Node;
typedef Node * Link;
/* ===================
功能:初始化頭指針
返回:void
=================== */
void init_head_node(Link *head)
{
*head = NULL; //頭指針置空
}
/* =========================
功能:從鏈表尾部插入結點
返回:void
========================= */
void insert_tail_node(Link newnode, Link *head)
{
if (NULL == *head) //判斷是否爲空表
{
newnode->next = NULL;
*head = newnode;
}
else
{
Link temp = *head;
while (temp->next != NULL) //找到最後一個結點
{
temp = temp->next;
}
temp->next = newnode; //插入結點
newnode->next = NULL;
}
}
/* =====================
功能:從中間插入結點
返回:是否成功執行
===================== */
int insert_mid_node(Link newnode, Link head, int num)
{
if (NULL == head) //判斷是否爲空表,空表則退出
{
return -1;
}
Link temp = head;
while (temp != NULL) //遍歷鏈表
{
if (num == temp->num) //判斷是否爲要插入的目標結點,是則插入
{
newnode->next = temp->next;
temp->next = newnode;
return 0;
}
temp = temp->next;
}
return -1; //遍歷整個鏈表也找不到目標結點,退出
}
/* =================
功能:打印鏈表
返回:void
================= */
void display_link(Link head)
{
Link temp = head;
while (temp != NULL) //遍歷鏈表
{
printf("%d\n", temp->num);
temp = temp->next;
}
}
int main()
{
Link head; //創建頭指針
Link newnode; //創建新結點
init_head_node(&head); //初始化頭指針
for (int i = 0; i < 10; i++)
{
newnode = (Link)malloc(sizeof(Node)); //逐一爲結點分配空間
newnode->num = i + 1; //逐一爲結點數據域賦值
insert_tail_node(newnode,&head); //尾插
}
newnode = (Link)malloc(sizeof(Node)); //爲新結點分配空間
newnode->num = 11;
insert_mid_node(newnode,head,5); //在數據域爲5的結點後插入結點
printf("從中間插入後的鏈表爲:\n");
display_link(head); //打印鏈表
return 0;
}
運行結果:
從中間插入後的鏈表爲:
1
2
3
4
5
11
6
7
8
9
10
4. 遍歷鏈表
/* =================
功能:打印鏈表
返回:void
================= */
void display_link(Link head)
{
Link temp = head;
while (temp != NULL) //遍歷鏈表
{
printf("%d\n", temp->num);
temp = temp->next;
}
}
找最後一個結點:temp->next != NULL;
找所有結點:temp != NULL;
5. 刪除結點
#include <stdio.h>
#include <stdlib.h>
/* =================
定義鏈表數據結構
================= */
struct node
{
int num;
struct node *next; //next存放下一個結點的地址
};
typedef struct node Node;
typedef Node * Link;
/* ===================
功能:初始化頭指針
返回:void
=================== */
void init_head_node(Link *head)
{
*head = NULL; //頭指針置空
}
/* =========================
功能:從鏈表尾部插入結點
返回:void
========================= */
void insert_tail_node(Link newnode, Link *head)
{
if (NULL == *head) //判斷是否爲空表
{
newnode->next = NULL;
*head = newnode;
}
else
{
Link temp = *head;
while (temp->next != NULL) //找到最後一個結點
{
temp = temp->next;
}
temp->next = newnode; //插入結點
newnode->next = NULL;
}
}
/* ===================
功能:刪除某個結點
返回:是否成功
=================== */
int del_mid_node(Link *head, int num)
{
if (NULL == *head) //判斷是否爲空表,空表則退出
{
return -1;
}
Link temp = *head;
if (num == (*head)->num) //判斷頭結點是否是要刪除的結點,是則刪除
{
*head = (*head)->next; //刪除結點
free(temp); //釋放
temp = NULL; //置空
return 0;
}
Link ptr = temp; //ptr指向temp的結點
temp = temp->next; //temp指向下一個結點,即ptr指向temp前面的結點
while (temp != NULL) //遍歷鏈表
{
if (num == temp->num) //判斷是否是要刪除的結點,是則刪除
{
ptr->next = temp->next;
free(temp);
temp = NULL;
return 0;
}
ptr = temp;
temp = temp->next;
}
return -1; //遍歷整個鏈表也找不到目標結點,則退出
}
/* =================
功能:打印鏈表
返回:void
================= */
void display_link(Link head)
{
Link temp = head;
while (temp != NULL) //遍歷鏈表
{
printf("%d\n", temp->num);
temp = temp->next;
}
}
int main()
{
Link head; //創建頭指針
Link newnode; //創建新結點
init_head_node(&head); //初始化頭指針
for (int i = 0; i < 10; i++)
{
newnode = (Link)malloc(sizeof(Node)); //逐一爲結點分配空間
newnode->num = i + 1; //逐一爲結點數據域賦值
insert_tail_node(newnode,&head); //尾插
}
del_mid_node(&head,5); //刪除數據域爲5的結點
printf("刪除數據域爲5的結點後的鏈表爲:\n");
display_link(head); //打印鏈表
return 0;
}
運行結果:
刪除數據域爲5的結點後的鏈表爲:
1
2
3
4
6
7
8
9
10
6. 鏈表逆序
#include <stdio.h>
#include <stdlib.h>
/* =================
定義鏈表數據結構
================= */
struct node
{
int num;
struct node *next; //next存放下一個結點的地址
};
typedef struct node Node;
typedef Node * Link;
/* ===================
功能:初始化頭指針
返回:void
=================== */
void init_head_node(Link *head)
{
*head = NULL; //頭指針置空
}
/* =========================
功能:從鏈表尾部插入結點
返回:void
========================= */
void insert_tail_node(Link newnode, Link *head)
{
if (NULL == *head) //判斷是否爲空表
{
newnode->next = NULL;
*head = newnode;
}
else
{
Link temp = *head;
while (temp->next != NULL) //找到最後一個結點
{
temp = temp->next;
}
temp->next = newnode; //插入結點
newnode->next = NULL;
}
}
/* ===============
功能:逆序鏈表
返回:是否成功
=============== */
int reverse_link(Link *head)
{
/*判斷是否爲空表或只有一個結點,是則退出*/
if (NULL == *head || NULL == (*head)->next)
{
return -1;
}
Link str = *head;
Link ptr = str->next;
Link temp = ptr->next;
while (NULL != temp)
{
ptr->next = str;
str = ptr;
ptr = temp;
temp = temp->next;
}
ptr->next = str;
(*head)->next = NULL;
*head = ptr;
return 0;
}
/* =================
功能:打印鏈表
返回:void
================= */
void display_link(Link head)
{
Link temp = head;
while (temp != NULL) //遍歷鏈表
{
printf("%d\n", temp->num);
temp = temp->next;
}
}
int main()
{
Link head; //創建頭指針
Link newnode; //創建新結點
init_head_node(&head); //初始化頭指針
for (int i = 0; i < 10; i++)
{
newnode = (Link)malloc(sizeof(Node)); //逐一爲結點分配空間
newnode->num = i + 1; //逐一爲結點數據域賦值
insert_tail_node(newnode,&head); //尾插
}
reverse_link(&head);
printf("逆序後的鏈表爲:\n");
display_link(head); //打印鏈表
return 0;
}
運行結果:
逆序後的鏈表爲:
10
9
8
7
6
5
4
3
2
1