静态链表

逻辑结构上相邻的数据元素,存储在指定的一块内存空间中,数据元素只允许在这块内存空间中随机存放,这样的存储结构生成的链表称为静态链表。

 

静态链表和动态链表的区别:静态链表限制了数据元素存放的位置范围;动态链表是整个内存空间。

 

静态链表的构建方法

静态链表使用数组这一数据类型预先申请足够大的内存空间。

由于各数据元素在数组申请的内存空间内随机存放,为了体现逻辑上的相邻,为每一个数据元素配备一个具有指针作用的整形变量,用于记录下一元素在数组中的位置。

在数组申请的存储空间中,各数据元素虽随机存储,每一个元素都记录着下一元素在数组中的位置,通过前一个元素,可以找到下一个元素,构成了一条链表,这条被局限在特定内存空间的链表就是静态链表。

静态链表中结点的构成

静态链表中每个结点既有自己的数据部分,还需要存储下一个结点的位置,所以静态链表的存储实现使用的是结构体数组,包含两部分: 数据域 和 游标(存放的是下一个结点在数组中的位置下标)。

静态链表的空间重复利用

由于静态链表提前申请了有限的内存空间,在使用的过程中,极有可能会出现申请的内存空间不足,需要使用之前被遗弃的内存空间。

被遗弃的意思是:之前已经使用,但是后期对该结点做了摘除操作,该内存空间中存放的是已经不用的垃圾数据。

所以,在整个过程中,需要自己动手把两者区分开,也就是需要自己实现 malloc 和 free 两个函数的作用。

解决的办法是:提前将所有未被使用的结点链成一个备用链表。需要对链表做插入操作时,从备用链表上摘下一个结点使用;删除链表中的结点时,删除的同时链接到备用链表上,以备下次使用。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#pragma once
#include<vector>
using namespace std;
template<typename T>
class Node {
public:
	Node(){}
	Node(T d, int i) {
		data = d;
		cur = i;
	}
	T data;
	int cur;
};
template<typename T>
class CStaticList
{
public:
	CStaticList(int s);
	~CStaticList();

	bool isEmpty();
	//生请待插入节点 返回待插入节点再数组中的下标
	int Malloc_SLL();
	//插入代码1
	void ListInsert(int i, T data);
	//获取链表长度
	int ListLength();
	//初始化
	int InitArr();
	//查找
	int selectElem(T data);
	//插入代码2
	void insertArr(int i, T data);
	//删除
	void deleteArr(T data);
	//放入备用节点
	void freeArr(int del);
private:
	int MAX_SIZE;
	int m_lenght = 0;
	vector<Node<T>> m_list;
};

template<typename T>
CStaticList<T>::CStaticList(int s) :MAX_SIZE(s)
{
	m_list.resize(MAX_SIZE);//分配空间
	int i;
	for (i = 0; i < MAX_SIZE; i++) {
		m_list[i].cur = i + 1;
	}//初始化为备用链表
	//MAXsize - 1的位置 存放第一个有数值元素的下标 相当于链表的头节点作用
	m_list[MAX_SIZE - 1].cur = 0;//当此位置的cur为0时相当于空表
}
template<typename T>
CStaticList<T>::~CStaticList()
{
}
template<typename T>
bool CStaticList<T>::isEmpty()
{
	return false;
}
/*若备用链表非空,返回分配的结点的下标,否则返回0*/
template<typename T>
int CStaticList<T>::Malloc_SLL()
{
	int i = m_list[0].cur;  /*返回备用链表的第一个结点的下标*/
	if (m_list[0].cur)
		m_list[0].cur = m_list[i].cur;  /*由于使用了一个元素,我们将它的后继链接元素作为备用链表的头*/
	return i;
}
//插入
template<typename T>
inline void CStaticList<T>::ListInsert(int i, T data)
{
	if (i < 1|| i > m_list.size()-1)return;//小标越界返回
	int j, k, l;
	k = m_list[1].cur;  /*获取数组最后一个位置下标*/
	j = Malloc_SLL();  /*获取备用链表第一个位置的下标*/
	if (j) {
		m_list[j].data = data;
		for (l = 1; l < i - 1; l++)
			k = m_list[k].cur;  /*获取第i个元素之前位置的下标*/
			m_list[j].cur = m_list[k].cur;
		m_list[k].cur = j;  /*cur值之间的重新链接*/
	}
}
/* 返回m_list中有数据元素链表的个数 */
template<typename T>
inline int CStaticList<T>::ListLength()
{
	int j = 0;
	int i = m_list[1].cur;
	while (i)
	{
		i = m_list[i].cur;
		j++;
	}
	return j;
}

template<typename T>
inline int CStaticList<T>::InitArr()
{
	//从备用链表中拿出一个分量作为链表头结点,返回的是这个分量的下标
	int body = Malloc_SLL();
	//声明一个变量,把它当指针使,指向链表的最后的一个结点,因为链表为空,所以和头结点重合
	int tempBody = body;
	for (int i = 1; i < 5; i++)
	{
		int j = Malloc_SLL();			//从备用链表中拿出空闲的分量
		m_list[tempBody].cur = j;		//将申请的空线分量链接在链表的最后一个结点后面
		m_list[j].data = 'a' + i - 1;	//给新申请的分量的数据域初始化
		tempBody = j;					//将指向链表最后一个结点的指针后移
	}
	m_list[tempBody].cur = 0;			//新的链表最后一个结点的指针设置为0
	return body;
}

template<typename T>
inline int CStaticList<T>::selectElem(T data)
{
	int i = m_list[1].cur;
	while (m_list[i].cur!=0)
	{
		if (m_list[i].data == data) {
			return i;
		}
		i = m_list[i].cur;
	}
	if (m_list[i].data == data) {
		return i;
	}
	return -1;
}

template<typename T>
inline void CStaticList<T>::insertArr(int add, T data)
{
	int tempBody = m_list[1].cur;		//tempBody做遍历结构体数组使用
  //找到要插入位置的上一个结点在数组中的位置
	for (int i = 1; i < add-1; i++)
	{
		tempBody = m_list[tempBody].cur;
	}
	int insert = Malloc_SLL();	//申请空间,准备插入
	m_list[insert].cur = m_list[tempBody].cur;	//首先要插入结点的游标等于要插入位置的上一个结点的游标
	m_list[insert].data = data;
	m_list[tempBody].cur = insert;	//然后让上一结点的游标等于插入结点所在数组中的位置的下标
}

template<typename T>
inline void CStaticList<T>::deleteArr(T data)
{
	int del = selectElem(data);
	if(del<0){//表示未找到
		return;
	}
	int tempBody = m_list[1].cur;
	//找到该结点的上一个结点,做删除操作
	while (m_list[tempBody].cur != del)
	{
		tempBody = m_list[tempBody].cur;
	}
	//将被删除结点的游标直接给被删除结点的上一个结点
	m_list[tempBody].cur = m_list[del].cur;
	freeArr(del);
}

template<typename T>
inline void CStaticList<T>::freeArr(int k)
{
	m_list[k].cur = m_list[0].cur;
	m_list[0].cur = k;
}





 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
静态链表是一种使用数组实现的链表结构,它通过数组中的元素来模拟链表中的节点,并使用一个特殊的指针(游标)来表示节点之间的逻辑关系。静态链表的优点是实现简单,不需要频繁地申请和释放内存空间,但缺点是插入和删除操作比较麻烦,需要手动维护游标指针。 以下是一个简单的Python静态链表的实现示例[^1]: ```python class StaticLinkedList: def __init__(self, size): self.data = [None] * size # 存储数据的数组 self.next = [i + 1 for i in range(size)] # 游标数组,用于维护节点之间的逻辑关系 self.next[-1] = -1 # 最后一个元素的游标为-1,表示链表的末尾 self.head = -1 # 头指针,指向链表的第一个节点 def is_empty(self): return self.head == -1 def is_full(self): return self.next == -1 def insert(self, value): if self.is_full(): print("StaticLinkedList is full") return new_node = self.next # 获取一个空闲节点 self.next = self.next[new_node] # 更新空闲节点的游标 self.data[new_node] = value # 在空闲节点中存储数据 if self.is_empty(): self.head = new_node self.next[new_node] = -1 else: current = self.head while self.next[current] != -1: current = self.next[current] self.next[current] = new_node self.next[new_node] = -1 def delete(self, value): if self.is_empty(): print("StaticLinkedList is empty") return prev = -1 current = self.head while current != -1: if self.data[current] == value: break prev = current current = self.next[current] if current == -1: print("Value not found") return if prev == -1: self.head = self.next[current] else: self.next[prev] = self.next[current] self.next[current] = self.next # 将删除的节点加入空闲节点链表 self.next = current def display(self): if self.is_empty(): print("StaticLinkedList is empty") return current = self.head while current != -1: print(self.data[current], end=" ") current = self.next[current] print() # 创建一个容量为5的静态链表 static_list = StaticLinkedList(5) # 插入数据 static_list.insert(1) static_list.insert(2) static_list.insert(3) # 删除数据 static_list.delete(2) # 显示链表中的数据 static_list.display() ``` 输出结果为: ``` 1 3 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值