线性表3——静态链表

零、说明

  1. 产生原因:某些早期语言没有指针,却想使用链表的功能
  2. 结构说明:
    (1)静态链表实际上是一个结构体数组,数组的每一个元素(即一个结构体)有两个成员:int data(数据)、int cur(相当于指针的东西,但是在结构体数组内运作)
    (2)静态链表分为四部分:(依照我自己的习惯分类命名)
    a. 头节点:s[0],data存储已经使用的节点的数量,cur存储备用链表第一个节点的下标
    b.尾节点:s[MAXSIZE-1],data存储未用节点的数量,cur存储已用链表第一个节点的下标
    c.已用链表:已经用于存储数据的部分,data存储数据,cur存储下一个存数据的节点。但是已用链表的最后一位的cur=0,表示已经到头了
    d.备用链表:还没用于存储数据的部分,最后一位的cur同样为零
    *就是说,在刚开始时,最后两个元素的cur都为0

*静态链表应用不广,搜索、清空之类的操作先不写了

一、数据类型

typedef struct Node
{
	int data;
	int cur;
}Node,slist[MAXSIZE];//由于slist[]等价于*slist,故slist是一种数据类型,指向一个结构体数组的头部 

二、初始化

void Initial(slist s)
{
	int i;
	for(i=0;i<=MAXSIZE-3;i++)
	{
		s[i].cur=i+1;
	}
	s[MAXSIZE-2].cur=0;//现在还没使用链表,除了头尾全部为备用链表,其最后一个元素的cur指向0 
	s[MAXSIZE-1].cur=0;//尾节点的cur指向已用链表的头部,现在还没开始使用,也为0 
	s[0].data=0;//已用0个节点 
	s[MAXSIZE-1].data=MAXSIZE-1;//未用MAXSIZE-1个节点 
}

三、插入与删除

  1. 插入:注意,没有指针,就意味着New的功能要自己写
int New(slist s)
{
	int i;
	i=s[0].cur;//i是备用链表第一个元素的下标 
	if(i)//如果i不为0,则将备用链表第二个元素的下标赋给slist[0].cur 
	{
		s[0].cur=s[i].cur;
	}
	return i;//如果i不为零就return i,不然就会return 0,表示已经满了 
}

①插入到尾部

void Insert(slist s,int data)
{
	int i,j;
	i=New(s);
	j=MAXSIZE-1;//不用j=s[MAXSIZE-1].cur的原因是从第一格开始,第一格就可能是0 
	if(i)//如果可以找到空位置 
	{
		s[i].data=data;
		while(s[j].cur)//一直到已用链表的最后一位,这一位的cur为0:注意while里面是s[j].cur而不是j 
		{
			j=s[j].cur; 
		}
		//此时不用s[0].cur=s[i].cur因为New函数里已经搞过了 
		s[j].cur=i;
		s[i].cur=0;
	}
	s[0].data++;
	s[MAXSIZE-1].data--;
}

void Insert(slist s,int data,int position)
{
	int i,j,k;
	i=New(s);
	j=MAXSIZE-1;
	if(i)
	{
		s[i].data=data;
		for(k=1;k<=position-1;k++)//遍历得到想插入位置的前一位置,出来之后,j等于待插入节点的前一个节点的下标(下标不是cur,是数组中的所处位置) 
		{
			j=s[j].cur;
		}
		s[i].cur=s[j].cur;//由于是插入中间,所以把原来在待插入位置的元素的下标赋给新节点 
		s[j].cur=i;
	}
	s[0].data++;
	s[MAXSIZE-1].data--;
}
  1. 删除
int Delete(slist s,int position)
{
	int i,j,k,ret;
	j=MAXSIZE-1;
	for(k=1;k<=position-1;k++)
	{
		j=s[j].cur;
	}
	i=s[j].cur;//待删除结点前一个的下标是j,待删除节点的下标是s[j].cur
	ret=s[i].data;
	s[j].cur=s[i].cur;//画个示意图
	s[i].cur=s[0].cur;
	s[0].cur=i;
	s[0].data--;
	s[MAXSIZE-1].data++;
	return ret; 
}

四、遍历

void Traverse(slist s)
{
	int i;
	i=MAXSIZE-1;
	if(s[i].cur!=0)
	{
		i=s[i].cur;
		while(i)
		{
			cout<<s[i].data<<' ';
			i=s[i].cur;
		}
	} 
	cout<<endl;
}

五、使用

  1. 附上主函数:
int main()
{
	slist s;
	Initial(s);
	int i;
	for(i=0;i<50;i++)
	{
		Insert(s,i);
	}
	Traverse(s);
	Insert(s,114514,10);
	Traverse(s);
	Delete(s,11);
	Traverse(s);
	return 0;
}
  1. 静态链表是比普通链表难,但是核心就是理解静态链表的结构:如何通过cur实现指针的功能,然后利用cur
    还要注意:要自己明确一种结构,网上和教材里可能各有不同的结构,有些让头两位是上述头尾节点,有一些让尾节点也存储数据…
    必须要明确结构,哪怕自己设计一个和网上博客里和教材里都不一样的,只要能实现cur指向下一个节点这个性质,就能实现静态链表
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页