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