【链表】静态链表的基础操作

静态链表是用顺序表模拟链表(数据存放在数组中),在内存池中有应用,防止内存碎片化。

静态链表内部有两条循环链,其中0号下标位置为有效链表的头节点,初始化0下标的next为0;1号下标位置为空闲链表的头节点(无效链)。

0和1号下标为头节点,不存数据,所以长度为n的静态链表只能装n-2个数据。

静态链表的优点:

与顺序表相比,它的数据删除和插入不需要移动数据,只用改变后继指针的指向。

与链表相比,它使数据在一定的内存中存储,不会浪费内存。

静态链表的结构:

#define MAXSIZE 10
typedef struct SNode
{
	int data;//数据
	int next;//后继指针(游标)
}SNode, SLinkList[MAXSIZE];
//定义SLinkList s;中s是长度为MAXSIZE结构体数组

初始化

 

 上图为长度为5的静态链表初始化的样子

void InitList(SLinkList ps)
{
	assert(ps != NULL);
	if (ps == NULL)
	{
		return;
	}
	//处理有效链表
	ps[0].next = 0;
	for (int i = 1; i < MAXSIZE; i++)//处理无效链表
	{
		ps[i].next = i + 1;
		if (i == MAXSIZE - 1)
		{
			ps[i].next = 1;
		}
	}
}

判空与判满

//判满
static bool IsFull(SLinkList ps)
{
	return ps[1].next == 1;//无效链表只有头,没有剩余的未存数据空间
}

//判空
bool IsEmpty(SNode* ps)
{
	return ps[0].next == 0;
}

插入

头插

bool  Insert_head(SLinkList ps, int val)
{
	assert(ps != NULL);
	if (ps == NULL)
	{
		return false;
	}
	if (IsFull(ps))
	{
		return false;
	}
	//取一个空闲节点(的下标)
	int p = ps[1].next;
	//将空闲节点从空闲链表中踢出
	ps[1].next = ps[p].next;
	//放数据
	ps[p].data = val;
	//插入到有效链里
	ps[p].next = ps[0].next;
	ps[0].next = p;
	return true;
}

尾插

bool Insert_tail(SNode* ps, int val)
{
	assert(ps != NULL);
	if (ps == NULL)
		return false;
	if (IsFull(ps))
		return false;
	//找空闲节点
	int p = ps[1].next;
	//从空闲链删除
	ps[1].next = ps[p].next;
	//赋值
	ps[p].data = val;
	int i = 0;
	//找尾
	while(ps[i].next != 0)
	{
		i = ps[i].next;
	}
	//连前面
	ps[i].next = p;
	//后继连到头
	ps[p].next = 0;
	return true;
}


头插时间复杂度O(1);
尾插时间复杂度O(n);

获取数据结点的个数

int GetLength(SNode* ps)
{
	assert(ps != NULL);
	if (ps == NULL)
		return -1;

	int count = 0;
	int i = ps[0].next;//初始化成第一个数据节点,不是头!
	while (i != 0)
	{
		i = ps[i].next;
		count++;
	}
	return count ;
}

获取val的前驱

若不存在则返回-1

static int GetPrio(SNode* ps, int val)
{
	for (int i = 0; ps[i].next != 0; i = ps[i].next)
	{
		int q = ps[i].next;
		if (ps[q].data == val)
		{
			return i;
		}
	}
	return -1;
}

查找

在ps查找第一个key值,找到返回结点地址下标,没有找到返回-1;

int Search(SNode* ps, int key)
{
	assert(ps != NULL);
	if (ps == NULL)
	{
		return -1;
	}
	if (IsEmpty(ps))
		return -1;
	for (int i = ps[0].next; i != 0; i = ps[i].next)
	{
		if (ps[i].data == key)
			return i;
	}
	return -1;
}

删除第一个val

bool DelVal(SNode* ps, int val)
{
	assert(ps != NULL);
	if (ps == NULL)
		return false;
	if(IsEmpty(ps))
		return false;
	
	int i = GetPrio(ps, val);
	if (i < 0)
		return false;

	int d = ps[i].next;
	//将空闲节点从空闲链表中踢出
	ps[i].next = ps[d].next;
	//插入到有效链里
	ps[d].next = ps[1].next;
	ps[1].next = d;
	return true;
}

输出

void  Show(SLinkList ps)
{
	assert(ps != NULL);
	if (ps == NULL)
	{
		return;
	}
	for (int i = ps[0].next; i != 0; i = ps[i].next)
	{
		printf("%d ", ps[i].data);
	}
	printf("\n");
}

清空与销毁

清空:(数据不要了)清空数据
销毁:(内存不要了)"销毁"整个内存,没有malloc所以没有free,可直接调用Clear()

  //清空
void Clear(SNode* ps)
{
	InitList(ps);
}
//销毁
void Destroy(SNode* ps)
{
	Clear(ps);
}


 

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
静态链表是一种使用数组实现的链表结构。它通过数组中的元素自身的指针来实现链表的连接关系。以下是静态链表的基本操作: 1. 初始化:创建一个包含足够多元素的数组,每个元素包含两个字段,一个用于存储数据,另一个用于存储指向下一个元素的索引。初始化时,设置数组中所有元素的指针字段为-1,表示链表为空。 2. 插入:插入操作将新元素插入到静态链表中的指定位置。首先找到一个空闲位置并将新元素插入其中,然后将前一个元素的指针字段指向新元素,在将新元素的指针字段指向原来位置的后继元素。 3. 删除:删除操作静态链表中指定位置的元素移除。首先将要删除的元素的前一个元素的指针字段指向要删除元素的后继元素,然后将要删除元素所在位置设置为空闲。 4. 查找:查找操作可以根据给定的关键字或索引在静态链表中找到对应的元素。可以通过遍历整个链表,逐个比较每个节点中存储的值与给定关键字或索引进行匹配。 5. 更新:更新操作用于修改静态链表中指定位置元素的值。首先找到要更新的元素位置,然后将其值进行修改。 需要注意的是,静态链表的插入和删除操作可能需要额外的空间来存储空闲位置的索引信息,以便快速找到可用位置。另外,由于静态链表使用数组实现,插入和删除操作可能会涉及元素的移动,因此效率较低,适用于对数据的频繁查找而不是插入和删除的场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曦樂~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值