最近在看视频学习郝斌老师的数据结构,但是视频中只是讲了一部分数据结构的内容,静态链表没有讲,我参考大话数据对静态链表进行尝试。
静态链表其实是为了给没有指针的高级语言设计的一种实现单链表能力的方法。把静态链表整体看做是一个结构体数组,这个结构体中有两个数据域组成,data(数据)和cur(游标),数组的每一个下标都对应一个数据域和一个游标,数据域data存放数据,cur相当于单链表中的next指针,存放该节点的后继节点的坐标。为了方便插入数据,一般在把数组建得较大,以便有一些空闲空间在插入时不溢出。
静态链表的组成:
1.头结点:下标为0的节点,数据域不放内容,游标存放静态链表中第一个空闲节点的下标
2.尾节点:即数组的最后一个节点,数据域同样不放内容,游标存放静态链表中第一个有效节点的下标
主要算法:
1.初始化(init):每一个节点的游标都指向下一个节点的下标
2.插入(insert):如果是第一个位置插入,需要更新尾节点游标
3.删除(delete):如果删除第一个位置,需要更新尾节点游标
4.求长度(length):从第一个有效节点开始,遍历值节点游标为0的节点
具体程序如下,有较为详细的注释,相信大家都能看得懂。
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define Maxsize 10
typedef struct Node
{
int data;
int cur;
}NODE,StaticList[Maxsize];
//静态链表:每一个节点中data存放数据,cur游标存放下一个有效节点的下标
// 最后一个节点的游标存放第一个有效节点的下标
// 约定“头结点”,即第0个节点不存放数据
void init(StaticList space)
{
int i;
for(i = 0; i < Maxsize-1; i++)
space[i].cur = i + 1;
space[Maxsize-1].cur = 0;//目前静态链表为空,最后一个节点的cur存放头结点地址
return;
}
int length(StaticList space)
{
int len = 0;
int i = space[Maxsize-1].cur;//取出第一个有效节点的下标。
while(i)
{
i = space[i].cur;
len++;
}
return len;
}
bool isempty(StaticList space)
{
if(space[Maxsize-1].cur == 0)
return true;
else
return false;
}
bool is_full(StaticList space)
{
return true;
}
bool insert(StaticList space, int pos, int val)
{
int i = space[Maxsize-1].cur;//取到第一个有效节点的下标
if(pos < 1 || pos > length(space)+1)
return false;
int j = space[0].cur;//取出头结点的cur,即为第一个空闲节点的下标
if(j && j < Maxsize - 1)//这个地方为什么要判断是否为0,不太理解
{
space[j].data = val; //把数据放入对应数据域
space[0].cur = space[j].cur;//把space[j]拿出来使用了,所以space[j]的下一个分量作为空闲分量放在头结点中
if(pos == 1)//插在头部,即第一个位置
{
space[j].cur = i;
space[Maxsize-1].cur = j;//需要最后节点中的游标,即第一个有效节点的变为新插入的节点。
return true;
}
/*if(pos == length(space)+1)//插在尾部,即插在最后一个位置
{
space[j].cur = space[i].cur;//把i的游标赋给j,其实这时候我觉得可以直接赋值为0
space[i].cur = j;//原尾节点的游标变为新节点下标
return true;
}*/
int k;
for(k = 1; k < pos - 1; k++)
i = space[i].cur;
space[j].cur = space[i].cur;//把新节点的游标记录为pos-i的游标
space[i].cur = j; //pos-1的游标记录为新节点的下标
return true;
}
else
return false;
}
bool delete(StaticList space, int pos, int *val)
{
int i = space[Maxsize-1].cur;//第一有效节点的下标
if(pos < 1 || pos > length(space)+1)
return false;
if(pos == 1)
{
//要删除第一个节点,所以在删除之前需要把第一个节点的游标,即第二个的下标放在尾节点的游标中
space[Maxsize-1].cur = space[i].cur;
space[i].cur = space[0].cur;//把目前头结点存放的空闲节点下标,放在要删除的节点的游标中。
space[0].cur = i;//把第一个空闲节点的下标放进头结点游标中
}
else
{
int k;
for(k = 1; k < pos - 1; k++)
i = space[i].cur;
//for循环结束之后,i为pos-1的下标
int j = space[i].cur;//j为要删除节点下标
space[i].cur = space[j].cur;//要删除的前一个节点的游标等于删除节点的游标
space[j].cur = space[0].cur;//要删除节点的游标等于第一空闲节点的下标
space[0].cur = j;//作为空闲节点放在头结点中
}
return true;
}
void traverse(StaticList space)
{
int i = space[Maxsize-1].cur;
while(i)
{
printf("%d:%d ", i, space[i]);
i = space[i].cur;
}
printf("\n");
return;
}
int main(void)
{
StaticList S;
int val;
init(S);
S[1].cur = 0;
S[1].data = 99;
S[0].cur = 2;
S[Maxsize-1].cur = 1;
traverse(S);
//traverse(S);
insert(S,2,222);
insert(S,3,333);
insert(S,4,444);
insert(S,5,555);
traverse(S);
//insert(S,2,666);
delete(S,1,&val);
traverse(S);
//insert(S,1,1000);
//insert(S,1,999);
delete(S,2,&val);
traverse(S);
insert(S,2,13);
traverse(S);
return 0;
}