目錄
創(chuàng)新互聯(lián)是一家專(zhuān)注于網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè)與策劃設(shè)計(jì),臨漳網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專(zhuān)注于網(wǎng)站建設(shè)十余年,網(wǎng)設(shè)計(jì)領(lǐng)域的專(zhuān)業(yè)建站公司;建站業(yè)務(wù)涵蓋:臨漳等地區(qū)。臨漳做網(wǎng)站價(jià)格咨詢(xún):028-86922220前言
一、什么是鏈表
1.1鏈表的結(jié)構(gòu)和概念
1.2 鏈表的分類(lèi)
二、無(wú)頭單向非循環(huán)鏈表
2.1 創(chuàng)建結(jié)構(gòu)體
2.2 動(dòng)態(tài)申請(qǐng)一個(gè)節(jié)點(diǎn)
2.3 單鏈表打印
2.4 單鏈表尾插/尾刪
2.4.1 單鏈表尾插
2.4.2 單鏈表尾刪
2.5 單鏈表頭插/頭刪
2.5.1 頭插
2.5.2 頭刪
2.6 單鏈表查找
2.7 單鏈表中間插入/中間刪除
2.7.1 中間插入
2.7.2 中間刪除
2.8 單鏈表銷(xiāo)毀
三、雙向帶頭循環(huán)鏈表
3.1 結(jié)構(gòu)體的創(chuàng)建
3.2 創(chuàng)造節(jié)點(diǎn)
3.3 創(chuàng)建返回鏈表的頭結(jié)點(diǎn)(哨兵位)
3.4 雙鏈表打印
3.5 雙鏈表的尾插/尾刪
3.5.1 尾插
3.5.2 尾刪
3.6 雙鏈表的頭插/頭刪
3.6.1 頭插
3.6.2 頭刪
3.7 雙鏈表的查找
3.8 雙鏈表的中間插入/中間刪除
3.8.1 中間插入
3.8.2 中間刪除
3.9 雙鏈表的銷(xiāo)毀
四、鏈表和順序表的區(qū)別
五、代碼及代碼展示
5.1 單向鏈表
5.1.1 效果展示
5.1.2 代碼
5.2 雙向帶頭循環(huán)鏈表
5.2.1 效果展示
5.2.2 代碼
總結(jié)
大家好,本篇文章主要帶領(lǐng)大家了解一下什么是鏈表,鏈表的兩個(gè)主要結(jié)構(gòu),以及鏈表和順序表的差別。
概念:鏈表是一種物理存儲(chǔ)結(jié)構(gòu)上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯順序是通過(guò)鏈表中的指針鏈接次序?qū)崿F(xiàn)的 。
鏈表就像是火車(chē),每塊空間都獨(dú)立存在,彼此通過(guò)指針相鏈接。
鏈表的數(shù)據(jù)結(jié)構(gòu)如下所示:
1.2 鏈表的分類(lèi)注意:
1.從上圖看出,鏈?zhǔn)浇Y(jié)構(gòu)邏輯上是連續(xù)的,但在內(nèi)存中的存儲(chǔ)可能是不連續(xù)的。
2.現(xiàn)實(shí)中的節(jié)點(diǎn)一般都是在堆上面申請(qǐng)的。
3.從堆上面申請(qǐng)空間是有其規(guī)律的,兩次申請(qǐng)的空間可能連續(xù)也可能不連續(xù)。
實(shí)際中鏈表的結(jié)構(gòu)非常多樣,以下情況組合起來(lái)就有8種鏈表結(jié)構(gòu):
1.單向或者雙向
2.帶頭(哨兵位)或者不帶頭
3.循環(huán)或者非循環(huán)
8種鏈表結(jié)構(gòu)分別是:?jiǎn)蜗蜴湵?,單向帶頭,單向循環(huán),單向帶頭循環(huán),雙向鏈表,雙向帶頭,雙向循環(huán),雙向帶頭循環(huán)
其中最常用的有兩個(gè)分別是單向鏈表,雙向帶頭循環(huán)鏈表。
1. 無(wú)頭單向非循環(huán)鏈表:結(jié)構(gòu)簡(jiǎn)單,一般不會(huì)單獨(dú)用來(lái)存數(shù)據(jù)。實(shí)際中更多是作為其他數(shù)據(jù)結(jié)構(gòu)的子結(jié)構(gòu),如哈希桶、圖的鄰接表等等
2.帶頭雙向循環(huán)鏈表:結(jié)構(gòu)最復(fù)雜,一般用在單獨(dú)存儲(chǔ)數(shù)據(jù)。實(shí)際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表。
接下來(lái)我們就帶領(lǐng)大家實(shí)現(xiàn)這兩個(gè)最常用的鏈表結(jié)構(gòu)
ps:建議大家在完成鏈表時(shí),每完成一個(gè)功能都測(cè)試一下,以免最后調(diào)bug調(diào)崩潰
二、無(wú)頭單向非循環(huán)鏈表本次鏈表我們將其分成三個(gè)文件SList.c,SList.h,test.c,分別用來(lái)實(shí)現(xiàn),聲明,測(cè)試。
ps:鏈表的全部代碼以及效果展示會(huì)在文章末尾貼出
2.1 創(chuàng)建結(jié)構(gòu)體創(chuàng)建結(jié)構(gòu)體,其中有兩個(gè)成員,一個(gè)用來(lái)存儲(chǔ)數(shù)據(jù),一個(gè)用來(lái)指向下一個(gè)空間,并將其名字定義為SListNode方便后續(xù)使用
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
2.2 動(dòng)態(tài)申請(qǐng)一個(gè)節(jié)點(diǎn)申請(qǐng)節(jié)點(diǎn)我們用malloc函數(shù),申請(qǐng)成功后返回空間地址,需要注意此時(shí)未和其他節(jié)點(diǎn)鏈接
// 動(dòng)態(tài)申請(qǐng)一個(gè)節(jié)點(diǎn)
SListNode* BuySListNode(SLTDateType x)
{
SListNode* ptr = (SListNode*)malloc(sizeof(SListNode));
if (ptr == NULL)
{
perror("malloc");
exit(-1);
}
SListNode* Phead = ptr;
Phead->data = x;
Phead->next = NULL;
return Phead;
}
2.3 單鏈表打印先寫(xiě)打印的函數(shù),方便后續(xù)測(cè)試,將鏈表遍歷一遍即可
// 單鏈表打印
void SListPrint(SListNode* plist)
{
SListNode* tail = plist;
while (tail)
{
printf("%d->", tail->data);
tail = tail->next;
}
printf("NULL\n");
}
2.4 單鏈表尾插/尾刪
2.4.1 單鏈表尾插先判斷鏈表是否為空,為空則直接為其創(chuàng)建一個(gè)節(jié)點(diǎn)即可,不為空則需要遍歷到最后一個(gè)節(jié)點(diǎn)進(jìn)行插入。
// 單鏈表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
if (*pplist == NULL)
{
*pplist=BuySListNode(x);
}
else
{
SListNode* tail = *pplist;
while (tail->next)
{
tail = tail->next;
}
tail->next = BuySListNode(x);
}
}
2.4.2 單鏈表尾刪尾刪也就是尾插反著來(lái)即可,但是需要判斷是否為空,為空則無(wú)法刪除
// 單鏈表的尾刪
void SListPopBack(SListNode** pplist)
{
assert(*pplist);
SListNode* tail = *pplist;
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
2.5 單鏈表頭插/頭刪
2.5.1 頭插// 單鏈表的頭插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
if (*pplist == NULL)
{
*pplist = BuySListNode(x);
}
else
{
SListNode* cur = BuySListNode(x);
cur->next = *pplist;
*pplist = cur;
}
}
2.5.2 頭刪// 單鏈表頭刪
void SListPopFront(SListNode** pplist)
{
assert(*pplist);
SListNode* cur = *pplist;
*pplist = cur->next;
free(cur);
}
2.6 單鏈表查找單鏈表查找主要是為了后面的中間插入刪除,需要先找到要?jiǎng)h的位置,遍歷一遍鏈表就可以
// 單鏈表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
assert(plist);
SListNode* cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
2.7 單鏈表中間插入/中間刪除2.7.1 中間插入由于單鏈表只能從前往后走,而想要從中間位置插入或者刪除數(shù)據(jù),則需要改變前一個(gè)結(jié)構(gòu)體的指針,所以只能插入或者刪除指定位置后面的數(shù)據(jù)。
// 單鏈表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* a=BuySListNode(x);
SListNode* cur = pos->next;
pos->next = a;
a->next = cur;
}
2.7.2 中間刪除// 單鏈表刪除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
assert(pos);
if (pos->next == NULL)
{
return;
}
SListNode* cur = pos->next;
pos->next = cur->next;
free(cur);
}
2.8 單鏈表銷(xiāo)毀遍歷一遍,一個(gè)一個(gè)釋放即可
// 單鏈表的銷(xiāo)毀
void SListDestroy(SListNode** pplist)
{
assert(*pplist);
while (*pplist)
{
SListNode* cur = (*pplist)->next;
free(*pplist);
*pplist = cur;
}
*pplist = NULL;
}
三、雙向帶頭循環(huán)鏈表本次鏈表我們將其分成三個(gè)文件List.c,List.h,test.c,分別用來(lái)實(shí)現(xiàn),聲明,測(cè)試。
ps:鏈表的全部代碼以及效果展示會(huì)在文章末尾貼出
3.1 結(jié)構(gòu)體的創(chuàng)建創(chuàng)建結(jié)構(gòu)體,其中有三個(gè)成員,一個(gè)用來(lái)存放數(shù)據(jù),另外兩個(gè)指針,分別指向前一個(gè)空間和后一個(gè)空間
// 帶頭+雙向+循環(huán)鏈表增刪查改實(shí)現(xiàn)
typedef int LTDataType;
typedef struct ListNode
{
LTDataType _data;
struct ListNode* _next;
struct ListNode* _prev;
}ListNode;
3.2 創(chuàng)造節(jié)點(diǎn)創(chuàng)造節(jié)點(diǎn)我們?nèi)杂胢alloc函數(shù)
//創(chuàng)造節(jié)點(diǎn)
ListNode* BuyLTNode(LTDataType x)
{
ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
if (cur == NULL)
{
perror("malloc");
exit(-1);
}
cur->_data = x;
return cur;
}
3.3 創(chuàng)建返回鏈表的頭結(jié)點(diǎn)(哨兵位)當(dāng)創(chuàng)建哨兵位時(shí),我們一般將其中的數(shù)據(jù)賦為0,而且創(chuàng)建哨兵位的時(shí)候,鏈表只有哨兵位一個(gè)數(shù)據(jù),所以其前后指針都指向自己以達(dá)到循環(huán)的目的。
// 創(chuàng)建返回鏈表的頭結(jié)點(diǎn).
ListNode* ListCreate()
{
ListNode* head = BuyLTNode(0);
head->_next = head;//循環(huán)列表創(chuàng)建頭時(shí)頭的首尾都指向自己
head->_prev = head;
return head;
}
3.4 雙鏈表打印從頭的下一個(gè)節(jié)點(diǎn)開(kāi)始遍歷,當(dāng)重新遍歷到頭部時(shí),說(shuō)明遍歷完成。
// 雙向鏈表打印
void ListPrint(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->_next;
while (cur!=pHead)
{
printf("%d->", cur->_data);
cur = cur->_next;
}
printf("head\n");
}
3.5 雙鏈表的尾插/尾刪
3.5.1 尾插// 雙向鏈表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuyLTNode(x);
newnode->_prev = pHead->_prev;//要尾插的節(jié)點(diǎn)的prev指向原來(lái)的尾節(jié)點(diǎn)
newnode->_next = pHead;//要尾插的節(jié)點(diǎn)的next指向頭
pHead->_prev->_next = newnode;//原來(lái)的尾節(jié)點(diǎn)的next指向新尾
pHead->_prev = newnode;//頭的prev指向新尾
}
3.5.2 尾刪// 雙向鏈表尾刪
void ListPopBack(ListNode* pHead)
{
assert(pHead);
assert(pHead->_next!=pHead);
ListNode* tail = pHead->_prev;//用一個(gè)指針保存尾巴
tail->_prev->_next = pHead;//將倒數(shù)第二個(gè)節(jié)點(diǎn)的next指向頭
pHead->_prev = tail->_prev;//頭節(jié)點(diǎn)的prev指向倒數(shù)第二節(jié)點(diǎn)
free(tail);
}
3.6 雙鏈表的頭插/頭刪
3.6.1 頭插// 雙向鏈表頭插
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuyLTNode(x);
newnode->_next = pHead->_next;//新空間的next指向原來(lái)的第一個(gè)數(shù)據(jù)
newnode->_prev = pHead;//新空間的prev指向頭
pHead->_next->_prev = newnode;//原來(lái)的的一個(gè)數(shù)據(jù)的prev指向newnode
pHead->_next = newnode;//頭的next指向newnode
}
3.6.2 頭刪// 雙向鏈表頭刪
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(pHead->_next != pHead);//先判斷鏈表中除了頭有無(wú)其他數(shù)據(jù)
ListNode* oldnode = pHead->_next;//將要?jiǎng)h除的數(shù)據(jù)的位置保存起來(lái),以防后面丟失
pHead->_next = oldnode->_next;//頭的next指向第二個(gè)數(shù)據(jù)
oldnode->_next->_prev = pHead;//第二個(gè)數(shù)據(jù)的prev指向頭
free(oldnode);//釋放數(shù)據(jù)空間即可
}
3.7 雙鏈表的查找主要是為后面的中間插入刪除服務(wù)
// 雙向鏈表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* cur = pHead->_next;
while (cur != pHead)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
3.8 雙鏈表的中間插入/中間刪除
3.8.1 中間插入要插入指定位置,其實(shí)就是插入到指定位置的前面即可
// 雙向鏈表在pos的前面進(jìn)行插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
//調(diào)整pos newnode pos前面的數(shù)據(jù)這三個(gè)空間的prev和next即可
ListNode* newnode = BuyLTNode(x);
ListNode* prev = pos->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos;
pos->_prev = newnode;
}
3.8.2 中間刪除// 雙向鏈表刪除pos位置的節(jié)點(diǎn)
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* prev = pos->_prev;
ListNode* next = pos->_next;
free(pos);
prev->_next = next;
next->_prev = prev;
}
3.9 雙鏈表的銷(xiāo)毀// 雙向鏈表銷(xiāo)毀
void ListDestory(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->_next;
ListNode* next = cur->_next;
while (cur != pHead)//先釋放除頭以外的所有節(jié)點(diǎn),再釋放頭
{
free(cur);
cur = next;
next = next->_next;
}
free(cur);
}
四、鏈表和順序表的區(qū)別順序表:
優(yōu)點(diǎn):尾刪尾插效率高,訪(fǎng)問(wèn)隨機(jī)下標(biāo)快
缺點(diǎn):空間不夠需擴(kuò)容(擴(kuò)容代價(jià)大);頭插頭刪及中間插入刪除需要挪動(dòng)數(shù)據(jù),效率低
鏈表
五、代碼及代碼展示 5.1 單向鏈表 5.1.1 效果展示優(yōu)點(diǎn):需要擴(kuò)容時(shí),按需申請(qǐng)小塊空間;任意位置插入效率都高(O(1))
缺點(diǎn):不支持下標(biāo)隨機(jī)訪(fǎng)問(wèn)
SList.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
// 動(dòng)態(tài)申請(qǐng)一個(gè)節(jié)點(diǎn)
SListNode* BuySListNode(SLTDateType x)
{
SListNode* ptr = (SListNode*)malloc(sizeof(SListNode));
if (ptr == NULL)
{
perror("malloc");
exit(-1);
}
SListNode* Phead = ptr;
Phead->data = x;
Phead->next = NULL;
return Phead;
}
// 單鏈表打印
void SListPrint(SListNode* plist)
{
SListNode* tail = plist;
while (tail)
{
printf("%d->", tail->data);
tail = tail->next;
}
printf("NULL\n");
}
// 單鏈表尾插
void SListPushBack(SListNode** pplist, SLTDateType x)
{
if (*pplist == NULL)
{
*pplist=BuySListNode(x);
}
else
{
SListNode* tail = *pplist;
while (tail->next)
{
tail = tail->next;
}
tail->next = BuySListNode(x);
}
}
// 單鏈表的尾刪
void SListPopBack(SListNode** pplist)
{
assert(*pplist);
SListNode* tail = *pplist;
while (tail->next->next)
{
tail = tail->next;
}
free(tail->next);
tail->next = NULL;
}
// 單鏈表的頭插
void SListPushFront(SListNode** pplist, SLTDateType x)
{
if (*pplist == NULL)
{
*pplist = BuySListNode(x);
}
else
{
SListNode* cur = BuySListNode(x);
cur->next = *pplist;
*pplist = cur;
}
}
// 單鏈表頭刪
void SListPopFront(SListNode** pplist)
{
assert(*pplist);
SListNode* cur = *pplist;
*pplist = cur->next;
free(cur);
}
// 單鏈表查找
SListNode* SListFind(SListNode* plist, SLTDateType x)
{
assert(plist);
SListNode* cur = plist;
while (cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
// 單鏈表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x)
{
assert(pos);
SListNode* a=BuySListNode(x);
SListNode* cur = pos->next;
pos->next = a;
a->next = cur;
}
// 單鏈表刪除pos位置之后的值
void SListEraseAfter(SListNode* pos)
{
assert(pos);
if (pos->next == NULL)
{
return;
}
SListNode* cur = pos->next;
pos->next = cur->next;
free(cur);
}
// 單鏈表的銷(xiāo)毀
void SListDestroy(SListNode** pplist)
{
assert(*pplist);
while (*pplist)
{
SListNode* cur = (*pplist)->next;
free(*pplist);
*pplist = cur;
}
*pplist = NULL;
}
SList.h
#define _CRT_SECURE_NO_WARNINGS 1
#include#include#include
typedef int SLTDateType;
typedef struct SListNode
{
SLTDateType data;
struct SListNode* next;
}SListNode;
// 動(dòng)態(tài)申請(qǐng)一個(gè)節(jié)點(diǎn)
SListNode* BuySListNode(SLTDateType x);
// 單鏈表打印
void SListPrint(SListNode* plist);
// 單鏈表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 單鏈表的尾刪
void SListPopBack(SListNode** pplist);
// 單鏈表的頭插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 單鏈表頭刪
void SListPopFront(SListNode** pplist);
// 單鏈表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
// 單鏈表在pos位置之后插入x
void SListInsertAfter(SListNode* pos, SLTDateType x);
// 單鏈表刪除pos位置之后的值
void SListEraseAfter(SListNode* pos);
// 單鏈表的銷(xiāo)毀
void SListDestroy(SListNode** pplist);
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "SList.h"
void menu()
{
printf("*******************************\n");
printf("****1.尾部插入 2.尾部刪除 ****\n");
printf("****3.頭部插入 4.頭部刪除 ****\n");
printf("****5.中間插入 6.中間刪除 ****\n");
printf("****7.打印 0.退出 ****\n");
printf("*******************************\n");
}
int main()
{
menu();
SListNode* Phead = NULL;
int input;
do
{
printf("請(qǐng)選擇:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("請(qǐng)輸入要寫(xiě)入的數(shù)字:");
SLTDateType i;
scanf("%d", &i);
SListPushBack(&Phead,i);
break;
case 2:
SListPopBack(&Phead);
break;
case 3:
printf("請(qǐng)輸入要寫(xiě)入的數(shù)字:");
SLTDateType a;
scanf("%d", &a);
SListPushFront(&Phead, a);
break;
case 4:
SListPopFront(&Phead);
break;
case 5:
printf("會(huì)將數(shù)據(jù)插入進(jìn)輸入數(shù)字之后的位置\n");
printf("請(qǐng)輸入要插入位置的數(shù)字及要插入的數(shù)字:");
SLTDateType b, j;
scanf("%d %d", &b, &j);
SListNode* ret1 = SListFind(Phead, b);
if (ret1 != NULL)
{
SListInsertAfter(ret1, j);
}
else
{
printf("該數(shù)字不存在");
}
break;
case 6:
printf("請(qǐng)輸入要?jiǎng)h除的數(shù)字之前的數(shù)字:");
SLTDateType c;
scanf("%d", &c);
SListNode* ret2 = SListFind(Phead, c);
if (ret2 != NULL)
{
SListEraseAfter(ret2);
}
else
{
printf("未找到該數(shù)字");
}
break;
case 7:
SListPrint(Phead);
break;
case 0:
printf("退出");
SListDestroy(&Phead);
break;
default:
printf("輸入錯(cuò)誤,請(qǐng)重新輸入");
break;
}
} while (input);
return 0;
}
5.2 雙向帶頭循環(huán)鏈表
5.2.1 效果展示List.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"
// 創(chuàng)建返回鏈表的頭結(jié)點(diǎn).
ListNode* ListCreate()
{
ListNode* head = BuyLTNode(0);
head->_next = head;//循環(huán)列表創(chuàng)建頭時(shí)頭的首尾都指向自己
head->_prev = head;
return head;
}
//創(chuàng)造節(jié)點(diǎn)
ListNode* BuyLTNode(LTDataType x)
{
ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
if (cur == NULL)
{
perror("malloc");
exit(-1);
}
cur->_data = x;
return cur;
}
// 雙向鏈表打印
void ListPrint(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->_next;
while (cur!=pHead)
{
printf("%d->", cur->_data);
cur = cur->_next;
}
printf("head\n");
}
// 雙向鏈表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuyLTNode(x);
newnode->_prev = pHead->_prev;//要尾插的節(jié)點(diǎn)的prev指向原來(lái)的尾節(jié)點(diǎn)
newnode->_next = pHead;//要尾插的節(jié)點(diǎn)的next指向頭
pHead->_prev->_next = newnode;//原來(lái)的尾節(jié)點(diǎn)的next指向新尾
pHead->_prev = newnode;//頭的prev指向新尾
}
// 雙向鏈表尾刪
void ListPopBack(ListNode* pHead)
{
assert(pHead);
assert(pHead->_next!=pHead);
ListNode* tail = pHead->_prev;//用一個(gè)指針保存尾巴
tail->_prev->_next = pHead;//將倒數(shù)第二個(gè)節(jié)點(diǎn)的next指向頭
pHead->_prev = tail->_prev;//頭節(jié)點(diǎn)的prev指向倒數(shù)第二節(jié)點(diǎn)
free(tail);
}
// 雙向鏈表頭插
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuyLTNode(x);
newnode->_next = pHead->_next;//新空間的next指向原來(lái)的第一個(gè)數(shù)據(jù)
newnode->_prev = pHead;//新空間的prev指向頭
pHead->_next->_prev = newnode;//原來(lái)的的一個(gè)數(shù)據(jù)的prev指向newnode
pHead->_next = newnode;//頭的next指向newnode
}
// 雙向鏈表頭刪
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(pHead->_next != pHead);//先判斷鏈表中除了頭有無(wú)其他數(shù)據(jù)
ListNode* oldnode = pHead->_next;//將要?jiǎng)h除的數(shù)據(jù)的位置保存起來(lái),以防后面丟失
pHead->_next = oldnode->_next;//頭的next指向第二個(gè)數(shù)據(jù)
oldnode->_next->_prev = pHead;//第二個(gè)數(shù)據(jù)的prev指向頭
free(oldnode);//釋放數(shù)據(jù)空間即可
}
// 雙向鏈表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* cur = pHead->_next;
while (cur != pHead)
{
if (cur->_data == x)
{
return cur;
}
cur = cur->_next;
}
return NULL;
}
// 雙向鏈表在pos的前面進(jìn)行插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos);
//調(diào)整pos newnode pos前面的數(shù)據(jù)這三個(gè)空間的prev和next即可
ListNode* newnode = BuyLTNode(x);
ListNode* prev = pos->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos;
pos->_prev = newnode;
}
// 雙向鏈表刪除pos位置的節(jié)點(diǎn)
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* prev = pos->_prev;
ListNode* next = pos->_next;
free(pos);
prev->_next = next;
next->_prev = prev;
}
// 雙向鏈表銷(xiāo)毀
void ListDestory(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->_next;
ListNode* next = cur->_next;
while (cur != pHead)//先釋放除頭以外的所有節(jié)點(diǎn),再釋放頭
{
free(cur);
cur = next;
next = next->_next;
}
free(cur);
}
List.h
#define _CRT_SECURE_NO_WARNINGS 1
#include#include
#include// 帶頭+雙向+循環(huán)鏈表增刪查改實(shí)現(xiàn)
typedef int LTDataType;
typedef struct ListNode
{
LTDataType _data;
struct ListNode* _next;
struct ListNode* _prev;
}ListNode;
//創(chuàng)造節(jié)點(diǎn)
ListNode* BuyLTNode(LTDataType x);
// 創(chuàng)建返回鏈表的頭結(jié)點(diǎn).
ListNode* ListCreate();
// 雙向鏈表銷(xiāo)毀
void ListDestory(ListNode* pHead);
// 雙向鏈表打印
void ListPrint(ListNode* pHead);
// 雙向鏈表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 雙向鏈表尾刪
void ListPopBack(ListNode* pHead);
// 雙向鏈表頭插
void ListPushFront(ListNode* pHead, LTDataType x);
// 雙向鏈表頭刪
void ListPopFront(ListNode* pHead);
// 雙向鏈表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 雙向鏈表在pos的前面進(jìn)行插入
void ListInsert(ListNode* pos, LTDataType x);
// 雙向鏈表刪除pos位置的節(jié)點(diǎn)
void ListErase(ListNode* pos);
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"
void menu()
{
printf("*******************************\n");
printf("****1.尾部插入 2.尾部刪除 ****\n");
printf("****3.頭部插入 4.頭部刪除 ****\n");
printf("****5.中間插入 6.中間刪除 ****\n");
printf("****7.打印 0.退出 ****\n");
printf("*******************************\n");
}
int main()
{
menu();
ListNode* head = ListCreate();
int input;
do
{
printf("請(qǐng)選擇:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("請(qǐng)輸入要寫(xiě)入的數(shù)字:");
LTDataType i;
scanf("%d", &i);
ListPushBack(head, i);
break;
case 2:
ListPopBack(head);
break;
case 3:
printf("請(qǐng)輸入要寫(xiě)入的數(shù)字:");
LTDataType a;
scanf("%d", &a);
ListPushFront(head, a);
break;
case 4:
ListPopFront(head);
break;
case 5:
printf("會(huì)將數(shù)據(jù)插入進(jìn)輸入數(shù)字之前的位置\n");
printf("請(qǐng)輸入要插入位置的數(shù)字及要插入的數(shù)字:");
LTDataType b,j;
scanf("%d %d", &b,&j);
ListNode* ret1 = ListFind(head, b);
if (ret1 != NULL)
{
ListInsert(ret1, j);
}
else
{
printf("該數(shù)字不存在");
}
break;
case 6:
printf("請(qǐng)輸入要?jiǎng)h除的數(shù)字:");
LTDataType c;
scanf("%d", &c);
ListNode* ret2 = ListFind(head, c);
if (ret2 != NULL)
{
ListErase(ret2);
}
else
{
printf("未找到該數(shù)字");
}
break;
case 7:
ListPrint(head);
break;
case 0:
printf("退出");
ListDestory(head);
break;
default:
printf("輸入錯(cuò)誤,請(qǐng)重新輸入");
break;
}
} while (input);
return 0;
}
以上就是今天文章的內(nèi)容,希望鐵子們可以有所收貨。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)頁(yè)名稱(chēng):C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)——鏈表-創(chuàng)新互聯(lián)
鏈接地址:http://chinadenli.net/article26/dhpgcg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、網(wǎng)站制作、網(wǎng)站建設(shè)、品牌網(wǎng)站設(shè)計(jì)、電子商務(wù)、靜態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容