目录
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;
}