鏈表
鏈表用于解決合理利用存儲(chǔ)空間的問(wèn)題
malloc在沒(méi)有連續(xù)內(nèi)存空間的時(shí)候分配會(huì)失敗
-
解決方案:
- 不要一次性開(kāi)辟一塊連續(xù)的存儲(chǔ)空間, 每次少開(kāi)辟一點(diǎn)
最后利用指針將所有開(kāi)辟的小的存儲(chǔ)空間鏈接在一起, 組成一個(gè)整體
- 不要一次性開(kāi)辟一塊連續(xù)的存儲(chǔ)空間, 每次少開(kāi)辟一點(diǎn)
靜態(tài)鏈表
typedef struct node{
int data; // 專(zhuān)門(mén)用于存儲(chǔ)數(shù)據(jù)的
struct node *next; // 專(zhuān)門(mén)用于實(shí)現(xiàn)鏈接的
} Node;
int main()
{
// 1.定義三個(gè)結(jié)構(gòu)體
Node a;
Node b;
Node c;
// 2.讓三個(gè)結(jié)構(gòu)體保存數(shù)據(jù)
a.data = 1;
b.data = 3;
c.data = 5;
// 3.將三個(gè)結(jié)構(gòu)體鏈接在一起
a.next = &b;
b.next = &c;
// 如果指針沒(méi)有值, 那么就可以賦值為NULL, 明確告訴系統(tǒng)該指針沒(méi)有值
// 如果一個(gè)指針沒(méi)有值,也沒(méi)有賦值為NULL, 那么這個(gè)指針就是一個(gè)野指針
// 注意: 一定不要操作沒(méi)有值的指針和野指針
c.next = NULL;
// 4.定義鏈表的頭指針
Node *head = &a;
return 0;
}
空鏈表
- 只有一個(gè)頭指針和頭結(jié)點(diǎn),并且頭結(jié)點(diǎn)沒(méi)有下一個(gè)結(jié)點(diǎn)且沒(méi)有數(shù)據(jù)
#include <studio.h>
Node * createNode();
typedef struct node{
int data;
struct node *next;
} Node;
int main()
{
Node *head = createNode();
return 0;
}
Node *createNode()
{
//1.創(chuàng)建一個(gè)頭結(jié)點(diǎn)
Node *head= (Node *)malloc(sizeof(Node));
//1.1可能分配失敗
if(head == NULL)
{
exit(-1);
}
//2.下一個(gè)節(jié)點(diǎn)賦值為空
head -> next = NULL;
return head;
}
-
內(nèi)存分配圖解:
動(dòng)態(tài)鏈表尾差法
- 規(guī)則:
1.把新結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)指向頭結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)
2.把頭結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)指向新結(jié)點(diǎn)
代碼如下:
#include <stdio.h>
typedef struct node
{
int data;
struct node *next;
} Node;
void printList(Node * head);
Node *createList();
int main()
{
//0.創(chuàng)建頭結(jié)點(diǎn)和頭指針
Node *head = createList();
//1.打印數(shù)據(jù)
printList(head);
return 0;
}
void printList(Node * head){
//1.接收頭指針,頭指針指向頭結(jié)點(diǎn)
//2.頭結(jié)點(diǎn)是沒(méi)有數(shù)據(jù)的,我們可以將頭指針直接指向頭結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)
//輸出數(shù)據(jù)
Node *cur = head;
while(cur->next != NULL){
cur = cur -> next;
printf("%d\n",cur -> data);
}
/**
* @brief createList 尾差法創(chuàng)建動(dòng)態(tài)鏈表
* @return 返回頭指針
*/
Node *createList(){
//1.創(chuàng)建頭指針和頭結(jié)點(diǎn)
Node *head = (Node *)malloc(sizeof(Node));
if(head == NULL){
exit(-1);
}
head -> next = NULL;
//1.用一個(gè)變量表示循環(huán)條件
//2.提示用戶輸入要保存的數(shù)據(jù)
int num = 0;
printf("請(qǐng)輸入想要保存的數(shù)據(jù),輸入-1結(jié)束\n");
scanf("%d",&num);
while(-1 != num)
{
Node *node = (Node*)malloc(sizeof(Node));
//保存數(shù)據(jù)
node -> data = num;
//1.把新結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)指向頭結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)
node -> next = head -> next;
//2.把頭結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)指向新結(jié)點(diǎn)
head -> next = node;
printf("請(qǐng)輸入想要保存的數(shù)據(jù),輸入-1結(jié)束\n");
scanf("%d",&num);
}
return head;
}
-
圖解
動(dòng)態(tài)鏈表頭插法
- 規(guī)則:
1.定義變量記錄最后一個(gè)結(jié)點(diǎn)
2.讓新結(jié)點(diǎn)成為上一個(gè)結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)
3.把新結(jié)點(diǎn)作為下一個(gè)結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn)
#include <stdio.h>
typedef struct node
{
int data;
struct node *next;
} Node;
Node *createList();
void printList(Node *head);
int main()
{
//動(dòng)態(tài)鏈表頭插法
Node *head = createList();
printList(head);
return 0;
}
void printList(Node *head){
Node *cur = head;
while(cur->next != NULL)//首先判斷不是空鏈表
{
cur = cur -> next;
printf("%d\n",cur -> data);
}
}
Node *createList(){
//1.創(chuàng)建頭結(jié)點(diǎn)和頭指針
Node *head = (Node*)malloc(sizeof(Node));
//分配失敗
if(head == NULL){
exit(-1);
}
head->next = NULL;
//定義變量控制循環(huán)
int num = -1;
printf("請(qǐng)輸入你想要保存的數(shù)據(jù):\n");
scanf("%d",&num);
//1.定義變量記錄最后一個(gè)結(jié)點(diǎn)
Node *cur = head;//一定要放在最外面,否則會(huì)引起值覆蓋
while(-1 != num)
{
Node *node = (Node*)malloc(sizeof(Node));
node->data = num;
node->next = NULL;
//2.讓新結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)指向新結(jié)點(diǎn)
cur->next = node;
//3.把新結(jié)點(diǎn)作為下一個(gè)結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn)
cur = node;
printf("請(qǐng)輸入你想要保存的數(shù)據(jù):\n");
scanf("%d",&num);
}
return head;
}
-
圖解
封裝
- 我們可以封裝一個(gè)創(chuàng)建空鏈表的函數(shù)
/**
* @brief createEmpty 創(chuàng)建空鏈表
* @return 鏈表的頭指針
*/
Node *createEmpty(){
// 1.定義頭指針
Node *head = NULL;
// 2.創(chuàng)建一個(gè)空節(jié)點(diǎn), 并且賦值給頭指針
head = (Node *)malloc(sizeof(Node));
head->next = NULL;
// 3.返回頭指針
return head;
}
- 我們可以將插入數(shù)據(jù)封裝成一個(gè)函數(shù)
void insertNode(Node *head, int num){
// 1.創(chuàng)建一個(gè)新的節(jié)點(diǎn)
Node *node = (Node *)malloc(sizeof(Node));
// 2.將數(shù)據(jù)保存到新節(jié)點(diǎn)中
node->data = num;
// 3.進(jìn)行插入
// 3.1讓新節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn) 等于 頭節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
node->next = head->next;
// 3.2讓頭結(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn) 等于 新節(jié)點(diǎn)
head->next = node;
}
- 我們可以封裝一個(gè)銷(xiāo)毀鏈表的函數(shù)
// 封裝一個(gè)專(zhuān)門(mén)用于銷(xiāo)毀鏈表的函數(shù)
/**
* @brief destroyList 銷(xiāo)毀鏈表
* @param head 鏈表的頭指針
*/
void destroyList(Node *head){
Node *cur = NULL;
while(head != NULL){
cur = head->next;
free(head);
head = cur;
}
}
- 我們可以封裝一個(gè)計(jì)算鏈表長(zhǎng)度的函數(shù)
// 封裝一個(gè)專(zhuān)門(mén)用于計(jì)算鏈表長(zhǎng)度的函數(shù)
int listLength(Node *head){
// 1.定義變量記錄節(jié)點(diǎn)的個(gè)數(shù)
int count = 0;
// 注意點(diǎn): 頭結(jié)點(diǎn)不要
Node *cur = head->next;
// 2.遍歷統(tǒng)計(jì)節(jié)點(diǎn)個(gè)數(shù)
while(cur != NULL){
count++;
cur = cur->next;
}
return count;
}
- 我們可以封裝一個(gè)查找指定結(jié)點(diǎn)的函數(shù)
// 封裝一個(gè)專(zhuān)門(mén)用于查找指定節(jié)點(diǎn)的函數(shù)
/**
* @brief findNode 查找指定節(jié)點(diǎn)
* @param head 鏈表的頭指針
* @param key 需要查找的key
* @return 符合要求的節(jié)點(diǎn), 如果找不到返回NULL
*/
Node *findNode(Node* head, int key){
// 注意點(diǎn): 頭結(jié)點(diǎn)不需要查找
head = head->next;
while(head != NULL){
// 判斷當(dāng)前節(jié)點(diǎn)保存的值是否是要查找的值
if(head->data == key){
return head;
}else{
head = head->next;
}
}
return NULL;
}
- 我們可以封裝一個(gè)刪除指定結(jié)點(diǎn)的函數(shù)
//封裝一個(gè)專(zhuān)門(mén)用于刪除指定節(jié)點(diǎn)的函數(shù)
/**
* @brief deleteNode 刪除指定節(jié)點(diǎn)
* @param head 鏈表的頭指針
* @param node 需要?jiǎng)h除的節(jié)點(diǎn)
*/
void deleteNode(Node *head, Node *node){
// 1.找到需要?jiǎng)h除節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)
while(head->next != node){
head = head->next;
}
// 2.將刪除節(jié)點(diǎn)上一個(gè)節(jié)點(diǎn)的next改為 , 刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
head->next = node->next;
// 3.刪除對(duì)應(yīng)節(jié)點(diǎn)
free(node);
}


