数据结构:静态链表

静态链表是一种使用数组模拟链表结构的数据结构,通过数组元素中的cur字段指示链表节点。它在删除和插入操作时保持低时间复杂度,但需预先分配空间。与动态链表相比,静态链表的物理地址连续,空间固定,而动态链表的内存分配灵活,节点物理地址不连续。文章详细介绍了静态链表的概念、实现原理,并提供了相关代码实现。
摘要由CSDN通过智能技术生成

1、对于没有指针的编程语言,可以用数组替代指针,来描述链表。让数组的每个元素由data和cur两部分组成,其中cur相当于链表的next指针,这种用数组描述的链表叫做静态链表,这种描述方法叫做游标实现法。我们对数组的第一个和最后一个元素做特殊处理,不存数据。让数组的第一个元素cur存放第一个备用元素(未被占用的元素)下标,而数组的最后一个元素cur存放第一个有值的元素下标,相当于头结点作用。

     优点:和动态链表一样,删除和插入元素时间复杂度低

     不足:和数组一样,需要提前分配一块较大的空间

2、实现原理:

(1)、使用结构体数组,结构体有指针域  cur  和数据域  data

(2)、一个数组分量表示一个节点,用cur代替指针指示节点在数组中的相对位置

(3)、数组逻辑上分为两个链表:备用链表(空闲的节点)和数据链表(已被使用的节点)

 

3、静态链表与动态链表的区别:

静态链表和动态链表是线性表链式存储结构的两种不同的表示方式。

1、静态链表是用类似于数组方法实现的,是顺序的存储结构,在物理地址上是连续的,而且需要预先分配地址空间大小。所以静态链表的初始长度一般是固定的,在做插入和删除操作时不需要移动元素,仅需修改指针。

2、动态链表是用内存申请函数(malloc/new)动态申请内存的,所以在链表的长度上没有限制。动态链表因为是动态申请内存的,所以每个节点的物理地址不连续,要通过指针来顺序访问。

4、静态链表的实现:
(1)slist.h:

#pragma once 
 
//静态链表:利用顺序表模拟带头结点的单循环链表
//0下标作为有效链表头 有效链为循环链
//1下标作为空闲链表头 空闲链为循环链
 
typedef struct SNode
{
	int data;
	int next;//后继指针 下一节点的下标
}SNode,*PList;
 
#define SIZE 10
typedef SNode SList[SIZE];
 
//初始化
void InitSList(PList pl);
 
//头插
bool Insert_head(PList pl,int val);
 
//尾插
bool Insert_tail(PList pl,int val);
 
//删除
bool Delete(PList pl,int key);
 
//获取长度(有效链的元素个数)
int GetLength(PList pl);
 
//判空
bool IsEmpty(PList pl);
 
//清空
void Clear(PList pl);
 
//摧毁
int Destroy(PList pl);
 
//打印
void Show(PList pl);

 (2)slist.cpp:

#include <stdio.h>
#include <assert.h>
#include "slist.h"

//初始化
void InitSList(PList pl)
{
	assert(pl != NULL);               //出错处理
	if(pl == NULL)
	{
		return ;
	}
	for(int i = 1;i < SIZE-1;i++)     //空闲链从1号下标开始
	{
		pl[i].next = i+1;             //把数据挂在空闲链上
	}
	pl[0].next = 0;                    //有效链为空
	pl[SIZE  - 1].next = 1;            //最后一个指向空闲链头
}

static bool IsFull(PList pl)
{
	return pl[1].next == 1;            //空闲链没有剩余的节点
}

//头插
bool Insert_head(PList pl,int val)
{
	assert(pl != NULL);
	if(IsFull(pl))
	{
		return false;
	}
	int p = pl[1].next;               //在空闲链中取一个节点
	pl[1].next = pl[p].next;          //从空闲链表中删除
	pl[p].data = val;                 //数据存入新节点中

	//将此节点头插在有效链中
	pl[p].next = pl[0].next;
	pl[0].next = p;

	return true;
}
 
//尾插
bool Insert_tail(PList pl,int val)
{
	assert(pl != NULL);
	if(IsFull(pl))
	{
		return false;
	}
	int p = pl[1].next;               //在空闲链中取一个节点
	pl[1].next = pl[p].next;          //从空闲链表中删除
	pl[p].data = val;                 //数据存入新节点中

	//将此节点尾插在有效链中
	int q;                            //有效链最后一个节点下标
	//查找有效链的最后一个节点 
	for(q = 0;pl[q].next != 0;q = pl[q].next);
	pl[p].next = pl[q].next;          //将新节点插入到有效数据链
	pl[q].next = p;

	return true;
}

//查找前驱
static int SearchPri(PList pl,int key)
{
	for(int p = 0;pl[p].next != 0;p = pl[p].next)
	{
		if(pl[pl[p].next].data == key)
		{
			return p;
		}
	}
	return -1;
}

//删除
bool Delete(PList pl,int key)
{
	int p = SearchPri(pl,key);
	if(p == -1)
	{
		return false;
	}
	int q = pl[p].next;               //需要删除的点
	pl[p].next = pl[q].next;          //将q从有效链中删除

	pl[q].next = pl[1].next;          //将q插入到空闲链中
	pl[1].next = q;

	return true;
}
 
//获取长度(有效链的元素个数)
int GetLength(PList pl)
{
	int count = 0;
	for(int p = 0;pl[p].next != 0;p = pl[p].next)
	{
		count++;
	}
	return count;
}
 
//判空
bool IsEmpty(PList pl)
{
	return pl[0].next == 0;
}
 
//清空
void Clear(PList pl)
{
	Destroy(pl);
}
 
//摧毁
int Destroy(PList pl)
{
	return pl[0].next = 0;
}
 
//打印
void Show(PList pl)
{
	for(int p = pl[0].next;p != 0;p = pl[p].next)
	{
		printf("%d ",pl[p].data);
	}
	printf("\n");
}

(3)main.cpp:

#include <stdio.h>
#include "slist.h"
 
int main()
{
	SList sl;
	InitSList(sl);
	for(int i = 0;i < 10;i++)
	{
		Insert_head(sl,i);
		//Insert_tail(sl,i);
	}
	Show(sl);
 
	//获取长度测试用例
	printf("%d\n",GetLength(sl));
	
	//删除测试用例
	Delete(sl,7);
	Delete(sl,-1);
	Delete(sl,0);
	Delete(sl,10);
	Show(sl);
 
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值