91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言無頭單向非循環鏈表的操作方法有哪些

發布時間:2022-04-24 10:05:50 來源:億速云 閱讀:159 作者:iii 欄目:開發技術

這篇文章主要介紹“C語言無頭單向非循環鏈表的操作方法有哪些”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“C語言無頭單向非循環鏈表的操作方法有哪些”文章能幫助大家解決問題。

鏈表引入

問:上次我們看了順序表,那么順序表有些什么優缺點呢?

優點:

順序表是連續的物理空間,方便下標的隨機訪問。

缺點:

1.增容需要申請新空間,拷貝數據,釋放舊的空間。會有一定消耗。

2.頭部或者中間位置插入或者刪除數據,需要挪動數據,效率較低。

3.可能存在一定空間占用,浪費空間,不能按需申請和釋放空間。

為了解決上訴問題,我們引入了鏈表。首先我們先來看看單鏈表。

鏈表介紹

鏈表是一種物理存儲結構上非連續、非順序的存儲結構、數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點(鏈表中每一個元素稱為結點)組成,結點可以在運行時動態生成。每個節點包含兩部分:一個是存儲數據元素的數據域,另一個是存儲下一個結點地址的指針域。

C語言無頭單向非循環鏈表的操作方法有哪些

實際上,鏈表的結構多樣,如下:

1.單向或者雙向

C語言無頭單向非循環鏈表的操作方法有哪些

2.帶頭或者不帶頭

C語言無頭單向非循環鏈表的操作方法有哪些

3.循環或者非循環

C語言無頭單向非循環鏈表的操作方法有哪些

創建鏈表

鏈表是由結點鏈接而成的,所以創建鏈表需要創建一個結點類型。該類型由指針域和數據域組成。

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;//用來存放該結點的數據
	struct SListNode* next;//用來存放下一個結點的地址
}SListNode;

打印鏈表

從頭指針指向的位置開始,依次向后打印,知道cur訪問到NULL就結束循環。

C語言無頭單向非循環鏈表的操作方法有哪些

void SListPrint(SListNode* phead);
void SListPrint(SListNode* phead)
{
	SListNode* cur = phead;//我們一般不會改變頭指針,所以我們把頭指針賦值給cur
	while (cur)//鏈表結束條件
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");//表示數據已經打印完畢
}

創建結點

每當我們需要插入一個數據,我們就需要申請一個結點,如果每次都重新申請就會很麻煩,所以我們將創建一個新結點封裝為一個函數。

SListNode* BuySListNode(SLTDataType x)
{
	SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));
	if (newnode == NULL)
	{
		printf("BuySListNode::%s\n", strerror(errno));//若申請失敗,則打印錯誤信息
		exit(-1);
	}
	else
	{
		newnode->data = x;//將數據賦值到新點的數據域
		newnode->next = NULL;//新結點指針域置為空指針
	}
	return newnode;//返回新結點的地址
}

單鏈表尾插

我們需要將尾插分為兩種情況:

情況一: 鏈表為空,我們直接讓頭指針指向新的結點即可。

情況二: 鏈表已經有多個結點,我們需要找到鏈表的最后一個結點,然后讓最后一個結點指向新的結點。

void SListPushBack(SListNode** pphead, SLTDataType x);
void SListPushBack(SListNode** pphead, SLTDataType x)
{
	assert(pphead);
	SListNode* newnode = BuySListNode(x);
	//鏈表為空
	if (*pphead == NULL)
	{
		*pphead = newnode;//頭指針指向新的結點
	}
	//鏈表不為空
	else
	{
		SListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

注意: 鏈表頭插函數的參數我們應該傳頭指針的地址,而不是頭指針本身。如果為傳值調用,那么形參是實參的一份臨時拷貝,對形參的改變不會影響實參。

單鏈表頭插

單鏈表頭插時,我們申請一個新的結點,然后讓新結點的指針域指向之前的第一個結點,然后讓頭指針指向新結點。

注意:這兩步操作的順序不可以顛倒,如果先讓頭指針指向了新結點,那么將不可能找到第一個結點的位置了。也不可能在找到后面的數據了。

void SListPushFront(SListNode** pphead, SLTDataType x);
void SListPushFront(SListNode** pphead, SLTDataType x)
{
	assert(pphead);
	SListNode* newnode = BuySListNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

單鏈表尾刪

演示一種錯誤的寫法:

C語言無頭單向非循環鏈表的操作方法有哪些

對于單鏈表的尾刪,我們需要考慮三種情況:

1.鏈表為空時,不做任何處理。

2.鏈表只有一個結點時,釋放該結點,然后將頭指針置為空。

3.鏈表有多個結點時,有兩種處理方法,詳見一下代碼。

C語言無頭單向非循環鏈表的操作方法有哪些

代碼一: 找到最后一個結點的前一個結點,釋放最后一個結點。將前一個結點的指針域置為空指針。

void SListPopBack(SListNode** pphead);
void SListPopBack(SListNode** pphead)
{
	assert(pphead);
	if (*pphead == NULL)
		return;
	else if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SListNode* prev = NULL;
		SListNode* tail = *pphead;
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		prev->next = NULL;
	}
}

代碼二: 找到最后一個結點的前一個結點,將后一個結點釋放掉,然后在置為空就可以了。

void SListPopBack(SListNode** pphead);
void SListPopBack(SListNode** pphead)
{
	assert(pphead);
	if (*pphead == NULL)
		return;
	else 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 SListPopFront(SListNode** pphead);
void SListPopFront(SListNode** pphead)
{
	assert(pphead);
	if (*pphead == NULL)//鏈表為空
		return;
	else
	{
		SListNode* head = *pphead;
		*pphead = head->next;//讓頭指針指針域中的地址指向頭指針
		free(head);//釋放第一個結點
		head = NULL;
	}
}

在pos位置之前插入數據

若pos是第一個結點,我們直接調用之前寫的頭插。若pos不是第一個結點,我們找到pos位置的前一個結點,讓新的結點指向地址為pos的結點,然后讓前一個結點指向新結點。

C語言無頭單向非循環鏈表的操作方法有哪些

void SListInsertBefore(SListNode** pphead, SListNode* pos, SLTDataType x);
void SListInsertBefore(SListNode** pphead, SListNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SListPushFront(pphead,x);//頭插函數
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)//找到pos的前一個結點
		{
			prev = prev->next;
		}
		SListNode* newnode = BuySListNode(x);
		newnode->next = prev->next;//讓新結點指向pos結點
		prev->next = newnode;//讓前一個結點指向新結點
	}
}

在pos位置之后插入數據

讓新結點指向該位置的下一個位置,然后讓該位置的結點指向新結點。

C語言無頭單向非循環鏈表的操作方法有哪些

void SListInsertAfter(SListNode** pphead, SListNode* pos, SLTDataType x);
void SListInsertAfter(SListNode** pphead, SListNode* pos, SLTDataType x)
{
	assert(pphead);
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

刪除pos位置結點

C語言無頭單向非循環鏈表的操作方法有哪些

void SListErase(SListNode** pphead, SListNode* pos);
void SListErase(SListNode** pphead, SListNode* pos)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SListPopFront(pphead);
	}
	else
	{
		SListNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
		pos = NULL;
	}
}

刪除pos位置之后的結點

C語言無頭單向非循環鏈表的操作方法有哪些

void SListEraseAfter(SListNode* pos);
void SListEraseAfter(SListNode* pos)
{
	assert(pos);
	SListNode* next = pos->next;
	if (next)//如果next不為空,則條件為真
	{
		pos->next = next->next;//讓pos指向要刪除位置的后一個結點
		free(next);//釋放pos的下一個結點
		next = NULL;
	}	
}

銷毀鏈表

在銷毀鏈表時。首先我們將頭指針賦值給一個新的指針,用該指針依次遍歷鏈表,先把該結點的下一個結點的地址保存,然后在釋放該結點,最后將頭指針置為空。

注意: 一定要在釋放該指針之前保存該指針的下一個結點的地址,否則就找不到下一個結點了。

void SListDestroy(SListNode** pphead);
void SListDestroy(SListNode** pphead)
{
	assert(pphead);
	SListNode* cur = *pphead;
	while (cur)
	{
		SListNode* next = cur->next;//存放下一個結點地址
		free(cur);//釋放當前結點
		cur = NULL;
	}
	*pphead = NULL;//將頭指針置為空
}

鏈表查找

SListNode* SListFind(SListNode* phead, SLTDataType x);
SListNode* SListFind(SListNode* phead, SLTDataType x)
{
	SListNode* cur = phead;
	while (cur != NULL)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

關于“C語言無頭單向非循環鏈表的操作方法有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

麦盖提县| 灵宝市| 丹江口市| 平山县| 财经| 仁布县| 永新县| 平舆县| 苏尼特右旗| 呈贡县| 深圳市| 石景山区| 独山县| 敖汉旗| 玉林市| 南涧| 巴东县| 平凉市| 徐水县| 邹城市| 开鲁县| 奉贤区| 泰宁县| 通许县| 石城县| 益阳市| 灌阳县| 昌乐县| 泸定县| 宣恩县| 达拉特旗| 河曲县| 兴海县| 师宗县| 吴江市| 大港区| 乐至县| 寻乌县| 墨竹工卡县| 阳江市| 剑川县|