?本節復習鏈表的增刪查改
首先, 鏈表不是連續的, 而是通過指針聯系起來的。 如圖:
這四個節點不是連續的內存空間, 但是彼此之間使用了一個指針來連接。 這就是鏈表。?
現在我們來實現鏈表的增刪查改。
目錄
單鏈表的全部接口:
?準備文件
建立結構體藍圖
申請鏈表節點函數接口
單鏈表的打印函數接口
單鏈表尾插函數接口
單鏈表頭插函數接口
?單鏈表尾刪函數接口
單鏈表的頭刪函數接口
?單鏈表查找函數接口
單鏈表pos位置之后插入數據接口
單鏈表刪除pos之后位置的數據
單鏈表在pos位置之前插入數據接口
單鏈表刪除pos位置數據接口
單鏈表的銷毀
單鏈表的全部接口:
//申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x);
//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x);
//單鏈表在pos之后的位置刪除數據
void SListPopAfter(SLNode* pos);
//單鏈表在pos位置之前插入數據接口
void SListInsert(SLNode** pphead, SLNode* pos, SLTDataType x);
//單鏈表在pos位置刪除數據接口
void SListPop(SLNode** pphead, SLNode* pos);
//單鏈表的銷毀函數接口
void SLTDestory(SLNode** pphead);
?
---------------------------------------------------------------------------------------------------------------------------------
?準備文件
首先準備好三個文件夾, 一個main.c文件夾, 一個.h文件夾用來聲明鏈表的接口以及定義結構體等。 一個.c文件夾用來實現單鏈表。
---------------------------------------------------------------------------------------------------------------------------------
建立結構體藍圖
首先包含一下頭文件, 定義一下數據類型。
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;
接著再建立一個鏈表的結構體
#include<stdio.h> #include<assert.h> #include<stdlib.h>typedef int SLTDataType;typedef struct SListNode {struct SListNode* next;SLTDataType data; }SLNode;
---------------------------------------------------------------------------------------------------------------------------------
申請鏈表節點函數接口
申請鏈表的節點操作, 在尾插, 頭插, 或者特定位置插入的時候都需要, 所以可以封裝成一個函數。 后續直接進行復用就可以。
.h函數聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode //創建結構體
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
.c函數實現
單鏈表函數實現函數接口//單鏈表申請節點函數接口
SLNode* BuySListNode(SLTDataType x)
{SLNode* NewNode = (SLNode*)malloc(sizeof(SLNode));if (NewNode == NULL) {printf("申請節點失敗\n");return;}//NewNode->data = x;NewNode->next = NULL;
}
?在實現的過程中,可以將數據直接儲存到新節點中。 然后讓新節點指向NULL, 然后返回該節點。 然后將鏈表直接連接到這個節點就可以。
---------------------------------------------------------------------------------------------------------------------------------
單鏈表的打印函數接口
為了便于后續的函數接口的調試, 我們先實現單鏈表的打印操作。
.h函數聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
.c函數實現
單鏈表函數實現函數接口//單鏈表申請節點函數接口
SLNode* BuySListNode(SLTDataType x)
{SLNode* NewNode = (SLNode*)malloc(sizeof(SLNode));if (NewNode == NULL) {printf("申請節點失敗\n");return;}//NewNode->data = x;NewNode->next = NULL;
}//單鏈表的節點打印操作
void SListPrint(SLNode* phead)
{SLNode* cur = phead;while (cur != NULL) {printf("%d->", cur->data);cur = cur->next;}if (cur == NULL)//最后打印一個NULL{printf("NULL");}}
---------------------------------------------------------------------------------------------------------------------------------
單鏈表尾插函數接口
.h函數聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
.c函數實現
單鏈表函數實現函數接口//單鏈表申請節點函數接口
SLNode* BuySListNode(SLTDataType x)
{SLNode* NewNode = (SLNode*)malloc(sizeof(SLNode));if (NewNode == NULL) {printf("申請節點失敗\n");return;}//NewNode->data = x;NewNode->next = NULL;
}//單鏈表的節點打印操作
void SListPrint(SLNode* phead)
{SLNode* cur = phead;while (cur != NULL) {printf("%d->", cur->data);cur = cur->next;}if (cur == NULL)//最后打印一個NULL{printf("NULL");}}//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//利用申請節點函數申請節點SLNode* cur = *pphead; //讓cur指向phead所指向空間if (cur == NULL) //cur == NULL代表著phead指向NULL, 這時候讓phead改變指向。傳送phead指針的原因就是{ //要改變phead的指向。*pphead = newnode;//}else {while (cur->next != NULL) //讓cur遍歷到最后一個節點{cur = cur->next;}cur->next = newnode;//最后}}
尾插接口時傳送phead的指針的原因是因為phead可能改變指向,從空指針變為指向一個節點。要改變phead的指向那就是意味著形參要相對于phead傳址調用,??而phead本身就是一個一級指針, phead取地址就是一個二級指針, 所以形參是二級指針。
---------------------------------------------------------------------------------------------------------------------------------
單鏈表頭插函數接口
.h函數接口
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
.c函數實現
單鏈表函數實現函數接口//單鏈表申請節點函數接口
SLNode* BuySListNode(SLTDataType x)
{SLNode* NewNode = (SLNode*)malloc(sizeof(SLNode));if (NewNode == NULL) {printf("申請節點失敗\n");return;}//NewNode->data = x;NewNode->next = NULL;
}//單鏈表的節點打印操作
void SListPrint(SLNode* phead)
{SLNode* cur = phead;while (cur != NULL) {printf("%d->", cur->data);cur = cur->next;}if (cur == NULL)//最后打印一個NULL{printf("NULL");}}//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//利用申請節點函數申請節點SLNode* cur = *pphead; //讓cur指向phead所指向空間if (cur == NULL) //cur == NULL代表著phead指向NULL, 這時候讓phead改變指向。傳送phead指針的原因就是{ //要改變phead的指向。*pphead = newnode;//}else {while (cur->next != NULL) //讓cur遍歷到最后一個節點{cur = cur->next;}cur->next = newnode;//最后}}//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//SLNode* cur = *pphead;newnode->next = cur;*pphead = newnode;}
現在我們來利用打印接口調試一下我們寫的是否存在問題。?
在main.c中輸入如下代碼
void TestSListNode()
{SLNode* phead = NULL;SListPushBack(&phead, 1);SListPushBack(&phead, 2);SListPushBack(&phead, 3);SListPushBack(&phead, 4);SListPushBack(&phead, 5);SListPushFront(&phead, 0);SListPrint(phead);printf("\n");/*SListPopFront(&phead);SListPopFront(&phead);SListPopFront(&phead);SListPopBack(&phead);SListPrint(phead);printf("\n");SLTDestory(&phead);SListPrint(phead);printf("\n");*/}int main()
{
// TestTree();
// TestStack();
// TestQueue();
// TestSeqList();TestSListNode();
// TestDSLNode();
// TestOJ();return 0;
}
運行圖如下:?
?通過檢驗,沒有問題。 繼續往下走。?
---------------------------------------------------------------------------------------------------------------------------------
?單鏈表尾刪函數接口
.h文件聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
.c函數實現
??首先pphead不能為空, 如果phead指向空的話就直接返回。 然后定義cur和prev兩個指針, 遍歷尋找尾節點。 cur領先prev一個節點, cur指向尾節點的時候, 就釋放掉這個節點。 然后prev指向空節點。 尋找尾節點的過程是這樣的:
代碼實現
單鏈表函數實現函數接口//單鏈表申請節點函數接口
SLNode* BuySListNode(SLTDataType x)
{SLNode* NewNode = (SLNode*)malloc(sizeof(SLNode));if (NewNode == NULL) {printf("申請節點失敗\n");return;}//NewNode->data = x;NewNode->next = NULL;
}//單鏈表的節點打印操作
void SListPrint(SLNode* phead)
{SLNode* cur = phead;while (cur != NULL) {printf("%d->", cur->data);cur = cur->next;}if (cur == NULL)//最后打印一個NULL{printf("NULL");}}//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//利用申請節點函數申請節點SLNode* cur = *pphead; //讓cur指向phead所指向空間if (cur == NULL) //cur == NULL代表著phead指向NULL, 這時候讓phead改變指向。傳送phead指針的原因就是{ //要改變phead的指向。*pphead = newnode;//}else {while (cur->next != NULL) //讓cur遍歷到最后一個節點{cur = cur->next;}cur->next = newnode;//最后}}//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//SLNode* cur = *pphead;newnode->next = cur;*pphead = newnode;}//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead)
{assert(pphead);if (*pphead == NULL)return;//SLNode* cur = *pphead;SLNode* prev = *pphead;while (cur->next != NULL) //對鏈表進行遍歷。 cur最終會指向尾節點。 prev用來維護鏈表{prev = cur;cur = cur->next;}if (prev == cur) {free(cur);*pphead = NULL;}else {free(cur);prev = NULL;}}
---------------------------------------------------------------------------------------------------------------------------------
單鏈表的頭刪函數接口
.h函數聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
.c函數實現?
單鏈表函數實現函數接口//單鏈表申請節點函數接口
SLNode* BuySListNode(SLTDataType x)
{SLNode* NewNode = (SLNode*)malloc(sizeof(SLNode));if (NewNode == NULL) {printf("申請節點失敗\n");return;}//NewNode->data = x;NewNode->next = NULL;
}//單鏈表的節點打印操作
void SListPrint(SLNode* phead)
{SLNode* cur = phead;while (cur != NULL) {printf("%d->", cur->data);cur = cur->next;}if (cur == NULL)//最后打印一個NULL{printf("NULL");}}//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//利用申請節點函數申請節點SLNode* cur = *pphead; //讓cur指向phead所指向空間if (cur == NULL) //cur == NULL代表著phead指向NULL, 這時候讓phead改變指向。傳送phead指針的原因就是{ //要改變phead的指向。*pphead = newnode;//}else {while (cur->next != NULL) //讓cur遍歷到最后一個節點{cur = cur->next;}cur->next = newnode;//最后}}//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//SLNode* cur = *pphead;newnode->next = cur;*pphead = newnode;}//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead)
{assert(pphead);if (*pphead == NULL)return;//SLNode* cur = *pphead;SLNode* prev = *pphead;while (cur->next != NULL) //對鏈表進行遍歷。 cur最終會指向尾節點。 prev用來維護鏈表{prev = cur;cur = cur->next;}if (prev == cur) {free(cur);*pphead = NULL;}else {free(cur);prev = NULL;}}//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead)
{assert(pphead);if (*pphead == NULL)return;//SLNode* cur = *pphead;*pphead = cur->next;free(cur);
}
代碼的意思是, 首先pphead不能為空, 然后phead不能指向空。?然后讓一個cur指針指向頭節點。 然后修改phead的指向, 使其指向第二個節點(當第二個節點是空的時候, 就是指向空)。然后釋放cur指向的節點也就是頭節點。 如圖為過程:
---------------------------------------------------------------------------------------------------------------------------------
?單鏈表查找函數接口
.h接口聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x);
.c接口實現
單鏈表函數實現函數接口//單鏈表申請節點函數接口
SLNode* BuySListNode(SLTDataType x)
{SLNode* NewNode = (SLNode*)malloc(sizeof(SLNode));if (NewNode == NULL) {printf("申請節點失敗\n");return;}//NewNode->data = x;NewNode->next = NULL;
}//單鏈表的節點打印操作
void SListPrint(SLNode* phead)
{SLNode* cur = phead;while (cur != NULL) {printf("%d->", cur->data);cur = cur->next;}if (cur == NULL)//最后打印一個NULL{printf("NULL");}}//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//利用申請節點函數申請節點SLNode* cur = *pphead; //讓cur指向phead所指向空間if (cur == NULL) //cur == NULL代表著phead指向NULL, 這時候讓phead改變指向。傳送phead指針的原因就是{ //要改變phead的指向。*pphead = newnode;//}else {while (cur->next != NULL) //讓cur遍歷到最后一個節點{cur = cur->next;}cur->next = newnode;//最后}}//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//SLNode* cur = *pphead;newnode->next = cur;*pphead = newnode;}//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead)
{assert(pphead);if (*pphead == NULL)return;//SLNode* cur = *pphead;SLNode* prev = *pphead;while (cur->next != NULL) //對鏈表進行遍歷。 cur最終會指向尾節點。 prev用來維護鏈表{prev = cur;cur = cur->next;}if (prev == cur) {free(cur);*pphead = NULL;}else {free(cur);prev = NULL;}}//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead)
{assert(pphead);if (*pphead == NULL)return;//SLNode* cur = *pphead;*pphead = cur->next;free(cur);
}//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x)
{SLNode* cur = phead;//定義一個指向頭節點的指針, 用于遍歷while (cur != NULL) //向后遍歷{if (cur->data == x) //找到節點后就返回節點的地址。{return cur;}cur = cur->next;}return NULL;
}
?代碼太長, 之后.c文件的代碼只展示相應接口的代碼
---------------------------------------------------------------------------------------------------------------------------------
單鏈表pos位置之后插入數據接口
.h接口聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x);
//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x);
.c接口實現?
//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x)
{assert(pos);SLNode* newnode = BuySListNode(x);//SLNode* cur = pos->next;newnode->next = cur;pos->next = newnode;
}
?該接口的實現過程如下:
令指針cur指向pos的下一個節點, newnode的next指向cur, pos的next指向newnode
---------------------------------------------------------------------------------------------------------------------------------
單鏈表刪除pos之后位置的數據
.h接口聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x);
//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x);
//單鏈表在pos之后的位置刪除數據
void SListPopAfter(SLNode* pos);
.c接口實現
//單鏈表在pos之后的位置刪除數據
void SListPopAfter(SLNode* pos)
{assert(pos);//SLNode* cur = pos->next;pos->next = pos->next->next;free(cur);
}
該接口實現和單鏈表在pos位置之后插入數據接口實現方式類似, 都是利用一個cur指針指向pos之后的位置作為記憶保存,然后進行插入或者刪除操作。?
---------------------------------------------------------------------------------------------------------------------------------
單鏈表在pos位置之前插入數據接口
該接口的實現有點復雜, 但是實現該接口之后, 對于尾插還有頭插就很好實現了, 尾插和頭插是該接口的兩個特殊情況。 假如pos是頭節點,就是頭插, 假如pos是尾節點, 就是尾插。
.h接口聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x);
//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x);
//單鏈表在pos之后的位置刪除數據
void SListPopAfter(SLNode* pos);
//單鏈表在pos位置之前插入數據接口
void SListInsert(SLNode** pphead, SLNode* pos, SLTDataType x);
.c接口實現
//單鏈表在pos位置之前插入數據接口
void SListInsert(SLNode** pphead, SLNode* pos, SLTDataType x)
{assert(pphead);//SLNode* newnode = BuySListNode(x);//if (*pphead == NULL) {*pphead = newnode;return;}//if (*pphead == pos) {newnode->next = pos;*pphead = newnode;return;}SLNode* cur = *pphead;while (cur != NULL && cur->next != pos) {cur = cur->next;}newnode->next = pos;cur->next = newnode;
}
該接口分為三種情況:
第一種是鏈表為空, 這個時候直接插入節點。
第二種情況是pos的位置在第一個節點的位置, 這個時候需要改變phead的指向。?
第三種情況就是最普通的情況, 在除頭節點, 鏈表的任意節點前插入。如圖:
?
---------------------------------------------------------------------------------------------------------------------------------
單鏈表刪除pos位置數據接口
和pos位置插入數據接口一樣, 實現了該接口對于尾刪, 頭刪接口就很簡單了。 頭刪, 尾刪都是單鏈表刪除pos位置數據接口的特殊情況。 pos是頭節點, 就是頭刪, pos是尾節點。 就是尾刪。?
.h接口聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x);
//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x);
//單鏈表在pos之后的位置刪除數據
void SListPopAfter(SLNode* pos);
//單鏈表在pos位置之前插入數據接口
void SListInsert(SLNode** pphead, SLNode* pos, SLTDataType x);
//單鏈表在pos位置刪除數據接口
void SListPop(SLNode** pphead, SLNode* pos);
.c接口實現
//單鏈表在pos位置刪除數據接口
void SListPop(SLNode** pphead, SLNode* pos)
{assert(pphead);//if (*pphead == pos) {*pphead = (*pphead)->next;free(pos);}else {SLNode* cur = *pphead;while (cur->next != pos) {cur->next = pos->next;free(pos);}}
}
pos位置刪除分兩種情況
一種是頭刪, 需要phead改變指向。
?一種是其他位置刪除節點
單鏈表的銷毀
?鏈表使用完之后應該銷毀, 放置內存泄漏
.h接口聲明
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x);
//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x);
//單鏈表在pos之后的位置刪除數據
void SListPopAfter(SLNode* pos);
//單鏈表在pos位置之前插入數據接口
void SListInsert(SLNode** pphead, SLNode* pos, SLTDataType x);
//單鏈表在pos位置刪除數據接口
void SListPop(SLNode** pphead, SLNode* pos);
//單鏈表的銷毀函數接口
void SLTDestory(SLNode** pphead);
.c接口實現?
//單鏈表的銷毀函數接口
void SLTDestory(SLNode** pphead)
{assert(pphead);if (*pphead == NULL) {return;}SLNode* prev = (*pphead);SLNode* cur = (*pphead)->next;if (cur == NULL) {*pphead = NULL;free(prev);}else {*pphead = NULL;while(cur != NULL){free(prev);prev = cur;cur = cur->next;}free(prev);}}
銷毀需要一步一步的進行, 如下圖:
現在來看一下總體代碼:
.h文件
鏈表的增刪查改///
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;typedef struct SListNode
{struct SListNode* next;SLTDataType data;
}SLNode;//鏈表接口聲明///申請鏈表節點函數接口
SLNode* BuySListNode(SLTDataType x);
//單鏈表的打印函數接口
void SListPrint(SLNode* phead);
//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x);
//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x);
//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead);
//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead);
//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x);
//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x);
//單鏈表在pos之后的位置刪除數據
void SListPopAfter(SLNode* pos);
//單鏈表在pos位置之前插入數據接口
void SListInsert(SLNode** pphead, SLNode* pos, SLTDataType x);
//單鏈表在pos位置刪除數據接口
void SListPop(SLNode** pphead, SLNode* pos);
//單鏈表的銷毀函數接口
void SLTDestory(SLNode** pphead);
.c文件
單鏈表函數實現函數接口//單鏈表申請節點函數接口
SLNode* BuySListNode(SLTDataType x)
{SLNode* NewNode = (SLNode*)malloc(sizeof(SLNode));if (NewNode == NULL) {printf("申請節點失敗\n");return;}//NewNode->data = x;NewNode->next = NULL;
}//單鏈表的節點打印操作
void SListPrint(SLNode* phead)
{SLNode* cur = phead;while (cur != NULL) {printf("%d->", cur->data);cur = cur->next;}if (cur == NULL)//最后打印一個NULL{printf("NULL");}}//單鏈表尾插函數接口
void SListPushBack(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//利用申請節點函數申請節點SLNode* cur = *pphead; //讓cur指向phead所指向空間if (cur == NULL) //cur == NULL代表著phead指向NULL, 這時候讓phead改變指向。傳送phead指針的原因就是{ //要改變phead的指向。*pphead = newnode;//}else {while (cur->next != NULL) //讓cur遍歷到最后一個節點{cur = cur->next;}cur->next = newnode;//最后}}//單鏈表頭插函數接口
void SListPushFront(SLNode** pphead, SLTDataType x)
{assert(pphead);SLNode* newnode = BuySListNode(x);//SLNode* cur = *pphead;newnode->next = cur;*pphead = newnode;}//單鏈表尾刪函數接口
void SListPopBack(SLNode** pphead)
{assert(pphead);if (*pphead == NULL)return;//SLNode* cur = *pphead;SLNode* prev = *pphead;while (cur->next != NULL) //對鏈表進行遍歷。 cur最終會指向尾節點。 prev用來維護鏈表{prev = cur;cur = cur->next;}if (prev == cur) {free(cur);*pphead = NULL;}else {free(cur);prev = NULL;}}//單鏈表的頭刪函數接口
void SListPopFront(SLNode** pphead)
{assert(pphead);if (*pphead == NULL)return;//SLNode* cur = *pphead;*pphead = cur->next;free(cur);
}//單鏈表查找函數接口
SLNode* SListFind(SLNode* phead, SLTDataType x)
{SLNode* cur = phead;//定義一個指向頭節點的指針, 用于遍歷while (cur != NULL) //向后遍歷{if (cur->data == x) //找到節點后就返回節點的地址。{return cur;}cur = cur->next;}return NULL;
}//單鏈表在pos位置之后插入數據接口
void SListInsertAfter(SLNode* pos, SLTDataType x)
{assert(pos);SLNode* newnode = BuySListNode(x);//SLNode* cur = pos->next;newnode->next = cur;pos->next = newnode;
}//單鏈表在pos之后的位置刪除數據
void SListPopAfter(SLNode* pos)
{assert(pos);//SLNode* cur = pos->next;pos->next = pos->next->next;free(cur);
}//單鏈表在pos位置之前插入數據接口
void SListInsert(SLNode** pphead, SLNode* pos, SLTDataType x)
{assert(pphead);//SLNode* newnode = BuySListNode(x);//if (*pphead == NULL) {*pphead = newnode;return;}//if (*pphead == pos) {newnode->next = pos;*pphead = newnode;return;}SLNode* cur = *pphead;while (cur != NULL && cur->next != pos) {cur = cur->next;}newnode->next = pos;cur->next = newnode;
}//單鏈表在pos位置刪除數據接口
void SListPop(SLNode** pphead, SLNode* pos)
{assert(pphead);//if (*pphead == pos) {*pphead = (*pphead)->next;free(pos);}else {SLNode* cur = *pphead;while (cur->next != pos) {cur->next = pos->next;free(pos);}}
}//單鏈表的銷毀函數接口
void SLTDestory(SLNode** pphead)
{assert(pphead);if (*pphead == NULL) {return;}SLNode* prev = (*pphead);SLNode* cur = (*pphead)->next;if (cur == NULL) {*pphead = NULL;free(prev);}else {*pphead = NULL;while(cur != NULL){free(prev);prev = cur;cur = cur->next;}free(prev);}}