欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)——鏈表-創(chuàng)新互聯(lián)

目錄

創(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),以及鏈表和順序表的差別。


一、什么是鏈表 1.1鏈表的結(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.從上圖看出,鏈?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ù)。

1.2 鏈表的分類(lèi)

實(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 單鏈表中間插入/中間刪除

由于單鏈表只能從前往后走,而想要從中間位置插入或者刪除數(shù)據(jù),則需要改變前一個(gè)結(jié)構(gòu)體的指針,所以只能插入或者刪除指定位置后面的數(shù)據(jù)。

2.7.1 中間插入

// 單鏈表在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ù),效率低

鏈表

優(yōu)點(diǎn):需要擴(kuò)容時(shí),按需申請(qǐng)小塊空間;任意位置插入效率都高(O(1))

缺點(diǎn):不支持下標(biāo)隨機(jī)訪(fǎng)問(wèn)

五、代碼及代碼展示 5.1 單向鏈表 5.1.1 效果展示

5.1.2 代碼

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 效果展示

5.2.2 代碼

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;
}


總結(jié)

以上就是今天文章的內(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)

成都網(wǎng)站建設(shè)