1. 程式人生 > >資料結構與演算法分析——帶有頭結點的單鏈表的實現(C語言)

資料結構與演算法分析——帶有頭結點的單鏈表的實現(C語言)

資料結構與演算法分析——帶有頭結點的單鏈表的實現

表——一種簡單的資料結構,有兩種實現方式,陣列和連結串列,各有各的優點,用陣列來寫優點是查詢一個元素花費O(1)的時間,缺點是事先並不知道元素個數需要預估的大一些,可能浪費空間,另外刪除和插入花費O(N)的時間,用連結串列寫的缺點是查詢一個元素需要從頭開始查詢花費O(N)的時間,優點是採用了不連續儲存,插入和刪除都避免了線性開銷,也不用預估元素個數了,因為在使用表這種資料結構時,會用到大量的插入與刪除操作,所以表這種資料結構一般採用連結串列來實現

連結串列,每一個結點含有表元素和指向下一個結點的指標,主要操作有查詢,插入,刪除,大致有兩種寫法,一種是不帶頭結點的連結串列,另一種是帶頭結點的連結串列,使用頭結點還是有好處的,在插入和刪除時避免了對第一個結點的特判,在這裡我採用了頭結點

我是根據這本書上的函式寫的,初次接觸連結串列比較難理解的就是插入和刪除這兩個操作了,其實在紙上畫出來是一個比較好的理解方法,其餘的操作都挺簡單的,短小精悍。

在單鏈表實現的基礎上又有雙向連結串列和迴圈連結串列的擴充套件,可以避免單鏈表每次都要從頭結點開始查詢的缺點,還有一些應用用到了連結串列,比如多項式、基數排序。

在ACM中,做的題用到連結串列的不多

程式碼細節還是挺多的,一次就寫成功挺不容易的

/*
實現一個帶有頭結點的單鏈表,
*/
#pragma warning(disable:4996);
#include<stdio.h>
#include<stdlib.h>

struct Node;
typedef int ElementType;
typedef struct Node *PtrToNode;
typedef PtrToNode List;
typedef PtrToNode Position;
struct Node {
	ElementType Element;
	Position Next;
};


List MakeEmpty(List L); //生成一個空連結串列
int IsEmpty(List L);//判斷是否為空連結串列
int IsLast(Position P, List L);//判斷是否為最後一個節點
int Length(List L);//返回連結串列的長度
Position Find(ElementType X, List L);//查詢含有元素X的結點
void Delete(ElementType X, List L);//刪除含有元素X的節點
Position FindPrevious(ElementType X, List L);//查詢含有元素X結點的前驅元
void Insert(ElementType X, List L, Position P);//在P位置之後插入一個結點
void DeleteList(List L);//刪除連結串列
Position Header(List L);//返回頭結點
Position First(List L);//返回第一個節點
Position Advance(Position P);//返回該節點的後繼元
ElementType Retrieve(Position P);//返回該節點的元素
void Print(List L);//列印連結串列


List MakeEmpty(List L) {
	if (L != NULL) {
		DeleteList(L);
	}
	L = (List)malloc(sizeof(Node));
	if (L == NULL) {
		printf("out of space\n");
		exit(1);
	}
	L->Next = NULL;
	return L;
}
int IsEmpty(List L) {
	return L->Next == NULL;
}
int IsLast(Position P, List L) {
	return P->Next == NULL;
}
Position Find(ElementType X, List L) {
	Position P;
	P = L->Next;
	while (P != NULL && P->Element != X) {
		P = P->Next;
	}
	return P;
}
Position FindPrevious(ElementType X, List L) {
	Position P;
	P = L;
	while (P->Next != NULL && P->Next->Element != X) {
		P = P->Next;
	}
	return P;
}
void Delete(ElementType X, List L) {
	Position P, TmpCell;
	P = FindPrevious(X, L);
	if (!IsLast(P, L)) {
		TmpCell = P->Next;
		P->Next = TmpCell->Next;
		free(TmpCell);
	}
	else {
		printf("Not Found the Element %d\n",X);
	}
}
void Insert(ElementType X, List L, Position P) {
	Position TmpCell;

	TmpCell = (Position)malloc(sizeof(Node));

	if (TmpCell == NULL) {
		printf("Out of space!\n");
	}

	TmpCell->Element = X;
	TmpCell->Next = P->Next;
	P->Next = TmpCell;
}

void DeleteList(List L) {
	Position P, tmp;
	P = L->Next;
	L->Next = NULL;
	while (P != NULL) {
		tmp = P->Next;
		free(P);
		P = tmp;
	}
}
void Print(List L) {
	Position P = L->Next;
	printf("輸出連結串列所有元素: ");
	while (P != NULL) {
		printf("%d ", P->Element);
		P = P->Next;
	}
	printf("\n");
}
int Length(List L) {
	int Len;
	Len = 0;
	Position P = L->Next;
	while (P != NULL) {
		Len++;
		P = P->Next;
	}
	return Len;
}
Position Header(List L) {
	return L;
}
Position First(List L) {
	return L->Next;
}
Position Advance(Position P) {
	return P->Next;
}
ElementType Retrieve(Position P) {
	return P->Element;
}
int main(void) {
	List L = NULL;
	L = MakeEmpty(L);
	printf("已經建立了一個空表\n");
	if (IsEmpty(L)) {
		printf("該表是一個空表\n");
	}
	Position P;
	P = L;
	for (int i = 1; i <= 5; i++) {
		Insert(i, L, P);
		P = Advance(P);
	}
	printf("連結串列中共有 %d 個元素\n", Length(L));
	Print(L);
	printf("執行刪除0-3的操作\n");
	for (int i = 0; i <= 3; i++) {
		Delete(i, L);
	}
	printf("連結串列中共有 %d 個元素\n", Length(L));
	Print(L);
	for (int i = 4; i <= 5; i++) {
		printf("%d \n", Retrieve(Find(i, L)));
		if (IsLast(Find(i, L), L)) {
			printf("%d是最後一個元素\n",i);
		}
		else {
			printf("%d不是最後一個元素\n",i);
		}
	}
	DeleteList(L);
	if (IsEmpty(L)) {
		printf("該連結串列為空表\n");
	}
	getchar();
	getchar();
	return 0;
}

程式碼驗證