首頁 > 軟體

C++零基礎精通資料結構之帶頭雙向迴圈連結串列

2022-03-30 19:03:05

與單連結串列的區別

單向/雙向

單向:只有一個next指標,只指向下一位元素

雙向:有兩個指標,指向上一位和下一位元素,尋找前一節點和後一節點很便利

帶頭/不帶頭

帶頭:在本來的頭結點之前還有一個哨兵衛節點作為頭節點,它的址域指標指向頭節點,值域不做使用
不帶頭:沒有哨兵衛頭節點,在尾刪尾插等問題中要考慮頭結點的情況(侷限)

迴圈/非迴圈

迴圈:頭結點會與尾節點相連

非迴圈:頭結點不與尾節點相連

程式碼的實現

介面

// 建立連結串列(連結串列初始化)
ListNode* ListCreate();
//建立節點
ListNode* BuyListNode(ListNode* pHead);
// 雙向連結串列銷燬
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的前面進行插入
void ListInsert(ListNode* pos, LTDataType x);
// 雙向連結串列刪除pos位置的節點
void ListErase(ListNode* pos);

節點的構造

typedef int LTDataType;
typedef struct ListNode
{
	LTDataType data;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;

初始化連結串列

// 建立連結串列(初始化)
ListNode* ListCreate()
{
	//開闢哨兵衛頭結點
	ListNode* plist = (ListNode*)malloc(sizeof(ListNode));
	if (plist == NULL)//失敗列印錯誤資訊並結束程序
	{
		perror("ListCreat fail:");
		exit(-1);
	}
	plist->next = plist;
	plist->prev = plist;
	return plist;
}

開闢節點

//建立節點
ListNode* BuyListNode(LTDataType x)
{
	//建立節點
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)//失敗列印錯誤資訊並結束程序
	{
		perror("creatnode fail:");
		exit(-1);
	}
	newnode->data = x;
	//初始化結點
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

銷燬連結串列

注:動態開闢的連結串列空間,在不使用後需要將之釋放,避免造成記憶體漏失

// 雙向連結串列銷燬
void ListDestory(ListNode* pHead)
{
	//斷言傳入指標不為NULL
	assert(pHead);
	ListNode* cur = pHead;
	pHead->prev->next = NULL;
	while (cur!=NULL)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	return;
}

列印連結串列

// 雙向連結串列列印
void ListPrint(ListNode* pHead)
{
	//斷言傳入指標不為NULL
	assert(pHead);
	//建立定址指標
	ListNode* cur = pHead->next;
	//迴圈遍歷連結串列
	while (cur != pHead)
	{
		//列印資料
		printf("%d->", cur->data);
		//找到下一個節點
		cur = cur->next;
	}printf("NULLn");
	return;
}

尾插連結串列

// 雙向連結串列尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
	//斷言傳入指標不為NULL
	assert(pHead);
	//建立節點
	ListNode* newnode = BuyListNode(x);
	//找到尾節點
	ListNode* tail=pHead->prev;
	tail->next = newnode;
	newnode->prev = tail;
 
	pHead->prev = newnode;
	newnode->next = pHead;
}

尾刪連結串列

尾刪前記錄前一節點的地址

// 雙向連結串列尾刪
void ListPopBack(ListNode* pHead)
{
	//斷言傳入指標不為NULL
	assert(pHead);
	//只剩哨兵衛頭結點的情況
	if (pHead->prev == pHead)
		return;
	//記錄尾節點及其前一節點
	ListNode* tail = pHead->prev;
	ListNode* tailprev = tail->prev;
	//釋放尾節點
	free(tail);
	//構建尾節點前一節點與哨兵衛頭結點的關係
	tailprev->next = pHead;
	pHead->prev = tailprev;
	return;
}

頭插連結串列

頭插前記錄哨兵衛頭節點的下一節點

// 雙向連結串列頭插
void ListPushFront(ListNode* pHead, LTDataType x)
{
	//斷言傳入指標不為NULL
	assert(pHead);
	//建立節點
	ListNode* newnode = BuyListNode(x);
	//記錄哨兵衛頭結點的下一節點
	ListNode* next = pHead->next;
	//構建各節點之間的關係
	pHead->next = newnode;
	newnode->prev = pHead;
 
	newnode->next = next;
	next->prev = newnode;
	return;
}

頭刪連結串列

// 雙向連結串列頭刪
void ListPopFront(ListNode* pHead)
{
	//斷言傳入指標不為NULL
	assert(pHead);
	//只剩哨兵衛頭結點的情況
	if (pHead->next == pHead)
		return;
	//記錄哨兵衛頭結點下一節點及其的下一節點
	ListNode* next = pHead->next;
	ListNode* nextNext = next->next;
	//釋放節點
	free(next);
	pHead->next = nextNext;
	nextNext->prev = pHead;
	return;
}

查詢連結串列

// 雙向連結串列查詢
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
	//斷言傳入指標不為NULL
	assert(pHead);
	//建立定址指標
	ListNode* cur = pHead->next;
	while (cur != pHead)
	{
		//比較資料
		if (cur->data == x)
			return cur;
		//找到下一個節點
		cur = cur->next;
	}
	//沒找到則返回NULL
	return NULL;
}

連結串列pos位置的刪除

void ListErase(ListNode* pos)
{
	assert(pos);
	ListNode* prev = pos->prev;
	ListNode* next = pos->next;
	free(pos);
	prev->next = next;
	next->prev = prev;
	return;
}

總結

我們在實帶頭雙向迴圈連結串列:結構最複雜,一般用在單獨儲存資料。實際中使用的連結串列資料結構,都是帶頭雙向迴圈連結串列。另外這個結構雖然結構複雜,但是使用程式碼實現以後會發現結構會帶來很多優勢,實現反而簡單現的時候可以看出其實帶頭雙向迴圈連結串列實現起來並不難,而且在雙向迴圈特點的加持下,在一些方面顯得格外方便。

但是因為帶頭雙向迴圈連結串列結構的複雜性,我們通常還是會使用邏輯結構相對簡單的單連結串列,並且在oj題上考的最多的也是單連結串列。

但我們仍要熟練掌握帶頭雙向迴圈連結串列的結構和實現方式,因為這是一種特別且方便的結構,且用處十分強大。

到此這篇關於C++零基礎精通資料結構之帶頭雙向迴圈連結串列的文章就介紹到這了,更多相關C++ 帶頭雙向迴圈連結串列內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com