【数据结构与算法】不带头节点静态链表的插入和删除算法

题目:

        Question:写一个不带头节点静态链表插入删除算法。


主要思路

        链表的特性:

  •         由于静态链表的存储结构是由数组实现的,但由于与顺序表不同,其并不是按顺序存储的,而是按照游标的顺序来存储的,也就是说假设静态链表的第一个元素存储在 A[1] 中,那么链表第二个元素就可能不是 A[2] ,而是根据 A[1] 的游标域来决定下一个元素在何处,若 A[1] 的游标域的数值为4,则下一个元素为 A[4] 。
  •         静态链表有两个链,一个用于存放数据,在这里称作链表;另一个用于存放空数组,也就是备用链表,用于需要插入新的数据进静态链表中时,就调用备用链表中的节点,完成赋值操作后接到链表之后。

        该题的特殊之处:

        该静态链表为不带头节点的静态链表。一般来说静态链表会有两个头节点,因为有两个链表(链表和备用链表)。其中第一个节点为备用链表的头节点、最后一个节点为链表的头节点。(如下图所示)。因此我们采用双指针的思想,设p、q分别指向备用链表和链表的第一个元素,由于一开始链表为空,整个数组为备用链表,故p = 0; q = -1; (q 为 -1 表示链表不存在)。

带头节点的静态链表

 代码:

        定义的部分:

        一些基础的操作:

 

        插入和删除操作:

        (由于在调用删除和插入函数时链表不能为空,故使用之前必须的要运行基础操作中的InsertFirstData函数)。

        完整代码(可运行):

#include <stdio.h>
#define MAXSIZE 100

typedef struct
{
	int data;
	int cur;
}node;

node LinkList [MAXSIZE];

//备用链表第一个首元节点的下标 
int p = 0;
//链表的一个首元节点的下标,若链表为空则q为-1 
int q = -1;

//将下标为K的空闲节点回收到备用链表
void Free(int k)
{
	LinkList[k].cur = LinkList[p].cur;
	LinkList[p].cur = k;
} 
//初始化 
void Init()
{
	unsigned short i;
	for(i = 0; i < MAXSIZE - 1; i++) LinkList[i].cur = i + 1;
	LinkList[MAXSIZE - 1].cur = -1; 
}
//插入第一个元素,值为i 
void InsertFirstData(int i)
{
	q = p;
    LinkList[q].data = i;
    p = LinkList[p].cur;
    LinkList[q].cur = -1;
}

//返回LinkList中数据元素个数
int ListLength()
{
	int cacu = 0;//记录元素个数 
	int q1 = q;
	if(q1 == -1) return 0;
	while(q1 != -1)
	{
		q1 = LinkList[q1].cur; 
		cacu ++;
	}
	return cacu; 
}

//求前驱元素 cur_e是当前数据值,m返回为其前驱元素下标 
int PriorElem(int cur_e, int m)
{ 
  int j, i = q; //i指示链表第一个结点的位置
  do  //向后移动结点
  { j = i; //j指向i所指元素
    i = LinkList[i].cur; //i指向下一个元素
  }while(i && cur_e!=LinkList[i].data); //i所指元素存在且其值不是cur_e,继续循环
  if(LinkList[i].data == cur_e) //找到该元素
  { 
    m = j;
	return m; //j是i所指元素的前驱元素的下标,赋给m
  }
}

//在第i个元素前插入元素e 
void SLinkInsert(int i, int e){
	if(i < 1||i > ListLength()) return;
    int m = -1;//前驱元素返回的数组下标
	if(i > 1)
	{
        int q1 = q;
		for(int k = 1; k < i; k++)
		{ 
			q1 = LinkList[q1].cur;
			int cur_e = LinkList[q1].data;
			m = PriorElem(cur_e, m);
		} 
		int n = p; //临时指针
		LinkList[p].data = e;
		LinkList[m].cur = p;
		p = LinkList[n].cur;
		LinkList[n].cur = q1;
		return;
	}
    if(i = 1)
    {
    	int k = q; //临时指针
		q = p;
		p = LinkList[p].cur;
		LinkList[q].cur = k;
		LinkList[q].data = e; 
	}
	return;
}
//删除第i个元素 
void SLinkListDelet(int i)
{
	if(i < 1||i > ListLength()) return;
    int m = -1;//前驱元素返回的数组下标
	if(i > 1)
	{
	    int q1 = q;
		for(int k = 1; k < i; k++)
		{
			q1 = LinkList[q1].cur;
			int cur_e = LinkList[q1].data;
			m = PriorElem(cur_e, m);
		}
		LinkList[m].cur = LinkList[q1].cur;
		Free(q1);
		return;
	}
	if(i = 1)
	{
		int k = q;//临时指针
		q = LinkList[q].cur;
		Free(k);
		return; 
	}

}



int main(){
	Init();//初始化 
	InsertFirstData(1);//插入之前需要链表中有至少一个元素 (1)
	SLinkInsert(1, 0);//在第一个元素之前插入0 输出:0 -> 1 
	SLinkInsert(2, 2);//在第二个元素之前插入2 输出:0 -> 2 -> 1 
	SLinkListDelet(2);//删除第二个元素 输出:0 -> 1 
	printf("链表长度为%d\n",ListLength());
	int k = q;//临时指针 
    for(int i = 1; i <= ListLength(); i++){
        printf("第%d个数据是%d\t",i,LinkList[k].data);
        k = LinkList[k].cur;
    }
	return 0;
}

         一些图解:

图解(画的有点丑)


结束语

        因为是算法小菜,所以提供的方法和思路可能不是很好,请多多包涵~如果有疑问欢迎大家留言讨论,你如果觉得这篇文章对你有帮助可以给我一个免费的赞吗?我们之间的交流是我最大的动力!

猜你喜欢

转载自blog.csdn.net/Zchengjisihan/article/details/129964755
今日推荐