線性表:動態鏈表

在數據結構中我們經常會用到鏈表來處理一些問題, 鏈表同順序表一樣, 包括靜態鏈表和動態鏈表, 靜態鏈表並不是很常用, 但動態鏈表的重要性是不言而喻的. 接下來我們看一下動態鏈表的基本操作, 以書上的資料爲參考, 同時自己對動態鏈表增加了新的認識和總結

動態鏈表的基本操作

動態鏈表的定義

//定義一個動態鏈表
typedef int ElemType;
typedef struct LNode {
	ElemType data;
	struct LNode* next;
}LNode, *LinkList;

創建一個動態鏈表

//創建一個動態鏈表
void CreateList(LinkList* L, int len) {
	printf("請輸入 %d 個數據:", len);
	//創建鏈表的頭節點
	*L = (LinkList)malloc(sizeof(LNode));
	//定義一個指向尾節點的指針和一個指向創建結點的指針
	LinkList rear = *L, p = NULL;
	//創建指定大小的空間
	for (int i = 1; i < len + 1; ++i) {
		p = (LinkList)malloc(sizeof(LNode));
		scanf("%d", &p->data);
		//尾指針連接新結點
		rear->next = p;
		//改變尾指針位置
		rear = p;
	}
	//尾指針之後爲空
	rear->next = NULL;
}

//逆序
//void CreateList(LinkList* L, int len) {
//	printf("請輸入 %d 個數據:", len);
//	//創建頭節點
//	*L = (LinkList)malloc(sizeof(LNode));
//	(*L)->next = NULL;
//	//定義一個指向創建結點的指針
//	LinkList p = NULL;
//	for (int i = 1; i < len; ++i) {
//		p = (LinkList)malloc(sizeof(LNode));
//		scanf("%d", &p->data);
//		p->next = (*L)->next;
//		(*L)->next = p;
//	}
//	printf("\n");
//}

求鏈表的長度

//鏈表長度
int Length(LinkList L) {
	int len = 0;
	while (L->next != NULL) {
		++len;
		L = L->next;
	}
	return len;
}

向動態鏈表中插入結點

//向動態鏈表中插入結點
void InsertList(LinkList* L, int pos, ElemType e) {
	//判斷插入位置是否合理
	if (pos < 1 || pos > Length(*L) + 1) {
		printf("插入位置不合理\n");
		return;// exit(0);
	}
	LinkList adjust = *L;
	LinkList insert = (LinkList)malloc(sizeof(LNode));
	insert->data = e;
	//調整adjust的位置, 準備連接
	int i = 0;
	while (i++ < pos - 1) {
		adjust = adjust->next;
	}
	//連接右端
	insert->next = adjust->next;
	//連接左端
	adjust->next = insert;
}

從動態鏈表中刪除結點

//從動態鏈表中刪除結點
void DeleteList(LinkList* L, int pos) {
	//判斷刪除結點的位置是否合理
	if (pos < 1 || pos > Length(*L)) {
		printf("刪除結點的位置不合理\n");
		return;// exit(0);
	}
	LinkList adjust = *L;
	//調整刪除位置, 準備刪除指定結點
	int i = 0;
	while (i++ < pos - 1) {
		adjust = adjust->next;
	}
	//保存要刪除的結點
	LinkList deleted = adjust->next;
	//連接要刪除結點的兩端結點
	adjust->next = deleted->next;
	//釋放結點
	free(deleted);
}

銷燬一個動態鏈表

//銷燬一個動態鏈表
void DestroyList(LinkList* L) {
	LinkList adjust = *L;
	while (*L) {
		//調整指針始終在頭節點的下一個位置, 用來保存新的頭節點
		adjust = (*L)->next;
		//釋放頭節點
		free(*L);
		//調整新頭節點的位置
		*L = adjust;
	}
	printf("鏈表已銷燬\n");
}

清空一個動態鏈表

//清空一個動態鏈表
void ClearList(LinkList* L) {
	LinkList adjust = (*L)->next;
	while ((*L)->next) {
		//調整指針始終指向被刪除結點的下一個結點, 用來保存下一個要被刪除的結點
		adjust = adjust->next;
		//每次釋放頭節點的下一個結點
		free((*L)->next);
		//更新頭節點的下一個結點(調整指針指向的結點)
		(*L)->next = adjust;
	}
	printf("鏈表已清空\n");
}

判斷鏈表是否爲空

//判斷鏈表是否爲空
int IsEmpty(LinkList L) {
	if (L->next == NULL) {
		//printf("鏈表爲空\n");
		return 1;
	}
	//printf("鏈表不爲空\n");
	return 0;
}

獲取動態鏈表上的某個值

//獲取動態鏈表上某個位置上的值
ElemType GetElem(LinkList L, int pos) {
	//判斷獲取位置是否合理
	if (pos < 1 || pos > Length(L)) {
		printf("獲取位置不合理\n");
		return 0;// exit(0);
	}
	LinkList adjust = L;
	//調整獲取位置
	int i = 0;
	while (i++ < pos) {
		adjust = adjust->next;
	}
	//返回獲取值
	return adjust->data;
}

在動態鏈表中查找某個元素

//在動態鏈表中查找某個元素
void LocateElem(LinkList L, ElemType e) {
	LinkList adjust = L->next;
	int count = 0;
	//遍歷鏈表
	while (adjust) {
		++count;
		if (adjust->data == e) {
			printf("找到了該元素, 它是第 %d 個元素\n", count);
			return;
		}
		adjust = adjust->next;
	}
	printf("沒有找到該元素\n");
}

在動態鏈表中查找某個元素的前驅

//在動態鏈表中查找某個元素的前驅
ElemType ProriElem(LinkList L, ElemType cur_e) {
	//判斷是否爲第一個元素
	if (L->next->data == cur_e) {
		printf("第一個元素無前驅\n");
		return 0;
	}
	//從第二個元素開始查找
	LinkList adjust = L->next;
	while (adjust->next) {
		if (adjust->next->data == cur_e) {
			return adjust->data;
		}
		adjust = adjust->next;
	}
	printf("沒有該元素\n");
	return 0;
}

在動態鏈表中查找某個元素的後繼

//在動態鏈表中找某個元素的後繼
ElemType NextElem(LinkList L, ElemType cur_e) {
	//從第一個元素查找, 最後一個元素要進行判斷
	LinkList adjust = L->next;
	while (adjust) {
		if (adjust->data == cur_e) {
			if (adjust->next != NULL) {
				return adjust->next->data;
			}
			printf("最後一個元素沒有後繼\n");
			return 0;
		}
		adjust = adjust->next;
	}
	printf("沒有該元素\n");
	return 0;
}

遍歷鏈表

//遍歷鏈表
void Traverse(LinkList L) {
	//判斷鏈表是否爲空
	if (L->next == NULL)  {
		printf("鏈表爲空\n");
		return;
	}
	while (L->next != NULL) {
		printf("%d ", L->next->data);
		L = L->next;
	}	
	printf("\n");
}

測試

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <windows.h>

//定義一個動態鏈表
typedef int ElemType;
typedef struct LNode {
	ElemType data;
	struct LNode* next;
}LNode, *LinkList;

//創建一個動態鏈表
void CreateList(LinkList* L, int len) {
	printf("請輸入 %d 個數據:", len);
	//創建鏈表的頭節點
	*L = (LinkList)malloc(sizeof(LNode));
	//定義一個指向尾節點的指針和一個指向創建結點的指針
	LinkList rear = *L, p = NULL;
	//創建指定大小的空間
	for (int i = 1; i < len + 1; ++i) {
		p = (LinkList)malloc(sizeof(LNode));
		scanf("%d", &p->data);
		//尾指針連接新結點
		rear->next = p;
		//改變尾指針位置
		rear = p;
	}
	//尾指針之後爲空
	rear->next = NULL;
}

//逆序
//void CreateList(LinkList* L, int len) {
//	printf("請輸入 %d 個數據:", len);
//	//創建頭節點
//	*L = (LinkList)malloc(sizeof(LNode));
//	(*L)->next = NULL;
//	//定義一個指向創建結點的指針
//	LinkList p = NULL;
//	for (int i = 1; i < len; ++i) {
//		p = (LinkList)malloc(sizeof(LNode));
//		scanf("%d", &p->data);
//		p->next = (*L)->next;
//		(*L)->next = p;
//	}
//	printf("\n");
//}

//鏈表長度
int Length(LinkList L) {
	int len = 0;
	while (L->next != NULL) {
		++len;
		L = L->next;
	}
	return len;
}

//向動態鏈表中插入結點
void InsertList(LinkList* L, int pos, ElemType e) {
	//判斷插入位置是否合理
	if (pos < 1 || pos > Length(*L) + 1) {
		printf("插入位置不合理\n");
		return;// exit(0);
	}
	LinkList adjust = *L;
	LinkList insert = (LinkList)malloc(sizeof(LNode));
	insert->data = e;
	//調整adjust的位置, 準備連接
	int i = 0;
	while (i++ < pos - 1) {
		adjust = adjust->next;
	}
	//連接右端
	insert->next = adjust->next;
	//連接左端
	adjust->next = insert;
}

//從動態鏈表中刪除結點
void DeleteList(LinkList* L, int pos) {
	//判斷刪除結點的位置是否合理
	if (pos < 1 || pos > Length(*L)) {
		printf("刪除結點的位置不合理\n");
		return;// exit(0);
	}
	LinkList adjust = *L;
	//調整刪除位置, 準備刪除指定結點
	int i = 0;
	while (i++ < pos - 1) {
		adjust = adjust->next;
	}
	//保存要刪除的結點
	LinkList deleted = adjust->next;
	//連接要刪除結點的兩端結點
	adjust->next = deleted->next;
	//釋放結點
	free(deleted);
}

//銷燬一個動態鏈表
void DestroyList(LinkList* L) {
	LinkList adjust = *L;
	while (*L) {
		//調整指針始終在頭節點的下一個位置, 用來保存新的頭節點
		adjust = (*L)->next;
		//釋放頭節點
		free(*L);
		//調整新頭節點的位置
		*L = adjust;
	}
	printf("鏈表已銷燬\n");
}

//清空一個動態鏈表
void ClearList(LinkList* L) {
	LinkList adjust = (*L)->next;
	while ((*L)->next) {
		//調整指針始終指向被刪除結點的下一個結點, 用來保存下一個要被刪除的結點
		adjust = adjust->next;
		//每次釋放頭節點的下一個結點
		free((*L)->next);
		//更新頭節點的下一個結點(調整指針指向的結點)
		(*L)->next = adjust;
	}
	printf("鏈表已清空\n");
}

//判斷鏈表是否爲空
int IsEmpty(LinkList L) {
	if (L->next == NULL) {
		//printf("鏈表爲空\n");
		return 1;
	}
	//printf("鏈表不爲空\n");
	return 0;
}

//獲取動態鏈表上某個位置上的值
ElemType GetElem(LinkList L, int pos) {
	//判斷獲取位置是否合理
	if (pos < 1 || pos > Length(L)) {
		printf("獲取位置不合理\n");
		return 0;// exit(0);
	}
	LinkList adjust = L;
	//調整獲取位置
	int i = 0;
	while (i++ < pos) {
		adjust = adjust->next;
	}
	//返回獲取值
	return adjust->data;
}

//在動態鏈表中查找某個元素
void LocateElem(LinkList L, ElemType e) {
	LinkList adjust = L->next;
	int count = 0;
	//遍歷鏈表
	while (adjust) {
		++count;
		if (adjust->data == e) {
			printf("找到了該元素, 它是第 %d 個元素\n", count);
			return;
		}
		adjust = adjust->next;
	}
	printf("沒有找到該元素\n");
}

//在動態鏈表中查找某個元素的前驅
ElemType ProriElem(LinkList L, ElemType cur_e) {
	//判斷是否爲第一個元素
	if (L->next->data == cur_e) {
		printf("第一個元素無前驅\n");
		return 0;
	}
	//從第二個元素開始查找
	LinkList adjust = L->next;
	while (adjust->next) {
		if (adjust->next->data == cur_e) {
			return adjust->data;
		}
		adjust = adjust->next;
	}
	printf("沒有該元素\n");
	return 0;
}

//在動態鏈表中找某個元素的後繼
ElemType NextElem(LinkList L, ElemType cur_e) {
	//從第一個元素查找, 最後一個元素要進行判斷
	LinkList adjust = L->next;
	while (adjust) {
		if (adjust->data == cur_e) {
			if (adjust->next != NULL) {
				return adjust->next->data;
			}
			printf("最後一個元素沒有後繼\n");
			return 0;
		}
		adjust = adjust->next;
	}
	printf("沒有該元素\n");
	return 0;
}

//遍歷鏈表
void Traverse(LinkList L) {
	//判斷鏈表是否爲空
	if (L->next == NULL)  {
		printf("鏈表爲空\n");
		return;
	}
	while (L->next != NULL) {
		printf("%d ", L->next->data);
		L = L->next;
	}	
	printf("\n");
}

int main() {
	LinkList L1;
	CreateList(&L1, 5);
	Traverse(L1);
	InsertList(&L1, 4, 100);
	Traverse(L1);
	int value = GetElem(L1, 4);
	printf("%d\n", value);
	LocateElem(L1, 100);
	int prori_e = ProriElem(L1, 100);
	printf("%d\n", prori_e);
	int next_e = NextElem(L1, 100);
	printf("%d\n", next_e);
	DeleteList(&L1, 4);
	Traverse(L1);
	system("pause");
	return 0;
}

效果圖
在這裏插入圖片描述 希望能得到大家的指點和支持