大话数据结构(三)线性表相关概念——(顺序线性表插入和删除等)

话不多说,我们这一部分的主要重点是线性表的相关概念的总结和回顾。

线性表主要有两种存储结构,一是顺序存储结构,二是链式存储结构。当然这两种结构各有各的优点。接下来我们就慢慢开始回顾。首先我们开始顺序存储结构的介绍。

线性表的顺序存储结构

顺序存储结构,指的是用一段连续的地址的存储单元一次存储数据元素。直白点说就是在一个班级里边,每个学生都有自己的学号,这个学号一般是从****0001开始,按着0001,0002,0003····00XX这个顺序依次往下递增的,每个同学不仅知道自己的学号ID,而且一般都知道自己前一个ID的同学名字和后一个ID的同学名字(毕竟看了学生名单这么多次,要是不记得那可真是塑料同学情了,汗!)。OK,为了直观的感受线性表(ID1,ID2,ID3·····IDn)的顺序存储结构,我们来看以下这个示意图:

每个数据元素都得老老实实呆在自己的小房间(内存空间)里边,不能和其他的数据元素发生感情,也不能寻衅滋事。那么这个时候问题就来了,线性表中的数据元素一定要是一种数据类型。比如你在图书馆高峰期的时候看书看到一半突然肚子剧痛,你要是把你的包放在桌子上占座的话,等你再回来的时候,你的座位可能早就已经换主了吧,毕竟其他同学也要考前"突击"一下不是,遇到脾气暴躁的同学还免不得和你争辩一番:包怎么能代替人占座呢?

所以既然线性表中的数据元素都是同一个类型,那么我们很自然的可以想到,C语言老师不是说过数组就是用于储存多个相同类型数据的集合吗,并且数组也是有序的元素序列。是的,我们一般都用数组来实现线性表的顺序存储结构,并且数组名称就是指针指向的第一个数组元素,我们将它的下标设置为0,这样其他数据元素按着依次递增的顺序往下顺延。

我们假设图书馆就是一个很大的内存空间,它可以容纳上千个同学同时学习(即保证每个在图书馆学习的同学都有自己的座位),但是对于期末考试前的"高峰期',图书馆的座位可能就不够用了。这种情况类比于线性表来说也是一样的,线性表的顺序存储结构长度不能超过我们事先规定的存储容量,不然就会有数据"溢出"的风险。同样的,对于刚开学或者寒暑假的时候,这时是图书馆的"淡季",图书馆内的同学很少,但是图书馆依然面向同学开放,图书馆的电脑和台灯依然在工作,这种时候就会存在资源浪费的问题,类比于数组来说也是一样的,如果我们数组定义得够大,但是我们需要"安排"的数组元素缺较少,这个时候就会占用内存空间,引起不必要的资源浪费。

那么我们现在来定义一下线性表吧,代码如下:

#define MAXSIZE 100//宏定义一个最大数组长度,假设为100
typedef int type;//假设设定一个int类型的数组
typedef struct
{
	type a[MAXSIZE];//数组
	type length;//线性表长度
}SqList;

值得注意的一点是,线性表的长度应该小于等于数组的长度,另外数组元素的下标是从0开始的,这个大家应该都知道。

关于顺序存储结构的插入和删除操作

首先我们需要编写一个函数,返回我们想要的数组中的某一个下标的元素。

#define ERROR 0
#defien OK 1
int GetElem(SqList L,int i,int *e)
{
	if(i < 1 || L.length == 0 || i > L.length)
		return ERROR;
	*e = L.a[i-1];
	return OK;
}

注意*e = L.a[i-1],而不是*e = L.a[i],因为下标是从0开始的。

好了,现在我们来编写顺序存储结构的插入操作,在编写之前我们需要知道五个点:

1.如果插入位置不合理,抛出异常;

2.如果在插入的时候线性表长度超过了数组长度,需要抛出异常或者动态增加数组长度;

3.在插入的数组元素下标之后的元素下标都需要+1;

4.将要插入的元素填入想要填入的位置i处;

5.表长需要+1.

在知道这五个点之后,我们实现代码如下:

int ListInsert(SqList L,int i,int e)
{
	int k;//为for循环作准备
	if(L.length == MAXSIZE || i < 1 || i > L.length)//判断是否异常
		return ERROR;
	if(i <= L.length)
	{
		for(k = L.length - 1;k >= i - 1;k--)//位置i之后的元素向后移动一位
		{
			L.a[k+1] = L.a[k];
		}
		L.a[i - 1] = e;//将元素插入
		L.length++;
		return OK;
	}
}

注意,在实现for循环的时候,我们不能将for(k = L.length - 1;k >= i - 1;k--)写成for(k = i - 1;k<= L.length -1;k++),这样i位置之后的数据元素都将是i下标的元素。应该从后往前进行循环,即从后向前遍历。

那么相同的,我们开始编写删除操作,同意在编写进行删除操作的代码之前,我们也需要厘清我们的思路

1.如果删除位置不合理,抛出异常;

2.取出删除元素;

3.从删除元素位置到最后一个元素,分别将它们都向前移动一个位置

4.表长+1.

在有了插入操作的基础上,删除操作得代码也很容易实现,代码实现如下:

int ListDelete(SqList L,int i,int e)
{
	int k;//为for循环作准备
	if(L.length == 0 || i < 1 || i > L.length)//判断是否异常
		return ERROR;
	if(i < L.length)
	{
		e = L.a[i-1];//将要删除的元素赋值给e
		for(k = i;k = L.length;k++)//下标i之后的元素向后移动一位
		{
			L.a[k-1] = L.a[k];
		}
		L.length--;
		return OK;
	}
}

注意,同样在实现for循环的时候,我们也不能将for(k = i;k = L.length;k++)写成for(k = L.length;k >= i;k--)。需要从前向后遍历

ok,代码写完了,照例我们限制来分析一下插入和删除操作的时间复杂度,当然最好的情况是插入到表最后一个元素,或者删除第一个元素,这样时间复杂度就为O(1),而最坏的情况呢,当然就需要移动n-i个元素,那么时间复杂度就是O(n),

现在我们来总结一下线性表的顺序存储结构的优缺点:

优点

缺点

无须描述表中元素的逻辑关系

插入和删除需要大量操作

可以快速存取表中任意位置的元素

不能很好地确定存储空间的容量

好了,线性表的顺序存储结构我们就介绍完了,经过总结我们可以看到,顺序存储结构的缺点是很明显的,最大的缺点是它的插入和删除操作在平均的情况下都需要移动大量的元素,下一部分开始讲解的链式存储结构就能很好的解决了这个问题。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值