顺序表改进及算法实现

在数据结构中,有一种逻辑结构是线性结构,常用的存储结构便是顺序存储结构和链式存储结构,对应的名称便是顺序表和链表。这两种数据结构在操作系统内核中的应用是非常多的,比如内存管理中的动态分区分配策略,就是使用顺序表,Linux系统内核也有内核链表。
顺序表简介
可以通俗理解,顺序表就是数组,支持随机存取(随便访问哪个地方都可以,但有越界访问的风险)以及下标访问,对于数据结构中几乎所有的结构来说,我们的通常操作便是增、删、改、查,顺序表也不例外。但是在增加元素以及删除元素的时候,顺序表有个极其致命的缺点,那就是需要进行数据的移动,想象一下,把一个顺序表看作是一列火车,若火车的某一节车厢要换,那应该把这节车厢先去掉,然后把后面所有的车厢往前移动一格才能保持整列火车的连续性,当车厢数量较多的时候,移动起来就比较费劲了,需要对删除插入操作进行改进。
示意图如下:

改进方法
将每个数据都做一个标记,有效数据标记为True,脏数据(即已被删除的数据)标记为False,删除就只对删除的数据的标记做更改,当一节车厢要被替换的时候,就将它标记一下,不使用它,当有新的车厢到来也就是有数据要进行插入时,就可以用新车厢代替旧车厢,只需更改数据和标志位即可,不涉及到别的元素的运动,插入删除的整体效率便会提高。使用两个整形变量分别记录数据总个数、脏数据个数,当脏数据太多时(两者比值大于某个设定值),我们可以将整个顺序表进行内存整理,类似于OS中可变分区分配的紧凑技术。
示意图如下:
删除:
在这里插入图片描述
新增数据:
在这里插入图片描述
接下来看代码实现
头文件及结构体定义


#include<iostream>
#include<Windows.h>
#define MAXSIZE 1024
using namespace std;
typedef struct Sq {
	int data;
	bool flag;
}sq;
typedef struct SqList {
	sq* elems;
	int Trnum;//当前有效个数
	int Fanum;//已被删除个数
}SL;

初始化

void init_SqList(SL*&s)
{
	s = new SL;
	s->elems = new sq[MAXSIZE];
	if (!s->elems)
	{
		fprintf(stderr, "分配内存失败!\n");
		exit(1);
	}
	s->Trnum = 0;
	s->Fanum = 0;
}

**添加元素 **

//添加元素 末尾添加 默认插入方法 
void Add_elems(SL*& s, int data)
{
	if ((s->Fanum + s->Trnum) == MAXSIZE)
	{
		fprintf(stderr, "内存空间已满!\n");
		return;
	}
	s->elems[s->Fanum + s->Trnum].data = data;
	s->elems[s->Fanum + s->Trnum].flag = true;
	s->Trnum++;
}

覆盖第一个已删除元素或者最末尾添加

void insert(SL*&s,int data) 
{
	if ((s->Trnum+s->Fanum)==MAXSIZE)
	{
		fprintf(stderr, "内存空间已满!\n");
		return;
	}
	int i = 1;
	while (i<MAXSIZE)
	{
		if (i>(s->Fanum+s->Trnum))
		{
			
			break;
		}
		else if (!s->elems[i-1].flag)
		{
			s->Fanum--;
			break;
		}
		i++;
	}
	s->elems[i - 1].flag = true;
	s->elems[i - 1].data = data;
	s->Trnum++;
}

指定位置插入 插入到第loca个位置

void Loca_insert(SL*&s,int data,int loca)
{
	if ((s->Fanum+s->Trnum)==MAXSIZE)
	{
		fprintf(stderr, "内存空间已满!\n");
		return;
	}
	if ((loca<=0)||(loca>(s->Fanum+s->Trnum)))
	{
		fprintf(stderr, "插入位置不合法!\n");
		return;
	}
	if (!s->elems[loca-1].flag)//插入位置恰好是已被标记删除
	{
		s->elems[loca - 1].data = data;
		s->elems[loca - 1].flag = true;
		s->Fanum--;
		s->Trnum++;
	}
	else//普通插入情况 即在所有节点数范围内插入 不支持在这范围之外添加
	{
		for (int i = (s->Fanum+s->Trnum); i >=loca; i--)
		{
			s->elems[i].data = s->elems[i - 1].data;
			s->elems[i].flag = s->elems[i - 1].flag;
		}
		s->elems[loca - 1].data = data;
		s->elems[loca - 1].flag = true;
		s->Trnum++;
	}
}

默认删除 删除第一个值为data的 只通过改变标记来实现删除

void Delete_One(SL*&s,int data)
{
	if (!s->Trnum)
	{
		fprintf(stderr, "可删除节点数为0!\n");
		return;
	}
	for (int i = 0; i < (s->Fanum+s->Trnum); i++)
	{
		if (s->elems[i].data==data)
		{
			s->elems[i].flag = false;
			s->Fanum++;
			s->Trnum--;
			break;
		}
	}
}

默认删除 删除所有值为data的 只通过改变标记来实现删除

void Delete_ALL(SL*& s, int data)
{
	if (!s->Trnum)
	{
		fprintf(stderr, "可删除节点数为0!\n");
		return;
	}
	for (int i = 0; i < (s->Fanum + s->Trnum); i++)
	{
		if (s->elems[i].data == data)
		{
			s->elems[i].flag = false;
			s->Fanum++;
			s->Trnum--;
		}
	}
}

删除指定位置的元素 只通过改变标记来实现删除

void Delete_loca(SL*&s,int loca)
{
	if (!s->Trnum)
	{
		fprintf(stderr, "可删除节点数为0!\n");
		return;
	}
	s->Trnum -= s->elems[loca - 1].flag ? 1 : 0;
	s->Fanum += s->elems[loca - 1].flag ? 1 : 0;
	s->elems[loca - 1].flag = false;
}

内存整理 将所有已删除节点进行覆盖并改变已删除节点数大小

void Tidying_up(SL*&s) 
{
	if (!s->Trnum)
	{
		fprintf(stderr, "可删除节点数为0!\n");
		return;
	}
	int n = 0;
	for (int i = 0; i < (s->Fanum+s->Trnum); i++)
	{
		if (!s->elems[i].flag)//计第i个元素之前的已标记删除的数的个数
		{
			n++;
		}
		else //将有效元素进行移动
		{
			s->elems[i - n].data = s->elems[i].data;
			s->elems[i - n].flag = true;
		}
	}
	s->Fanum = 0;
}

重载输出运算符

ostream&operator << (ostream&os,const SL&s)
{
	os << "总数据量为:" << s.Fanum + s.Trnum << endl << "有效数据个数:" << s.Trnum << '\t' << "脏数据个数:" << s.Fanum << '\t' << endl;;
	string A;
	for (int i = 0; i < (s.Fanum+s.Trnum); i++)
	{
		A = s.elems[i].flag ? "有效数据" : "脏数据";
		os << s.elems[i].data << "\t标记:" << A<<'\n';
		
	}
	os << endl;
	return os;
}

完整代码

#include<iostream>
#include<Windows.h>
#define MAXSIZE 1024
using namespace std;
typedef struct Sq {
	int data;
	bool flag;
}sq;
typedef struct SqList {
	sq* elems;
	int Trnum;//当前有效个数
	int Fanum;//已被删除个数
}SL;
//初始化
void init_SqList(SL*&s)
{
	s = new SL;
	s->elems = new sq[MAXSIZE];
	if (!s->elems)
	{
		fprintf(stderr, "分配内存失败!\n");
		exit(1);
	}
	s->Trnum = 0;
	s->Fanum = 0;
}
//添加元素 末尾添加 默认插入方法 
void Add_elems(SL*& s, int data)
{
	if ((s->Fanum + s->Trnum) == MAXSIZE)
	{
		fprintf(stderr, "内存空间已满!\n");
		return;
	}
	s->elems[s->Fanum + s->Trnum].data = data;
	s->elems[s->Fanum + s->Trnum].flag = true;
	s->Trnum++;
}
//覆盖第一个已删除元素或者最末尾添加
void insert(SL*&s,int data) 
{
	if ((s->Trnum+s->Fanum)==MAXSIZE)
	{
		fprintf(stderr, "内存空间已满!\n");
		return;
	}
	int i = 1;
	while (i<MAXSIZE)
	{
		if (i>(s->Fanum+s->Trnum))
		{
			
			break;
		}
		else if (!s->elems[i-1].flag)
		{
			s->Fanum--;
			break;
		}
		i++;
	}
	s->elems[i - 1].flag = true;
	s->elems[i - 1].data = data;
	s->Trnum++;
}
//指定位置插入 插入到第loca个位置
void Loca_insert(SL*&s,int data,int loca)
{
	if ((s->Fanum+s->Trnum)==MAXSIZE)
	{
		fprintf(stderr, "内存空间已满!\n");
		return;
	}
	if ((loca<=0)||(loca>(s->Fanum+s->Trnum)))
	{
		fprintf(stderr, "插入位置不合法!\n");
		return;
	}
	if (!s->elems[loca-1].flag)//插入位置恰好是已被标记删除
	{
		s->elems[loca - 1].data = data;
		s->elems[loca - 1].flag = true;
		s->Fanum--;
		s->Trnum++;
	}
	else//普通插入情况 即在所有节点数范围内插入 不支持在这范围之外添加
	{
		for (int i = (s->Fanum+s->Trnum); i >=loca; i--)
		{
			s->elems[i].data = s->elems[i - 1].data;
			s->elems[i].flag = s->elems[i - 1].flag;
		}
		s->elems[loca - 1].data = data;
		s->elems[loca - 1].flag = true;
		s->Trnum++;
	}
}
//默认删除 删除第一个值为data的 只通过改变标记来实现删除
void Delete_One(SL*&s,int data)
{
	if (!s->Trnum)
	{
		fprintf(stderr, "可删除节点数为0!\n");
		return;
	}
	for (int i = 0; i < (s->Fanum+s->Trnum); i++)
	{
		if (s->elems[i].data==data)
		{
			s->elems[i].flag = false;
			s->Fanum++;
			s->Trnum--;
			break;
		}
	}
}
//默认删除 删除所有值为data的 只通过改变标记来实现删除
void Delete_ALL(SL*& s, int data)
{
	if (!s->Trnum)
	{
		fprintf(stderr, "可删除节点数为0!\n");
		return;
	}
	for (int i = 0; i < (s->Fanum + s->Trnum); i++)
	{
		if (s->elems[i].data == data)
		{
			s->elems[i].flag = false;
			s->Fanum++;
			s->Trnum--;
		}
	}
}
//删除指定位置的元素 只通过改变标记来实现删除
void Delete_loca(SL*&s,int loca)
{
	if (!s->Trnum)
	{
		fprintf(stderr, "可删除节点数为0!\n");
		return;
	}
	s->Trnum -= s->elems[loca - 1].flag ? 1 : 0;
	s->Fanum += s->elems[loca - 1].flag ? 1 : 0;
	s->elems[loca - 1].flag = false;
}
//内存整理 将所有已删除节点进行覆盖并改变已删除节点数大小
void Tidying_up(SL*&s) 
{
	if (!s->Trnum)
	{
		fprintf(stderr, "可删除节点数为0!\n");
		return;
	}
	int n = 0;
	for (int i = 0; i < (s->Fanum+s->Trnum); i++)
	{
		if (!s->elems[i].flag)//计第i个元素之前的已标记删除的数的个数
		{
			n++;
		}
		else //将有效元素进行移动
		{
			s->elems[i - n].data = s->elems[i].data;
			s->elems[i - n].flag = true;
		}
	}
	s->Fanum = 0;
}
ostream&operator << (ostream&os,const SL&s)
{
	os << "总数据量为:" << s.Fanum + s.Trnum << endl << "有效数据个数:" << s.Trnum << '\t' << "脏数据个数:" << s.Fanum << '\t' << endl;;
	string A;
	for (int i = 0; i < (s.Fanum+s.Trnum); i++)
	{
		A = s.elems[i].flag ? "有效数据" : "脏数据";
		os << s.elems[i].data << "\t标记:" << A<<'\n';
		
	}
	os << endl;
	return os;
}
int main(void) {
	int data[] = { 50,98,96,43,56,87,82,30,12,25,45,44,46 };
	int len = sizeof(data) / sizeof(data[0]);
	SL* s = nullptr;
	init_SqList(s);
	for (int i = 0; i < len; i++)
	{
		Add_elems(s, data[i]);
	}
	cout << *s;
	Loca_insert(s, 1024, 5);
	cout << *s;
	Delete_One(s, 50);
	cout << *s;
	insert(s, 66);
	cout << *s;
	Delete_loca(s, 9);
	cout << *s;
	for (int i = 1; i < 4; i++)
	{
		Loca_insert(s, 566, i * i);
	}
	cout << *s;
	Delete_ALL(s, 566);
	cout << *s;
	Tidying_up(s);
	cout << *s;
	delete[]s->elems;
	delete s;
	system("pause");
	return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱你是长久之计~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值