1. 程式人生 > >靜態連結串列與迴圈連結串列的實現

靜態連結串列與迴圈連結串列的實現

一、靜態連結串列

用指標操作連結串列的實現固然方便,有時候我們也可以用一維陣列來實現連結串列的儲存與操作,這種方法不用設立指標,對於在沒有指標型別的高階程式設計語言中使用連結串列結構,可以用到。那麼如何用陣列來實現連結串列的儲存?先來看它的儲存結構:

#include <stdio.h>

#define MaxSize 100 /*連結串列的最大長度*/
#define ElemType int

/*靜態單鏈表的儲存結構*/
typedef struct Node {
	ElemType data;
	int cur; /*遊標代替指標指示結點在陣列中的相對位置*/ 
}component, SLinkList[MaxSize];

陣列的每一個分量代表連結串列中的一個結點,分量結構中的遊標指示器cur指示該結點在陣列中的相對位置(例如cur等於5代表該節點在陣列中下標為5的位置)。陣列的第0個分量可以看成是連結串列的頭結點,頭結點的指標域cur指示的是連結串列中的首元結點。

由於陣列方式是實現的連結串列結構要事先分配好空間大小,為了和指標型的連結串列區別開來,所以把這種用陣列表示的連結串列成為靜態連結串列。

假設space是SLinkList型的變數,則space[ 0 ].cur表示的是首元結點在陣列中的位置,若令i=space[ 0 ].cur,則space[ i ].data就是首元結點的資料元素值。space[ i ].cur指示的是首元結點之後第二個結點在陣列中的位置。若第N個數組分量表示的是第K個結點,那麼space[ N ].cur表示的是第K+1個結點的位置。所以靜態連結串列中的操作和指標型連結串列的操作相似。i=space[ i ].cur的操作其實就是指標型連結串列中的p=p->Next(後移操作)。例如如果我們想寫出靜態連結串列中的查詢元素操作,可以這樣寫:

int Search_SL(SLinkList space, ElemType K, int S) 
{
	int i;

	i=space[S].cur; /*i從連結串列的頭結點開始找起*/
	while (i && space[i].data!=K) {
		i=space[i].cur; /*i指向下一個結點,相當於p=p->Next*/
	}
	
	if (space[i].data==K) {
		printf("找到了,下標為:%d", i);
	} else {
		printf("沒找到這個元素.");
	}
	
	return i;
}

讓i從連結串列的頭結點開始,如果i && space[i].data!=K的話,就讓i=space[ i ].cur即指向下一個結點,直到找到元素位置,就返回該元素在陣列中的位置下標。

與指標型連結串列不同的是,靜態連結串列的malloc函式和free函式需要自己實現。malloc函式中將所有未被使用過的陣列分量連結成一個連結串列,每次呼叫malloc函式時就返回一個分量出去。而free函式將釋放的結點放回space連結串列中。下面我們先來看初始化連結串列怎麼做:

/*初始化連結串列*/
void InitSpace(SLinkList space) 
{
	/*將一維陣列中各個分量間建立關係鏈成一個連結串列,space[0].cur為頭指標*/
	int i; 
	
	for (i=0; i<MaxSize-1; i++) {
		space[i].cur=i+1;
		space[i].data=-1;
	}
	space[MaxSize-1].cur=0; /*連結串列中最後一個結點的"Next"指向NULL*/
}

將一維陣列space中各個分量通過遊標指示器cur建立連結關係形成一個連結串列,其中space[ 0 ].cur是頭指標。

/*malloc函式*/
int Malloc_SL(SLinkList space) 
{
	/*模擬malloc函式,分配一個結點的空間*/
	/*若連結串列非空,就返回分配的結點的下標,否則返回0*/
	int i;
	
	i=space[0].cur;
	if (space[0].cur) {
		space[0].cur=space[i].cur;/*指向下一個待分配的結點的下標*/
	}
	
	return i;
}

在連結串列中從第一個結點的位置開始,分出分量,返回該分量的位置下標i,把i的下一個結點賦給space[ 0 ].cur做下一次分配出去的結點用。

/*free函式*/
void free_SL(SLinkList space, int K) 
{
	/*將下標為K的空閒結點回收到備用連結串列*/
	
	/*下標為K的空閒結點回收到space[0].cur*/
	/*下一次呼叫malloc是就會先分配 K */
	space[K].cur=space[0].cur;
	space[0].cur=K;
}

free函式把要釋放的下標為K的結點,讓它的指標域cur等於space[ 0 ].cur,這樣下一次呼叫malloc函式時就會把下標為K的結點分配出去。

完整程式碼在個人程式碼雲:https://gitee.com/justinzeng/codes/783pvt9k5q1dnjl0ybxui80

  • 迴圈連結串列

迴圈連結串列是鏈式儲存結構的另一種形式,特點是迴圈連結串列中最後一個結點的指標域不是指向NULL而是指向連結串列的頭結點,使整個連結串列形成一個環狀,所以,從表中任何一個結點出發都可以找到其他結點。

迴圈連結串列的操作和線性連結串列的操作基本相同,不同的有例如遍歷迴圈連結串列的時,迴圈條件不是p或p->Next==NULL; 而是判斷p是否等於頭結點:

迴圈連結串列首尾連結方式:

/*連結末尾結點指向頭結點形成迴圈連結串列*/ 
void ConnectEndNode(List Ptrl) 
{
	List Ptrl1;
	Ptrl1=Ptrl;
	
	if (Ptrl1) {
		while (Ptrl1->Next) {
			Ptrl1=Ptrl1->Next;
		}
		Ptrl1->Next=Ptrl;
	}
}

求表長:

/*遍歷求表長*/
int Length(List Ptrl) 
{
	int count=0;
	List P=Ptrl->Next;
	while (P!=Ptrl) {
		P=P->Next;
		count++;
	} 
	
	return count;
}

完整程式碼在個人程式碼雲:https://gitee.com/justinzeng/codes/8ty9b4ez2rlh3swj0vciq30