C语言 线性表之静态链表的相关操作

学习静态链表的时候,理解清楚真是废了我九牛二虎之力啊,查找了好多博客,再看了一下视频讲解后,便觉得柳暗花明又一村,

现整理如下:

一、什么是静态链表

用数组描述的链表,即称为静态链表。在C语言中,静态链表的表现形式即为结构体数组,结构体变量包括数据域data和游标CUR。
 
 
 
二、静态链表重点
  • 数组的第一个和最后一个元素做特殊处理,其data不放数据
  • 我们通常把删除了的或未使用的数组元素称为备用链表
  • 数组的第一个元素,即下标为0的那个元素的cur用于存放备用链表的第一个结点的下标
  • 数组的最后一个元素,即下标为MAXSIZE-1的cur用于存放第一个有数据的元素的下标,相当于链表的头结点

三、静态链表的实现

不同于动态链表,静态链表没有malloc()函数和free()函数,需要我们对数组进行操作,自行实现这两个函数的功能,这就用到了备用链表,

理解好备用链表对于静态链表的分析很关键。

静态链表存储结构:

1 #define MAXSIZE 100
2 typedef int ElemType; 
3 typedef struct{
4     ElemType data;
5     int cur; /*游标(Cursor),为0时表示无指向*/
6 }Component,StaticLinkList[MAXSIZE];

静态链表的初始化:

图示:

 

 

 

 

代码如下

 

 

1 /*将一维数组space中各分量链成一备用链表*/
2 /*space[0].cur为头指针*/
3 bool InitList(StaticLinkList space){ 
4     int i;
5     for(i=0;i<MAXSIZE-1;i++)
6     space[i].cur = i+1;
7     space[MAXSIZE-1].cur = 0;  /*目前静态链表为空,最后一个元素的cur为0*/
8     return true;
9 }

(1)静态链表的插入操作

静态链表的插入操作,由两部分代码组成,首先是获取空闲分量的下标。

1 /*若备用链表非空,返回分配的结点的下标,否则返回0*/
2 int Malloc_SLL(StaticLinkList space){
3     int i = space[0].cur;  /*space[0]即为数组的第一个元素,它的游标cur连接的是备用链表的第一个结点的下标*/
4     if(space[0].cur)
5     space[0].cur = space[i].cur;  /*由于使用了一个元素,我们将它的后继链接元素作为备用链表的头*/
6     return i;
7 }

然后再将数据插入所取的空闲分量里。

 1 /*在L中第i个元素之前插入新元素e*/
 2 bool ListInsert(StaticLinkList L, int i, ElemType e){    
 3     int j, k ,l;
 4     k = MAXSIZE -1;  /*获取数组最后一个位置下标*/
 5     if(i<1)return false;
 6     j = Malloc_SLL(L);  /*获取备用链表第一个位置的下标*/
 7     if(j){
 8         L[j].data = e;  /*将数值赋给数据域data*/
 9         for(l=1;l<=i-1;l++)
10         k = L[k].cur;  /*获取第i个元素之前位置的下标*/
11         L[j].cur = L[k].cur;
12         L[k].cur = j;  /*cur值之间的重新链接*/
13         return true;
14     }
15     return false;
16 }

例如要插入数据F到第3个位置

(1)获取到数组第一个位置(即下标为0)的游标6,该游标指向备用链表(即为要插入的地方)的下标,将0改为7,实现类似分配一个空间给数据链表,

让其指向新的备用链表的起始位置,将数据F写入数据域。

(2)实现插入数据到第3个位置,则相当于将第2个位置的游标改为插入位置的下标,令其指向插入位置;再将插入位置的游标改为原第三个位置的下标,实现插入。

 

如下图

 

(2)静态链表的删除操作

 同静态链表的插入操作类似

1 void Free_SLL(StaticLinkList space,int k){
2     // 将删除的数据的游标改为第0个索引的游标, 即原指向空闲向量的游标
3     space[k].cur=space[0].cur;
4     // 将第0个索引的游标的指向更改为删除数据的索引, 实现回收
5     space[0].cur=k;
6 }
 1 /*在L中将第i个元素删除*/
 2 int ListDelete(StaticLinkList L,int i){
 3     int j,k;
 4     if(i<1 || i>GetLength(L)) return ERROR;
 5     k=MAXSIZE-1;/*获取数组最后一个位置下标*/
 6     for(j=1;j<=i-1;j++){
 7         k=L[k].cur;
 8     }
 9     j=L[k].cur;
10     L[k].cur=L[j].cur;
11     Free_SLL(L,j);
12     return OK;
13 } 

 

所有代码

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #define MAXSIZE 100 
  4 #define ERROR 0
  5 #define OK 1
  6 typedef int ElemType; 
  7 typedef struct{
  8     ElemType data;
  9     int cur; /*游标(Cursor),为0时表示无指向*/
 10 }Component,StaticLinkList[MAXSIZE];
 11 
 12 /*将一维数组space中各分量链成一备用链表*/
 13 ElemType InitList(StaticLinkList space){ 
 14     int i;
 15     for(i=0;i<MAXSIZE-1;i++)
 16     space[i].cur = i+1;
 17     space[MAXSIZE-1].cur = 0;  /*目前静态链表为空,最后一个元素的cur为0*/
 18     return OK;
 19 }
 20 
 21 int GetLength(StaticLinkList Space){
 22     int len = 0;
 23     // 获取最后一个下标的游标, 因为最后一个下标的游标指向第一个数据的下标
 24     int index = Space[MAXSIZE - 1].cur;
 25 
 26     while(index){ // 判断是否有效
 27         len++;  // 长度加1
 28         index = Space[index].cur;
 29     }
 30 
 31     return len;
 32 }
 33  
 34 /*若备用链表非空,返回分配的结点的下标,否则返回0*/
 35 int Malloc_SLL(StaticLinkList space){
 36     int i = space[0].cur;  /*返回备用链表的第一个结点的下标*/
 37     if(space[0].cur)
 38     space[0].cur = space[i].cur;  /*由于使用了一个元素,我们将它的后继链接元素作为备用链表的头*/
 39     return i;
 40 }
 41 
 42 /*在L中第i个元素之前插入新元素e*/
 43 ElemType ListInsert(StaticLinkList L, int i, ElemType e){    
 44     int j, k ,l;
 45     k = MAXSIZE -1;  /*获取数组最后一个位置下标*/
 46     if(i<1 || i> GetLength(L) + 1)return false;
 47     j = Malloc_SLL(L);  /*获取备用链表第一个位置的下标*/
 48     if(j){
 49         L[j].data = e;  /*将数值赋给数据域data*/
 50         for(l=1;l<=i-1;l++)
 51         k = L[k].cur;  /*获取第i个元素之前位置的下标*/
 52         L[j].cur = L[k].cur;
 53         L[k].cur = j;  /*cur值之间的重新链接*/
 54         return OK;
 55     }
 56     return ERROR;
 57 }
 58 void Free_SLL(StaticLinkList space,int k){
 59     // 将删除的数据的游标改为第0个索引的游标, 即原指向空闲向量的游标
 60     space[k].cur=space[0].cur;
 61     // 将第0个索引的游标的指向更改为删除数据的索引, 实现回收
 62     space[0].cur=k;
 63 }
 64 /*在L中将第i个元素删除*/
 65 ElemType ListDelete(StaticLinkList L,int i){
 66     int j,k;
 67     if(i<1 || i>GetLength(L)) return ERROR;
 68     k=MAXSIZE-1;/*获取数组最后一个位置下标*/
 69     for(j=1;j<=i-1;j++){
 70         k=L[k].cur;
 71     }
 72     j=L[k].cur;
 73     L[k].cur=L[j].cur;
 74     Free_SLL(L,j);
 75     return OK;
 76 } 
 77 
 78 void DispList(StaticLinkList L){
 79     int i,j;
 80     i=L[MAXSIZE-1].cur;
 81     while(i){
 82         printf("%d ",L[i].data);
 83         i=L[i].cur;
 84     }
 85     printf("\n");
 86     
 87 }
 88 
 89 int main(){
 90     StaticLinkList space;
 91     printf("静态链表的相关操作如下:\n");
 92     InitList(space);
 93     printf("(1)输入四个元素:");
 94     ListInsert(space,1,1);
 95     ListInsert(space,2,2);
 96     ListInsert(space,3,3);
 97     ListInsert(space,4,4);
 98     DispList(space);
 99     printf("(2)删除第二个元素:");
100     ListDelete(space,2);
101     DispList(space);
102     printf("(3)删除第一个元素:");
103     ListDelete(space,1);
104     DispList(space);
105 }

运行结果:

 四、静态链表总结

优点:在插入和删除操作时,只需要修改游标,不需要移动元素,从而改进了在顺序存储结构中的插入和删除操作需要移动大量元素的缺点。

缺点:没有解决连续存储分配带来的表长难以确定的问题。

总的来说,静态链表其实是为了给没有指针的编程语言设计的一种实现单链表功能的方法,数组的下标也充到了类似地址的作用。

 

文章部分图片来源网络,代码如有问题欢迎指正,期待你的关注!!

posted @ 2021-09-06 19:25  旺旺哈  阅读(274)  评论(0)    收藏  举报