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

數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

這篇具有很好參考價值的文章主要介紹了數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

前面學習了順序表發(fā)現(xiàn),順序表雖然好,但也有很多不足的地方,比方說,順序表是一塊連續(xù)的物理空間,如果頭插或者頭刪,那么整個數(shù)組的數(shù)據(jù)都要移動。但是鏈表不一樣,鏈表是通過指針訪問或者調(diào)整,鏈表是物理空間是不連續(xù)的,通過當前的next指針找到下一個。
插入和刪除時,數(shù)組平均需要移動n/2個元素,而鏈表只需修改指針即可
鏈表的優(yōu)點:
插入刪除速度快
內(nèi)存利用率高,不會浪費內(nèi)存
大小沒有固定,拓展很靈活
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

鏈表的概念及結構

概念:
鏈表是一種物理存儲結構上非連續(xù)、非順序的存儲結構,數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的
結構:
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

注意:
1.從圖上看,鏈式結構在邏輯上是連續(xù)的,但在物理上不一定連續(xù)
2.現(xiàn)實中節(jié)點一般都是從堆上申請出來的
3.從堆上malloc的空間是按照一定策略來分配的,第二次申請空間可能是連續(xù)的,也可能不是

鏈表的分類

實際中鏈表的結構非常多樣,以下情況組合起來就有8種鏈表結構:
單向或雙向鏈表:
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

帶頭節(jié)點或者不帶頭節(jié)點:
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

循環(huán)或者非循環(huán):

數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

最常用的兩種鏈表

無頭單向非循環(huán)鏈表:
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解
帶頭雙向循環(huán)鏈表:
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

————————————————

鏈表的創(chuàng)建

鏈表是由數(shù)據(jù)和指針組成
那么我們在創(chuàng)建鏈表的時候,需要一個指針指向下一個節(jié)點
如下:

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;

}SListNode;

創(chuàng)建新的節(jié)點

創(chuàng)建新的節(jié)點,把要插入的值放進新的節(jié)點的data,然后再把next指針賦成空,最后返回這個節(jié)點的指針

//創(chuàng)建新的節(jié)點
SListNode* BuySLTNode(SLTDataType x)
{
	SListNode* ret = (SListNode*)malloc(sizeof(SListNode));
	if (ret == NULL)
	{
		perror("BuySLTNode");
		return NULL;
	}
	ret->data = x;
	ret->next = NULL;

	return ret;
}

尾插

既然是尾插,那就是在尾部插入元素

我們可以看到下面是用二級指針接收的,因為傳過來的是一級指針的地址,所以我們要用二級指針接收,并且我們使用的時候要解引用,因為我們要改變的是一級指針本身

如果傳過來的指針本身就是NULL,那就直接把新的節(jié)點賦給傳過來的指針
如果不是空,那我們就找尾,找到尾之后,再把新的節(jié)點插入到尾部的next指針
注:
tail指針是指向元素當前位置,我們一般不直接使用原有的指針,因為我們要保留第一個元素指針的位置,以便后續(xù)使用。

//尾插
void SLTPushBack(SListNode** pphead, SLTDataType x)
{
	assert(pphead);

	SListNode* newnode = BuySLTNode(x);

	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SListNode* tail = *pphead;
		//找尾
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

頭插

我們把新節(jié)點的next指向第一個元素的指針,然后再把第一個節(jié)點的指針更新為newnode

//頭插
void SLTPushFront(SListNode** pphead, SLTDataType x)
{
	assert(pphead);

	SListNode* newnode = BuySLTNode(x);
	SListNode* tail = *pphead;

	newnode->next = *pphead;
	*pphead = newnode;
}

尾刪

分為三種情況:
1.鏈表沒有元素,那我們直接斷言解決
2.如果鏈表只有一個元素,那我們判斷一下,然后free掉第一個指針指向的空間
3.鏈表多個元素,我們這里選擇的是,判斷tail->next->next是否為空,如果不為空,我們讓tail指針向后走一步,再繼續(xù)判斷,直到tail->next->next為空,我們free掉tail->next即可

//尾刪
void SLTPopBack(SListNode** pphead)
{
	assert(pphead);
	assert(*pphead != NULL);//如果*pphead為空,說明鏈表沒有元素

	if ((*pphead)->next == NULL)//如果(*pphead)->next為空,說明鏈表只有一個元素,我們只需要free掉第一個指針指向的空間即可
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SListNode* tail = *pphead;
		//判斷tail->next->next是否為空,如果不為空,tail向后走一步,再判斷
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		//循環(huán)不滿足,說明tail->next->next為空
		//我們只需要free掉tail的next
		free(tail->next);
		tail->next = NULL;
	}
}

頭刪

分為兩種情況:
1.鏈表為空,直接用斷言解決
2.鏈表多個元素,我們直接用tail指針保留第一個指針的位置,然后再更新第一個位置的指針,最后free掉剛剛保留的tail位置
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

//頭刪
void SLTPopFront(SListNode** pphead)
{
	assert(pphead);
	assert(*pphead != NULL);

	SListNode* tail = *pphead;
	*pphead = tail->next;
	free(tail);
	tail = NULL;
}

查找

把phead指針賦給cur,如果cur->data和要查找的值相同,返回cur,如果不相同讓cur繼續(xù)向后走,直到相同位置,返回cur,如果走到NULL都沒有相同的,說明沒有。

//查找
SListNode* SLTFind(SListNode* phead, SLTDataType x)
{
	SListNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;

	}
	return NULL;
}

指定位置插入

進來直接判斷pos是不是第一個元素的空間,如果是,直接頭插
走到else里,我們定義一個prev指針,記錄pos前一個的位置,直到prev的next等于pos,然后把要插入的值放進prev的next位置,再把pos給newnode的next
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

//指定插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDataType x)
{
	assert(pos);
	assert(pphead);
	SListNode* newnode = BuySLTNode(x);

	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = newnode;
		newnode->next = pos;
	}
}

指定位置刪除

判斷要刪除的節(jié)點是否就是第一個節(jié)點,如果是,直接調(diào)用頭刪
反之,定義一個prev指針記錄pos的前一個位置,直到prev的next指針等于pos的時候,把pos的next賦給prev的next進行拼接,然后free掉pos即可
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

//指定刪除
void SLTErase(SListNode** pphead, SListNode* pos)
{
	assert(pphead);
	assert(pos);
	//判斷pos是否就是第一個節(jié)點
	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

pos位置后插入

pos位置后插入相比指定插入,通俗易懂
直接把newnode的next指向pos的next,然后再把pos的next指向newnode
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

//pos位置后插入
void SLTInsert_After(SListNode* pos, SLTDataType x)
{
	assert(pos);

	SListNode* newnode = BuySLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

pos位置后刪除

把pos的next給del,del是等會要刪除的位置
然后pos的next指向del的next,最后free掉del
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

//pos位置后刪除
void SLTEease_After(SListNode* pos)
{
	assert(pos);
	assert(pos->next);
	SListNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}

打印

把phead給cur指針,讓cur指針往后走,每次cur打印data數(shù)據(jù),直到走到NULL。

//打印
void SLTPrint(SListNode* phead)
{
	SListNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

銷毀

定義一個cur指針,再記錄一下cur的下一個位置,然后free掉cur,再把剛剛記錄的cur的next位置賦給cur,直到cur走到NULL為止
數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解

//銷毀
void SLTDestroy(SListNode** pphead)
{
	assert(pphead);
	SListNode* cur = *pphead;

	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

完整代碼

SList.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;

}SListNode;

//打印
void SLTPrint(SListNode* phead);
//尾插
void SLTPushBack(SListNode** pphead, SLTDataType x);
//頭插
void SLTPushFront(SListNode** pphead, SLTDataType x);
//尾刪
void SLTPopBack(SListNode** pphead);
//頭刪
void SLTPopFront(SListNode** pphead);

//查找
SListNode* SLTFind(SListNode* phead, SLTDataType x);

//指定插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDataType x);

//指定刪除
void SLTErase(SListNode** pphead, SListNode* pos); 

//pos位置后插入
void SLTInsert_After(SListNode* pos, SLTDataType x);

//pos位置后刪除
void SLTErase_After(SListNode* pos);

//銷毀
void SLTDestroy(SListNode** pphead);

SList.c

#include "SList.h"

//打印
void SLTPrint(SListNode* phead)
{
	SListNode* cur = phead;

	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}

	printf("NULL\n");
}

//創(chuàng)建新的節(jié)點
SListNode* BuySLTNode(SLTDataType x)
{
	SListNode* ret = (SListNode*)malloc(sizeof(SListNode));
	if (ret == NULL)
	{
		perror("BuySLTNode");
		return NULL;
	}
	ret->data = x;
	ret->next = NULL;

	return ret;
}

//尾插
void SLTPushBack(SListNode** pphead, SLTDataType x)
{
	assert(pphead);

	SListNode* newnode = BuySLTNode(x);

	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SListNode* tail = *pphead;
		//找尾
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}

}

//頭插
void SLTPushFront(SListNode** pphead, SLTDataType x)
{
	assert(pphead);

	SListNode* newnode = BuySLTNode(x);
	SListNode* tail = *pphead;

	newnode->next = *pphead;
	*pphead = newnode;
}

//尾刪
void SLTPopBack(SListNode** pphead)
{
	assert(pphead);


	assert(*pphead != NULL);

	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SListNode* tail = *pphead;

		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}

		free(tail->next);
		tail->next = NULL;
	}

}

//頭刪
void SLTPopFront(SListNode** pphead)
{
	assert(pphead);

	assert(*pphead != NULL);

	SListNode* tail = *pphead;
	*pphead = tail->next;
	free(tail);
	tail = NULL;

}

//查找
SListNode* SLTFind(SListNode* phead, SLTDataType x)
{
	SListNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;

	}
	return NULL;
}


//指定插入
void SLTInsert(SListNode** pphead, SListNode* pos, SLTDataType x)
{
	assert(pos);
	assert(pphead);
	SListNode* newnode = BuySLTNode(x);

	if (pos == *pphead)
	{
		SLTPushFront(pphead, x);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = newnode;
		newnode->next = pos;

	}
	
}
//指定刪除
void SLTErase(SListNode** pphead, SListNode* pos)
{
	assert(pphead);
	assert(pos);

	if (*pphead == pos)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

//pos位置后插入
void SLTInsert_After(SListNode* pos, SLTDataType x)
{
	assert(pos);

	SListNode* newnode = BuySLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;

}

//pos位置后刪除
void SLTEease_After(SListNode* pos)
{
	assert(pos);
	assert(pos->next);
	SListNode* del = pos->next;
	pos->next = del->next;
	free(del);
	del = NULL;
}


void SLTDestroy(SListNode** pphead)
{
	assert(pphead);
	SListNode* cur = *pphead;

	while (cur)
	{
		SListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	*pphead = NULL;
}

Test.c(測試代碼)

void SListTest2()
{
	SListNode* plist = NULL;

	SLTPushFront(&plist, 1);
	SLTPushFront(&plist, 2);
	SLTPushFront(&plist, 3);
	SLTPushFront(&plist, 4);
	SLTPrint(plist);

	SListNode* ret = SLTFind(plist, 2);
	//SLTPrint(plist);

	SLTInsert(&plist, ret, 22);
	SLTPrint(plist);

	SLTErase(&plist, ret);
	SLTPrint(plist);
}
int main()
{
	SListTest3();
	return 0;
}

下期講解帶頭雙向循環(huán)鏈表文章來源地址http://www.zghlxwxcb.cn/news/detail-463634.html

到了這里,關于數(shù)據(jù)結構《鏈表》無頭單向非循環(huán)-動圖詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關文章

  • 數(shù)據(jù)結構入門(C語言版)線性表中鏈表介紹及無頭單向非循環(huán)鏈表接口實現(xiàn)

    數(shù)據(jù)結構入門(C語言版)線性表中鏈表介紹及無頭單向非循環(huán)鏈表接口實現(xiàn)

    概念 : 線性表的鏈式存儲結構的特點是用一組任意的存儲單元存儲線性表的數(shù)據(jù)元素 。因此,為了表示每個數(shù)據(jù)元素與其直接后繼數(shù)據(jù)元素之間的邏輯關系,對數(shù)據(jù)元素來說,除了存儲其本身的信息之外,還需存儲一個指示其直接后繼的信息(即直接后繼的存儲位置)。這

    2023年04月09日
    瀏覽(30)
  • 【數(shù)據(jù)結構】單向鏈表

    【數(shù)據(jù)結構】單向鏈表

    哈嘍,大家好,今天我們學習的是數(shù)據(jù)結構里的鏈表,這里主要講的是不帶哨兵衛(wèi)頭節(jié)點的單向鏈表,下篇將會繼續(xù)帶大家學習雙向鏈表。 目錄 1.鏈表的概念 2.單向鏈表接口的實現(xiàn) 2.1動態(tài)申請一個節(jié)點 2.2單鏈表打印 2.3單鏈表尾插 2.4單鏈表頭插 2.5單鏈表尾刪 2.6單鏈表頭刪

    2024年02月11日
    瀏覽(26)
  • 數(shù)據(jù)結構——實現(xiàn)單向鏈表

    數(shù)據(jù)結構——實現(xiàn)單向鏈表

    單鏈表是一種常見的數(shù)據(jù)結構,用于存儲一系列的數(shù)據(jù)元素,每個節(jié)點包含數(shù)據(jù)和指向下一個節(jié)點的指針。 單鏈表通常用于實現(xiàn)某些算法或數(shù)據(jù)結構,如鏈式前向星、哈希表、鏈式棧、隊列等等。 單鏈表在程序設計中的作用不可忽略,是很多基礎算法的核心數(shù)據(jù)結構之一。

    2024年02月07日
    瀏覽(23)
  • 【數(shù)據(jù)結構】動圖詳解雙向鏈表

    【數(shù)據(jù)結構】動圖詳解雙向鏈表

    目錄 1.單向鏈表的劣勢 2.帶頭雙向循環(huán)鏈表 ? ? ? ? 1.邏輯結構 ? ? ? ?2.結點的代碼實現(xiàn) 3.雙向鏈表接口的實現(xiàn) ????????1.接口1---初始化 ????????2.接口2,3---頭插,尾插 ????????3. 接口4,5---頭刪,尾刪 ????????3. 接口6---查找 ?????????4. 接口7,8--插入,

    2024年01月23日
    瀏覽(29)
  • 數(shù)據(jù)結構:詳解【鏈表】的實現(xiàn)(單向鏈表+雙向鏈表)

    數(shù)據(jù)結構:詳解【鏈表】的實現(xiàn)(單向鏈表+雙向鏈表)

    1.順序表的問題和思考 問題: 中間/頭部的插入刪除,時間復雜度為O(N)。 增容需要申請新空間,拷貝數(shù)據(jù),釋放舊空間,會有不小的消耗。 增容一般是呈2倍的增長,勢必會有一定的空間浪費。例如當前容量為100,滿了以后增容到200,我們再繼續(xù)插入了5個數(shù)據(jù),后面沒有數(shù)據(jù)

    2024年03月26日
    瀏覽(34)
  • 數(shù)據(jù)結構與算法(三):單向鏈表

    數(shù)據(jù)結構與算法(三):單向鏈表

    鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結構,數(shù)據(jù)元素的邏輯是通過鏈表種的指針鏈接次序?qū)崿F(xiàn)的。鏈表由一系列節(jié)點組成,每個節(jié)點包括兩部分:一個是存儲數(shù)據(jù)元素的數(shù)據(jù)域,一個是存儲下一個節(jié)點地址的指針域。單向鏈表從頭節(jié)點(也可以沒有頭節(jié)點)開始

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

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

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

    2024年02月11日
    瀏覽(29)
  • 數(shù)據(jù)結構——單向鏈表(C語言版)

    在數(shù)據(jù)結構和算法中,鏈表是一種常見的數(shù)據(jù)結構,它由一系列節(jié)點組成,每個節(jié)點包含數(shù)據(jù)和指向下一個節(jié)點的指針。在C語言中,我們可以使用指針來實現(xiàn)單向鏈表。下面將詳細介紹如何用C語言實現(xiàn)單向鏈表。 目錄 1. 定義節(jié)點結構體 2. 初始化鏈表 3. 插入節(jié)點 4. 刪除節(jié)點

    2024年03月24日
    瀏覽(33)
  • 【數(shù)據(jù)結構】單向鏈表實現(xiàn) 超詳細

    【數(shù)據(jù)結構】單向鏈表實現(xiàn) 超詳細

    目錄 一. 單鏈表的實現(xiàn) 1.準備工作及其注意事項 1.1 先創(chuàng)建三個文件 1.2 注意事項:幫助高效記憶和理解 2.鏈表的基本功能接口 2.0 創(chuàng)建一個 鏈表 2.1 鏈表的 打印 ?3.鏈表的創(chuàng)建新節(jié)點接口 4.鏈表的節(jié)點 插入 功能接口 4.1 尾插接口 4.2 頭插接口 ? ??4.3 指定位置 pos 之前? 插入

    2024年02月19日
    瀏覽(23)
  • 【數(shù)據(jù)結構和算法】使用數(shù)組的結構實現(xiàn)鏈表(單向或雙向)

    【數(shù)據(jù)結構和算法】使用數(shù)組的結構實現(xiàn)鏈表(單向或雙向)

    上文我們通過結構體的結構實現(xiàn)了隊列 、以及循環(huán)隊列的實現(xiàn),我們或許在其他老師的教學中,只學到了用結構體的形式來實現(xiàn)鏈表、隊列、棧等數(shù)據(jù)結構,本文我想告訴你的是,我們 可以使用數(shù)組的結構實現(xiàn)鏈表、單調(diào)棧、單調(diào)隊列 目錄 前言 一、用數(shù)組結構的好處 1.數(shù)

    2024年01月20日
    瀏覽(91)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領取紅包

二維碼2

領紅包