線性表的可以順序實現(數組),也可以鏈式實現(鏈表)。但是這兩種方式各有優缺點。順序實現雖然可以隨機存取數據,但是在插入或者刪除時需要移動大量元素。鏈式實現在插入或者刪除數據時只需修改其前驅、后繼的指針即可,但是在隨機存取數據時卻需要從頭開始。此時,靜態鏈表會是一個不錯的選擇。
靜態鏈表其實就是借用一維數組來描述線性鏈表。
#define MAXSIZE 100 typedef struct{ ElemType data; int cur; }component,SLinkList[MAXSIZE];
在如上述的鏈表中,結構數組的一個元素表示一個結點,同時用游標(指示器cur)代替指針指示結點在數組中的相對位置。
結構數組的第一個元素可看成是頭結點,其指針域指向的是鏈表的第一個結點。這種存儲方式仍需事先分配一個較大的空間,但是在線性表插入或者刪除數據時就不需移動數據了,只要秀高指針即可。,這就是靜態鏈表最大的優點。
例如在靜態鏈表中實現定位函數LocateElem。
int LocateElem_SL(SLinkList S,Elemtype e){ i=S[0].cur; while(i&&S[i].data!=e) i=S[i].cur; retuen i; }
靜態鏈表與動態鏈表的異同點
異:靜態鏈表是數組實現的,是順序存儲結構,在物理地址上是連續的,而且需要預先分配大小。動態鏈表是用內存申請函數(malloc)動態申請內存的,所以每個節點的物理地址是不連續的,要通過指針來順序訪問。
同:在插入或者刪除數據時只需修改指針即可,不用移動元素。
下面附一個例子:
#include <stdio.h> #define N 100 typedef struct{ char data; int cur; }SList; void init_sl(SList slist[]){//初始化成空閑靜態鏈表, int i; for(i=0;i<N-1;i++) { slist[i].cur=i+1; } slist[N-1].cur=0;//最后一個指針域指向0 } int malloc_sl(SList slist[]){//分配空閑節點 int i=slist[0].cur;//總是取頭結點之后的第一個空閑結點做分配,同時空閑鏈表非空,頭結點做調整 if (i) { slist[0].cur=slist[i].cur;//空閑鏈表頭結點調整指針域 } return i;//返回申請到的空閑節點的數組下標 } void free_sl(SList slist[],int k){//將k節點回收 slist[k].cur=slist[0].cur;//總是將回收的節點放在頭結點之后 slist[0].cur=k; } int difference_sl(SList slist[],int n){ int i,m,q,p; char tmp[2];//為避免出現scanf輸入字符出現接受回車符,則采用輸入字符串的形式 int start,end;//start是哨兵,end指向最后的節點 init_sl(slist);//初始化 start=malloc_sl(slist);//從空閑鏈表中取出第一個空閑節點生成鏈表的頭結點 //注意區分,現在是有一個空閑鏈表是slist,里面都是空閑節點,每次申請malloc_sl和free_sl都是操作的是slist //然后非空靜態鏈表,即集合A的鏈表是由start這個下標指引一直向后走,end指向非空鏈表的尾節點, //而且你發現start基本上都是1,因為開始的時候slist都是空閑節點,而分配又都是從頭結點slist[0]之后的第一個 //節點,即slist[1]開始分配,所以start=1 end=start; while (n--) { scanf("%s",tmp); i=malloc_sl(slist); slist[i].data=tmp[0]; slist[end].cur=i; end=i;//end指針后移 } slist[end].cur=0;//這個勿忘!尾節點的指針為空 //至此A集合輸入完畢,然后處理B集合 scanf("%d",&m); while (m--) { scanf("%s",tmp); //從A集合中掃描,如果A中存在tmp,則在A中刪除(free_sl),即A-B,如果沒有則添加入A,即B-A q=start;//q是p的前驅 p=slist[start].cur; while (p!=slist[end].cur&&slist[p].data!=tmp[0]) { q=p; p=slist[p].cur; } if (p!=slist[end].cur)//說明在A中找到了tmp,則刪除 { slist[q].cur=slist[p].cur;//跨過p節點 free_sl(slist,p); if (end==p) { end=q;//如果刪除的是尾節點,則修改尾節點指針 } }else{ i=malloc_sl(slist); slist[i].data=tmp[0]; slist[i].cur=slist[end].cur; slist[end].cur=i;//插在end后,end位置不變,因為end是標志集合A的結束 } } return start; } void print_sl(SList slist[],int start){ int p=slist[start].cur; while (p) { printf("%c ",slist[p].data); p=slist[p].cur; } printf("\n"); } int main(){ int n,start; SList slist[N]; freopen("1.txt","r",stdin); //該程序是求(A-B)U(B-A)集合運算 while (scanf("%d",&n)==1) { start=difference_sl(slist,n); print_sl(slist,start); } fclose(stdin); return 0; }