動態鏈表之所以稱之為動態,因為它的存儲管理方便,用的時候申請空間,不用的時候釋放掉空間。
靜態鏈表的目的就是通過函數實現模擬動態鏈表中的申請空間和釋放空間,同是也要記錄下一個節點的位置,那麼需要解決幾個問題。
1.如何模擬動態節點。
動態鏈表需要空間的時候用malloc函數來從計算機系統中申請空間,並返回該空間的地址以便操作,釋放空間時用free函數將該空間重新返回給計算機系統中。
靜態鏈表中為了模擬這種申請空間和釋放空間的做法,需要兩個函數來實現。因為是靜態鏈表,所以只能用數組來表示節點,並且節點的內容包含數據域和指針域(暫且稱為指針,但並不是指針),因此可以定義一個結構體數組,將每個結構體看作是一個節點,結構體內包含數據域和指針域,可以做如下操作。
#define MAXSIZE 1000 typedef int Elem;//數據類型 typedef struct { Elem data;//數據域 int cur;//指針域 }StaticLinkList;
StaticLinkList List[MAXSIZE];
2.如何模擬申請到的空間和空閒的空間以及整個計算機空間。
申請完結構體數組後,將該數組看作是整個計算機空間。用的時候從這個裡面申請出一個節點來存放內容,釋放的話將該節點重新返回到空閒空間中。也就是說這整個結構體數組分為兩個部分,一部分是已經用的,另一部分是空閒的,所以需要將這兩部分區分開來。
為了記錄空閒空間和已占用空間的位置,需要兩個單獨的節點來保存這兩部分的起始點。
用第一個節點(也就是數組的第一個元素)來保存空閒空間的起始位置,用最後一個節點(也就是數組的最後一個元素)來保存已用空間的起始位置。
在計算機中每一個空間內存都有自己獨特的地址來標記,既然要模擬計算機系統,那麼每個空間也應該有著自己的獨特標記,而數組最好的標記就是每個元素的索引值了。
所以可以在最初的時候將其初始化,使每個數組元素都有著自己獨特的標記。
void CreateList(StaticLinkList *P)//創建一個靜態鏈表 { int i; for(i=0;i此時並沒有已占用空間,所以第一個節點中的指針(cur)的值為1,也就是說空閒空間的起始位置為1(下標為的1也是數組的第二個元素);而最後一個節點的指針的值為0,因為此時並沒有以占用的空間,最後一個節點類似於動態鏈表中的頭結點,當鏈表為空的時候就指向NULL(在這裡指向0),所以當頭結點中的指針等於0時代表鏈表為空。
可以在最初的時候給鏈表賦值。
void InitList(StaticLinkList *P) { int n,i; printf("請輸入鏈表的長度:"); scanf("%d",&n); for(i=1;i<=n;i++)//從下標1開始輸入內容 { printf("請輸入數據:"); scanf("%d",&P[i].data); P[0].cur = P[i].cur;//0位置記錄下一個空閒位置下標 } P[i-1].cur = 0; P[MAXSIZE-1].cur = 1;//記錄鏈表第一個元素的下標 }最後一個存放數據的cur為0;
3.如何模擬申請空間,插入節點。
由於第一個節點中的指針用來保存空閒空間的起始地址,所以只要修改第一個元素的cur即可。
int Malloc_List(StaticLinkList *P)//模擬創建節點,返回的是節點的下標 { int i; i = P[0].cur; P[0].cur = P[i].cur; return i; }先將空閒空間的位置賦值給i,然後再將i中保存的下一個位置賦值給第一個元素。
例如圖中:想要申請到位置7的空間,先修改第一個的數值,將其改為位置7中記錄的數值(也就是8),那麼位置7就相當於不在空閒空間中了,而且因為第一個節點中保存的是8,也就是說空閒空間的起始位置就是8了。
如果想將位置7插入到“乙”和“丁”之間的話,需要修改兩個地方。1.由於“乙”中保存的是下一個元素的位置,那麼需要將“乙”中下一個元素的位置修改為7,這樣在“乙”結束後會找下一個元素時就會在位置7上面找。2.由於位置7中保存的是下一個元素的位置,那麼需要將其修改為3(也就是“丁”的下標),這樣在找完位置7之後就是位置3了。
插入的方式可以如下:
void ListInsert(StaticLinkList *P)//插入鏈表 { int k,n,i,j; printf("請輸入插入的位置:"); scanf("%d",&n); if(n<1 || n>P[0].cur) { printf("插入位置異常,插入失敗!\n"); return ; } if(ListLength(P) == MAXSIZE-1)//如果鏈表滿了 { printf("靜態鏈表已滿,插入失敗!\n"); return ; } k = MAXSIZE-1; j = Malloc_List(P); for(i=1;i
4.如何模擬釋放空間,刪除節點。
同理,既然第一個節點保存的是空閒空間的起始位置,那麼修改第一個節點中的cur值即可。
void FreeList(StaticLinkList *P,int k)//模擬釋放節點 { P[k].cur = P[0].cur; P[0].cur = k; }將需要釋放的位置k傳入進來,讓空閒空間的起始位置為該釋放的位置(也就是k),並且將k的下一個節點的值設置為剛才的起始位置,這樣就將空閒空間的位置連接起來,並且需要修改相應位置上的cur,讓其連接起來。
如下圖要釋放位置1上的空間。
修改前:
修改後:
例如上圖,將位置1的空間釋放,先讓空閒空間的起始位置為1,並且讓位置1的下一個位置為8,所以空閒空間也就連起來了,1——8——9——10..,....(原先是:8——9——10........);而且需要修改刪除位置前的cur,使其能夠找到下一個元素,在這裡由於刪除的是第一個元素,所以需要修改頭結點(最後一個元素)的cur,原來是1,將其改為原先位置1中的cur(cur保存的是下一個節點的位置,1中原先保存的是2),那麼查找順序就會是2——7——3——...(原先是1——2——7——3——...)。
刪除的方式可以如下:
void DeleteList(StaticLinkList *P)//刪除節點 { int n,i,k,j; printf("請輸入刪除的位置:"); scanf("%d",&n); if(n<1 || n>ListLength(P)) { printf("刪除的位置異常,刪除失敗!\n"); return ; } k = MAXSIZE-1; for(i=1;i
5.如何遍歷鏈表。
因為最後一個元素相當於頭結點,並且其中保存的是鏈表第一個元素的位置,所以應該從頭結點開始遍歷,然後根據每個節點中的cur的值找到下一個節點的位置。
遍歷代碼可以如下:
void OutputList(const StaticLinkList *P)//輸出鏈表 { int i,k; k = MAXSIZE-1; for(i=1;i<=ListLength(P);i++) { k = P[k].cur; printf("%d\n",P[k].data); } }
例:如遍歷以下圖中的數據的話。
k最先等於999;鏈表長度為6(甲乙丁戊己庚)。
依次遍歷的話,i的值從1開始到6結束公六次循環。
k的值依次為;1 2 3 4 5 6.每次根據k的值將其數據輸出即可。
整體代碼可以如下:
#include#define MAXSIZE 1000 typedef int Elem; typedef struct { Elem data; int cur; }StaticLinkList; void CreateList(StaticLinkList *P)//創建一個靜態鏈表 { int i; for(i=0;i P[0].cur-1) { printf("查找位置異常,查找失敗!\n"); return ; } k = P[MAXSIZE-1].cur; for(i=1;i P[0].cur) { printf("插入位置異常,插入失敗!\n"); return ; } if(ListLength(P) == MAXSIZE-1)//如果鏈表滿了 { printf("靜態鏈表已滿,插入失敗!\n"); return ; } k = MAXSIZE-1; j = Malloc_List(P); for(i=1;i ListLength(P)) { printf("刪除的位置異常,刪除失敗!\n"); return ; } k = MAXSIZE-1; for(i=1;i