特点
基于数组实现,不依赖指针
具体实现
定义
- 使用游标cur(表示下一个元素数组下标)代替next指针
#define MAXSIZE 1000 //链表最大长度
typedef struct{
int data;
int cur;
}Component,StackLinkList[MAXSIZE]; //直接定义数组
初始化
- 数组首位存储第一个空闲位置下标(备用链表头结点),备用于分配
- 数组末位存储第一个元素(按静态链表顺序)下标,类似头结点
- 数组每个位置默认指向下一位(默认顺序排列)
- 数组末位设为0,用以表示链表结尾(链表此时为空,数组末位同时表示开头及结尾),类似单链表中最后一个节点指向NULL)
int InitList(StackLinkList space){
int i = 0;
for(int i = 0;i < MAXSIZE-1;i++){
space[i].cur = i+1; //默认指向数组下一位
}
space[MAXSIZE-1].cur = 0; //初始时,设置链表尾端为0
}
分配节点
单链表操作中通过动态分配空间,创造节点。
malloc在堆区通过扫描空闲链表,找到足够大小的内存块,并分配存储空间
类似的,通过数组首位找到当前空闲结点(即未使用数组位置),实现分配节点
同时,将数组首位更新指向下一个可用地址
int Malloc(StackLinkList space){
int i = space[0].cur; //返回一个备用的空闲下标
if(space[i].cur) //不为0
space[0].cur = space[i].cur; //指向下一个空闲节点
return i;
}
插入元素
- 通过数组末位(“头结点”),遍历链表,找到第i-1个元素,在其后插入(类似单链表操作)
void ListInsert(StackLinkList space,int i,int e){
int j,k,l;
k = MAXSIZE - 1;
if(i < 1 || i > ListLength(space) + 1) //可以在最后一个元素后插入
return;
j = Malloc(space); //分配存储位置
if(j){
space[j].data = e;
for(l = 1;l <= i-1;l++){
k = space[k].cur; //类似从头结点向后扫描
}
space[j].cur = space[k].cur;
space[k].cur = j;
}
}
释放节点
删除操作的最后需要使用free函数回收存储空间,类似地,可写出静态链表下的free函数
- 将释放位置放回空闲存储"链表"中,实现回收位置
void Free(StackLinkList space,int i){
space[i].data = 0;
space[i].cur = space[0].cur; //即将该位置插入到空闲的链中
space[0].cur = i;
}
删除
更改链表第i-1个元素cur值,指向第i+1个元素
若删除链表最后一个元素,则将第i-1个元素cur值改为0,表示链表末尾
void ListDelete(StackLinkList space,int i){
int j,k,l;
if(i < 1 || i > ListLength(space) + 1)
return;
k = MAXSIZE -1;
for(l = 1;l <= i-1;l++){ //找到第i-1个元素
k = space[k].cur;
}
j = space[k].cur; //找到第i个元素
space[k].cur = space[j].cur;
Free(space,j);
}
链表长度
通过数组末位(“头结点”),遍历链表,至cur值为0的元素(末尾)
int ListLength(StackLinkList space){
int len = 0;
int i = space[MAXSIZE-1].cur; //i为链表第一个元素下标
while(i){
i = space[i].cur;
len++;
}
return len;
}
创建链表(前插法)
可参考单链表前插法操作
每次在数组末位(头结点)与第一个元素间插入
void CreateList_H(StackLinkList space,int len){
int j;
int k = MAXSIZE-1;
int cnt = 0;
while(cnt < len){
j = Malloc(space);
space[j].data = cnt;
space[j].cur = space[k].cur;
space[k].cur = j;
cnt++;
}
}
打印链表
还是从数组末位开始遍历
void show(StackLinkList space){
int k = space[MAXSIZE-1].cur;
while(k){
printf("%d ",space[k].data);
k = space[k].cur;
}
printf("%c",'\n');
}
最后再check一下
int main(){
StackLinkList L;
InitList(L);
//前插法创建
printf("前插法创建:\n");
CreateList_H(L,8);
printf("长度:%d\n",ListLength(L));
show(L);
//插入
printf("插入:\n");
ListInsert(L,1,80);
show(L);
ListInsert(L,10,-1);
show(L);
ListInsert(L,2,70);
show(L);
//删除
printf("删除:\n");
ListDelete(L,2);
show(L);
ListDelete(L,1);
show(L);
ListDelete(L,9);
show(L);
}
结果:
前插法创建:
长度:8
7 6 5 4 3 2 1 0
插入:
80 7 6 5 4 3 2 1 0
80 7 6 5 4 3 2 1 0 -1
80 70 7 6 5 4 3 2 1 0 -1
删除:
80 7 6 5 4 3 2 1 0 -1
7 6 5 4 3 2 1 0 -1
7 6 5 4 3 2 1 0
上述代码参考自《大话数据结构》,可作为单链表相关实现逻辑的一种改写