国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【數據結構】—C語言實現雙向鏈表(超詳細!)

這篇具有很好參考價值的文章主要介紹了【數據結構】—C語言實現雙向鏈表(超詳細!)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【數據結構】—C語言實現雙向鏈表(超詳細!),數據結構與算法煉體 淬體中,數據結構,c++,c語言,鏈表,學習,經驗分享,開發(fā)語言

??????????????????????????????? ??? ?食用指南:本文在有C基礎的情況下食用更佳?

????????????????????????????? ??? ? ??這就不得不推薦此專欄了:C語言

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??雙向鏈表置知識:單鏈表?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? ??????今日夜電波:Departures ~あなたにおくるアイの歌~ —EGOIST?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3:12?━━━━━━???──────── 4:13? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????? ? ? ?? ? ?? ? ? ? ?? ? ??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???關注??點贊??收藏您的每一次鼓勵都是對我莫大的支持???


一、雙向鏈表介紹

什么是雙向鏈表?

? ? ? ? 它是是一種常見的線性數據結構,它由一系列節(jié)點組成,每個節(jié)點包含兩個指針,一個指向前一個節(jié)點(pre指針),一個指向后一個節(jié)點(next指針)。

雙向鏈表的基本結構?

????????一張圖讓你明白:

? ? ? ? 注:此為帶哨兵的雙向鏈表

【數據結構】—C語言實現雙向鏈表(超詳細!),數據結構與算法煉體 淬體中,數據結構,c++,c語言,鏈表,學習,經驗分享,開發(fā)語言

? ? ? ? ?注:next表示為指向下一個節(jié)點的指針,prev表示為指向上一個節(jié)點的指針,而head則是作為標兵的存在,里面不存數據,其他data存數據,此雙向鏈表無指向NULL的指針,讀者可在下文初始化雙向鏈表得到疑惑的答案。

與單鏈表相比的優(yōu)勢?

  1. 雙向遍歷:由于每個節(jié)點都存儲了前向和后向指針,可以從頭到尾或者從尾到頭方便地遍歷鏈表。這樣的遍歷方式在某些場景下非常有用,特別是需要反向操作或者雙向查找的情況。

  2. 方便插入和刪除:在雙向鏈表中,插入和刪除操作相對容易。通過修改前后指針,可以方便地調整節(jié)點的連接關系,無需像單鏈表那樣需要在刪除節(jié)點時找到其前驅節(jié)點。

  3. 更靈活的操作:雙向鏈表相比單鏈表,對于節(jié)點的操作更加靈活。例如,在單鏈表中,如果要刪除某個節(jié)點,需要先找到它的前驅節(jié)點,而在雙向鏈表中,可以直接通過節(jié)點本身進行刪除操作。

  4. 提高性能:在某些情況下,雙向鏈表可以提高性能。例如,在需要頻繁從鏈表中刪除節(jié)點或者在給定節(jié)點后插入新節(jié)點的情況下,雙向鏈表可以更高效地完成這些操作。

????????總的來說,雙向鏈表在一些特定場景下相比單鏈表具有更多的優(yōu)勢和靈活性,雙向鏈表是單鏈表的優(yōu)化!


二、總體思路

如何實現?

????????參照??雙向鏈表置知識單鏈表?(這是個鏈接,快點!),我們同樣需要實現增、刪、查、改。同樣的我們需要先定義好節(jié)點,以此得到基本的結構->接著定義好接口(定義完后發(fā)現比單鏈表簡單多了)->最后按照接口實現每一個功能

? ? ? ? 節(jié)點的定義(結構體)

typedef int LTDataType;
typedef struct ListNode
{
	LTDataType _data;
	struct ListNode* _next;
	struct ListNode* _prev;
}ListNode;

? ? ? ? 接口的定義?

// 創(chuàng)建返回鏈表的頭結點.
ListNode* ListCreate();
// 雙向鏈表銷毀
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位置的節(jié)點
void ListErase(ListNode* pos);

三、具體每個接口函數的實現

? ? ? ? 1、初始化(重點)

ListNode* ListCreate()
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	if (!node)
	{
		perror("malloc fail:");
		exit(-1);
	}

	node->_next = node;
	node->_prev = node;

	return node;
}

? ? ? ? 可以看到初始化的作用是建立了一個標兵,這個標兵沒有被賦值,因為他的值是多少無關緊要,重點在于:他的next指針指向的是他自己,而prev指針指向的也是他自己。這說明了什么?這說明了雙向鏈表的最開始就是在沒有任何值的時候就只有一個標兵,也就是說雙向鏈表的每一個指針都不是空的,都是有指向的,他們指向的地址不可能為NULL。


? ? ? ? 2、銷毀鏈表

void ListDestory(ListNode* pHead)
{
	assert(pHead);
	ListNode* cur = pHead->_next;
	while (cur != pHead)
	{
		ListNode* tmp = cur->_next;
		free(cur);
		cur = tmp;
	}

	free(pHead);
}

? ? ? ? 3、查找功能(返回pos的地址)

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;

}

? ? ? ? 4、插入節(jié)點的實現(基于查找功能

ListNode* BuyNode(LTDataType x)//實現節(jié)點的獲取
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	node->_data = x;
	node->_next = NULL;
	node->_prev = NULL;

	return node;
}

void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);

	ListNode* newnode = BuyNode(x);
	ListNode* dist = pos->_prev;

	dist->_next = newnode;
	newnode->_prev = dist;
	newnode->_next = pos;
	pos->_prev = newnode;
	
}

? ? ?特別注意

????????? 注意:在實現了 插入的功能后,其實一切都簡單了起來,比如頭插等等,只需要幾行代碼就能完成操作,而下面的刪除操作的實現對于頭刪等等都是僅需要幾行代碼就能實現,因此,我們如果要快速的寫完一個單鏈表或者其他鏈表,最好是從插入和刪除開始寫!o.o


? ? ? ? 5、刪除節(jié)點(基于查找功能)

void ListErase(ListNode* pos)
{
	assert(pos);

	ListNode* posPrev = pos->_prev;
	ListNode* posNext = pos->_next;

	posPrev->_next = posNext;
	posNext->_prev = posPrev;
	free(pos);
}

? ? ? ? 6、尾插

void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	//ListInsert(pHead, x);//此為簡化,如要簡化代碼,此段帶碼后的代碼可都不要

	ListNode* newnode = BuyNode(x);

	pHead->_prev->_next = newnode;
	newnode->_prev=pHead->_prev;
	newnode->_next = pHead;
	pHead->_prev = newnode;
}

? ? ? ? 7、尾刪

void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	//ListErase(pHead->_prev);//此為簡化,如要簡化代碼,此段帶碼后的代碼可都不要

	if (pHead->_prev != pHead)
	{
		ListNode* tmp = pHead->_prev;
		pHead->_prev = tmp->_prev;
		tmp->_prev->_next = pHead;
		free(tmp);
		tmp = NULL;
	}
}

? ? ? ? 8、頭插

void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	//ListInsert(pHead->_next, x);//此為簡化,如要簡化代碼,此段帶碼后的代碼可都不要

	ListNode* newnode = BuyNode(x);
	newnode->_next=pHead->_next;
	newnode->_prev = pHead;
	pHead->_next->_prev = newnode;
	pHead->_next = newnode;
}

? ? ? ? 9、頭刪

void ListPopFront(ListNode* pHead)
{
	assert(pHead);
	//ListErase(pHead->_next);//此為簡化,如要簡化代碼,此段帶碼后的代碼可都不要

	if (pHead->_next != pHead)
	{
		ListNode* node = pHead->_next;
		node->_next->_prev = pHead;
		pHead->_next = node->_next;
		free(node);
		node = NULL;
	}
}

????????10、打印

void ListPrint(ListNode* pHead)
{
	ListNode* cur = pHead->_next;
	printf("pHead<=>");
	while (cur != pHead)
	{
		printf("%d<=>", cur->_data);
		cur = cur->_next;
	}
	printf("\n");
}

四、總體代碼

1、頭文件

#pragma once
#define _CRT_SECURE_NO_WARNINGS 01
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

// 帶頭+雙向+循環(huán)鏈表增刪查改實現
typedef int LTDataType;
typedef struct ListNode
{
	LTDataType _data;
	struct ListNode* _next;
	struct ListNode* _prev;
}ListNode;

// 創(chuàng)建返回鏈表的頭結點.
ListNode* ListCreate();
// 雙向鏈表銷毀
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位置的節(jié)點
void ListErase(ListNode* pos);

2、主體函數文件

#include"list.h"

ListNode* BuyNode(LTDataType x)
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	if (node == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}

	node->_data = x;
	node->_next = NULL;
	node->_prev = NULL;

	return node;
}

ListNode* ListCreate()
{
	ListNode* node = (ListNode*)malloc(sizeof(ListNode));
	if (!node)
	{
		perror("malloc fail:");
		exit(-1);
	}

	node->_next = node;
	node->_prev = node;

	return node;
}

void ListDestory(ListNode* pHead)
{
	assert(pHead);
	ListNode* cur = pHead->_next;
	while (cur != pHead)
	{
		ListNode* tmp = cur->_next;
		free(cur);
		cur = tmp;
	}

	free(pHead);
}

void ListPrint(ListNode* pHead)
{
	ListNode* cur = pHead->_next;
	printf("pHead<=>");
	while (cur != pHead)
	{
		printf("%d<=>", cur->_data);
		cur = cur->_next;
	}
	printf("\n");
}

void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	//ListInsert(pHead, x);
	ListNode* newnode = BuyNode(x);

	pHead->_prev->_next = newnode;
	newnode->_prev=pHead->_prev;
	newnode->_next = pHead;
	pHead->_prev = newnode;
}

void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	//ListErase(pHead->_prev);
	if (pHead->_prev != pHead)
	{
		ListNode* tmp = pHead->_prev;
		pHead->_prev = tmp->_prev;
		tmp->_prev->_next = pHead;
		free(tmp);
		tmp = NULL;
	}
}

void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	//ListInsert(pHead->_next, x);
	ListNode* newnode = BuyNode(x);
	newnode->_next=pHead->_next;
	newnode->_prev = pHead;
	pHead->_next->_prev = newnode;
	pHead->_next = newnode;
}

void ListPopFront(ListNode* pHead)
{
	assert(pHead);
	//ListErase(pHead->_next);
	if (pHead->_next != pHead)
	{
		ListNode* node = pHead->_next;
		node->_next->_prev = pHead;
		pHead->_next = node->_next;
		free(node);
		node = NULL;
	}
}

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;

}

void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);

	ListNode* newnode = BuyNode(x);
	ListNode* dist = pos->_prev;

	dist->_next = newnode;
	newnode->_prev = dist;
	newnode->_next = pos;
	pos->_prev = newnode;
	
}

void ListErase(ListNode* pos)
{
	assert(pos);

	ListNode* posPrev = pos->_prev;
	ListNode* posNext = pos->_next;

	posPrev->_next = posNext;
	posNext->_prev = posPrev;
	free(pos);
}

3、測試用例

#include"list.h"


void text()
{
	ListNode* phead = ListCreate();
	ListPushBack(phead, 1);
	ListPushBack(phead, 2);
	ListPushBack(phead, 3);
	ListPrint(phead);

	ListPopBack(phead);
	ListPrint(phead);
	
	ListPushFront(phead, 10);
	ListPushFront(phead, 20);
	ListPushFront(phead, 30);
	ListPrint(phead);

	ListPopFront(phead);
	ListPrint(phead);

	ListNode* pos = ListFind(phead, 20);
	if (pos)
	{
		ListInsert(pos, 300);
	}
	ListPrint(phead);

	ListErase(pos);
	ListPrint(phead);

	ListDestory(phead);
}

int main()
{
	text();
	return 0;
}

? ? ? ? 測試結果:

【數據結構】—C語言實現雙向鏈表(超詳細!),數據結構與算法煉體 淬體中,數據結構,c++,c語言,鏈表,學習,經驗分享,開發(fā)語言


????????????????????感謝你耐心的看到這里?( ′???` )比心,如有哪里有錯誤請?zhí)咭荒_作者o(╥﹏╥)o!?

???????????????????????????????????????? ? ? ?【數據結構】—C語言實現雙向鏈表(超詳細!),數據結構與算法煉體 淬體中,數據結構,c++,c語言,鏈表,學習,經驗分享,開發(fā)語言

?????????????????????????????????????????????????????????????????????????給個三連再走嘛~??文章來源地址http://www.zghlxwxcb.cn/news/detail-641178.html

到了這里,關于【數據結構】—C語言實現雙向鏈表(超詳細!)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【數據結構初階】四、線性表里的鏈表(帶頭+雙向+循環(huán) 鏈表 -- C語言實現)

    【數據結構初階】四、線性表里的鏈表(帶頭+雙向+循環(huán) 鏈表 -- C語言實現)

    ========================================================================= 相關代碼gitee自取 : C語言學習日記: 加油努力 (gitee.com) ?========================================================================= 接上期 : 【數據結構初階】三、 線性表里的鏈表(無頭+單向+非循環(huán)鏈表 -- C語言實現)-CSDN博客 ?====

    2024年02月08日
    瀏覽(30)
  • 鏈接未來:深入理解鏈表數據結構(二.c語言實現帶頭雙向循環(huán)鏈表)

    鏈接未來:深入理解鏈表數據結構(二.c語言實現帶頭雙向循環(huán)鏈表)

    上篇文章簡述講解了鏈表的基本概念并且實現了無頭單向不循環(huán)鏈表:鏈接未來:深入理解鏈表數據結構(一.c語言實現無頭單向非循環(huán)鏈表)-CSDN博客 那今天接著給大家?guī)韼ь^雙向循環(huán)鏈表的實現 : 頭文件DoubleList.h:用來基礎準備(常量定義,typedef),鏈表表的基本框架

    2024年01月16日
    瀏覽(58)
  • C語言數據結構-雙向鏈表

    C語言數據結構-雙向鏈表

    帶頭鏈表的頭結點,實際是\\\"哨兵位\\\",哨兵位節(jié)點不存儲任何有效元素,只是站在這里\\\"放哨的\\\". 哨兵位的意義:遍歷循環(huán)鏈表避免死循環(huán). 筆者在刪除,插入數據時,畫好圖后,也好了代碼,但是在調試中多次出現 代碼位置出錯 ,導致寫的代碼的含義不符合預期. 所以說思路一定要清晰

    2024年02月04日
    瀏覽(23)
  • 雙向鏈表(數據結構)(C語言)

    雙向鏈表(數據結構)(C語言)

    目錄 概念 帶頭雙向循環(huán)鏈表的實現 前情提示 雙向鏈表的結構體定義 雙向鏈表的初始化 關于無頭單向非循環(huán)鏈表無需初始化函數,順序表、帶頭雙向循環(huán)鏈表需要的思考 雙向鏈表在pos位置之前插入x 雙向鏈表的打印 雙鏈表刪除pos位置的結點 雙向鏈表的尾插 關于單鏈表的尾

    2024年02月04日
    瀏覽(26)
  • 【數據結構篇】手寫雙向鏈表、單向鏈表(超詳細)

    【數據結構篇】手寫雙向鏈表、單向鏈表(超詳細)

    什么是鏈表 ? 鏈表(Linked List)是用鏈式存儲結構實現的線性表。鏈表示意圖: 鏈表的組成 : 數據域 + 引用域 (數據域和引用域合稱結點或元素) 數據域存放數據元素自身的數據 引用域存放相鄰結點的地址 鏈表的特點 : 鏈表中元素的聯系依靠引用域 具有線性結構的特

    2024年02月11日
    瀏覽(30)
  • 數據結構_鏈表_雙向循環(huán)鏈表的初始化、插入、刪除、修改、查詢打?。ɑ贑語言實現)

    數據結構_鏈表_雙向循環(huán)鏈表的初始化、插入、刪除、修改、查詢打?。ɑ贑語言實現)

    版本: 2024年4月26日 V1.0 發(fā)布于博客園 目錄 目錄 雙向循環(huán)鏈表公式 初始化雙向循環(huán)鏈表 構建雙向循環(huán)鏈表結點 創(chuàng)建一個空鏈表(僅頭結點) 創(chuàng)建一個新結點 插入數據 頭插 中插 尾插 刪除數據 頭刪 中刪 尾刪 查詢打印數據 遍歷打印 測試 測試結果: 完整代碼 DoubleCirLList.h

    2024年04月27日
    瀏覽(35)
  • Go語言數據結構(一)雙向鏈表

    Go語言中l(wèi)ist容器定義在\\\"container/list\\\"包中,實現了一個雙向鏈表。本文第一部分總結源碼包中的方法,第二部分展示使用list包的常見示例用法以及刷題時的用法。 食用指南:先看第二部分的常用示例用法然后再用到時在第一部分找對應的方法。 更多內容以及其他Go常用數據結

    2024年01月19日
    瀏覽(25)
  • 數據結構——雙向鏈表(C語言版)

    上一章: 數據結構——單向鏈表(C語言版)-CSDN博客 目錄 什么是雙向鏈表? 雙向鏈表的節(jié)點結構 雙向鏈表的基本操作 完整的雙向鏈表示例 總結 什么是雙向鏈表? 雙向鏈表是一種常見的數據結構,它由一系列節(jié)點組成,每個節(jié)點包含兩個指針:一個指向前一個節(jié)點,一個

    2024年03月26日
    瀏覽(14)
  • 數據結構-雙向鏈表(c++)超全超詳細

    數據結構-雙向鏈表(c++)超全超詳細

    單鏈表結點中只有一個指向其后繼的指針,使得單鏈表只能從頭結點依次順序地向后遍歷。要訪問某個結點的前驅結點(插入,刪除操作時),只能從頭開始遍歷,訪問后繼結點的時間復雜度為O(1),訪問前驅結點的時間復雜度為O(n)。 提示:以下是本篇文章正文內容,下面案

    2023年04月08日
    瀏覽(20)
  • 數據結構——實現雙向鏈表

    數據結構——實現雙向鏈表

    怎么說呢?光乍一聽名字好像很難的樣子是吧,那如果你這樣認為的話,可就要讓你大跌眼鏡了哦,其實雙向帶頭循環(huán)鏈表從操作和理解上來說都是要易于單項不帶頭不循環(huán)鏈表(俗稱單鏈表)的。 咱們就來見識見識吧!希望真的能讓你們“大跌眼鏡”哈! 雙向帶頭循環(huán)鏈

    2024年02月07日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包