目錄
1.什麼是靜態鏈表
用數組來代替指針,描述單鏈表。定義一個結構體,結構體中包含兩個整形變量,第一個整形變量等價於鏈表中的data域,第二個整形元素等價於單鏈表中的next指針域,這個變量用cur表示,用來存儲下一個元素的數組下標。結構體類型如下:
struct node{
int data; //數據域
int cur; //指針域
}slist[M],snode;
注意:<1>靜態鏈表中對數組中的第一個元素和最後一個元素做特殊處理,第一個元素相當於單鏈表中的尾指針,數據域不存數據,cur域用來存儲備用鏈表中的第一個元素的下標;最後一個元素中的data域同樣不存數據,cur域用來存儲第一個放數據的元素的下標,該結點相當於單鏈表中的頭結點(注意不是首結點);
<2>備用鏈表:未被使用的數組元素被稱爲備用鏈表;
2.添加一個新元素
node* createnode(node* p,int e)
{
int a,l;
l = 0;
if(p[M-1].cur==0) //表示當前鏈表爲空
{
a = 1;
p[a].data = e; //將數據放到下標爲1的結點中
p[0].cur = p[a].cur; //改變第一個結點中所存儲的備用鏈表的第一個節點的下標
p[a].cur = 0; //將尾結點指向空
p[M-1].cur = 1; //將頭結點中的下標指向首結點
}
else
{
a = p[0].cur; //找到備用鏈表中第一個結點的下標
p[0].cur = p[a].cur; //備用鏈表中的下一個元素的下標
l = findcur(p,0); //找到鏈表中cur域爲0的結點的下標
p[l].cur = a; //將之前的尾結點指向新插入的結點(即將之前尾結點的cur域賦值爲新結點的下標值)
p[a].data = e; //完成對新結點數據域的賦值
p[a].cur = 0; //使其指向空
}
return p;
}
3.插入結點
(這裏和書上實現不太一樣)
要點:<1>首先獲取備用鏈表中的第一個空閒結點,作爲這個插入元素的存儲結點,將數據存到這個節點的數據域中;
<2>獲取第i個元素之前的結點的下標,讓這個結點指向插入結點(即將插入結點的下標賦值給i之前結點的cur域);
<3>將這個新插入結點的cur賦值爲i元素的下標,即完成新插入結點的指向。
//在第i個元素之前插入元素e
node* insertnode(node* p,int i,int e)
{
int l,j;
//如果當前表是空的直接退出
if(p[M-1].cur==0)
{
printf("鏈表爲空,不能插入!\n");
return p;
}
if(i<1||i>(M-1))
{
printf("要插入的結點不在鏈表範圍內,不能插入\n");
return p;
}
l = p[0].cur; //先找到備用鏈表中第一個空閒結點
if(l) //表示鏈表沒有滿,可以取到空閒結點
{
p[0].cur = p[l].cur; //將備用鏈表的首結點 放在第一個鏈表的cur中
j = findcur(p,i); //找到下標爲i的那個結點的前一個節點的下標
p[j].cur = l; //將前一個結點指向這個新結點
p[l].data = e;
p[l].cur = i; //插入的這個結點指向i結點1
}
return p;
}
4.刪除結點
要點:<1>查找要刪除結點的上一個結點,使該結點的遊標(cur)指向要刪除結點的下一個結點
<2>回收刪除的結點,將該回收結點放到備用鏈表頭:第一,將第一個結點的遊標賦值給回收結點的遊標;第二,將第一 個結點的遊標指向回收結點。
//刪除鏈表中第l個結點
node* deletenode(node* p,int l)
{
if(p[M-1].cur == 0) //頭指針指向空,則鏈表爲空不能刪除
{
printf("the list is null\n");
return p;
}
if((l<1)||(l>=(M-2))) //如果輸入的位置在第一個和最後一個結點之外,也不能刪除,輸入範圍不對
{
printf("the location is error!\n");
return p;
}
int temp;
int c;
c = findcur(p,l); //找到上一個指向要輸入的這個結點的下標
p[c].cur = p[l].cur; //將要刪除結點的上一個結點的cur指向要刪除結點的下一個結點
p[l].cur=p[0].cur ; //將刪除了的這個空閒結點的遊標指向0中存的遊標 ,實現將該結點會收到備用鏈表中
p[0].cur = l; //將0中存的第一個備用鏈表的遊標指向剛剛刪除的這個結點
return p;
}
5.靜態鏈表的初始化
目標:將鏈表初始化爲備用鏈表
要點:1. 從第一個結點開始,使其cur指向下一個結點(即備用鏈表的首結點爲1,後面的結點依次連接起來);
2. 最後一個元素的cur域置爲0,表示該鏈表爲空鏈表;
//初始化所要做的操作就是將所有的cur都置爲下一個元素的數組下標,尤其是最後一個元素的下標置爲0,表示該鏈表爲空
node* initlist(node* p)
{
int i;
for(i=0;i<M-1;i++)
{
p[i].cur =(i+1);
}
p[M-1].cur = 0; //表示當前鏈表爲空
return p;
}
6.打印靜態鏈表
int plist(node* p)
{
int m = p[M-1].cur; //從首結點開始打印
while(m!=0)
{
printf("%d,%d\n",m,p[m].data);
m = p[m].cur;
}
return 0;
}
7. 查找給定結點的上一個結點的下標
int findcur(node* p,int c)
{
int i=1;
int l=(M-1);
while(c==0)
{
if(p[i].cur == 0)
{
return i;
}
else
{
i = p[i].cur;
}
}
for(i=1;i<c;i++) //找到i元素的上一個結點的下標
{
l=p[l].cur;
}
return l;
}
8.主函數
#include "stdio.h"
#include "stdlib.h"
#define M 1000
struct node{
int data;
int cur;
}slist[M],snode;
int main()
{
node *p;
int n,i=0,e;
p = &slist[0];
p = initlist(p);
scanf("%d",&n);
while(n!=i)
{
scanf("%d",&e);
createnode(p,e);
i++;
}
p = insertnode(p,2,13);
plist(p);
p = deletenode(p,5);
plist(p);
return 0;
}