《数据结构》学习笔记(1)--------继疫情封宿舍摆烂16天之后被迫开始卷

今天已经是疫情封校的第17天了,再摆烂就真的要烂了…
先整理了数据结构的第一部分笔记—线性表(顺序结构部分):
如有问题,请各位大佬批评指正

概念

零个或多个数据元素的有限序列。
线性表顺序结构的定义中,所有元素的数据类型为一致的。

其相关的函数和方法声明如下:

ADT线性表(List)
线性表的抽象数据类型定义如下:
	Operation
		InitList(*L);  //初始化空线性表L
		ListEmpty(L); //若线性表为空,返回True,否则False
		ClearList(*L) //将线性表清空
		GetElem(L, i, *e) //将线性表L中的第i个位置元素值返回给e
		LocateElem(L,e)//在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在表中的   
						序号,否则返回0表示
		ListInsert(*L,i,e) //在线性表L中第i个位置插入新元素e
		ListDelete(*L,i,*e)//删除在线性表L中第i个位置的元素,并将其返回给e
ListLength(L)//返回线性表L中元素个数

线性表顺序结构存储方式

顺序存储结构:
在这里插入图片描述
其本质就是在内存中开辟了一块内存,将一定的内存空间占用,然后把相同数据类型的数据元素一次存放在这片内存中。因为线性表中的每个元素类型相同,因此可以用C语言中的一维数组来实现顺序存储结构。
注意:线性表中,当前的数据长度不得超过存储容量
上代码:

#define MAXSIZE 20
Typedef int ElemType;	//ElemType类型根据实际情况而定这里是int
Typedef struct
{
	ElemType data[MAXSIZE];//数组存储数据元素,最大值为MAXSIZE
	int length;//线性表当前(已经占用)长度
}SqList;

存储空间的起始位置:数组data , 它的存储位置就是存储空间所在的存储位置
线性表的最大容量: 数组长度MAXSIZE
线性表当前长度: length

注意:数组长度和线性表长度不是同一个东西
线性表的长度是指线性表中数据元素的个数,随着插入删除等操作的进行,这个量会变换

数组长度一般存储分配之后不会变,如果用动态内存规划分配动态的一维数组,也可以实现,但是动态内存分配往往会带来性能上的损耗

地址计算

由于存储空间如下:
图2
因此表中元素a[i](下标从0开始)的地址即:
ADDRESS(a[0])+ i * m
ADDRESS是求地址 m是每个元素所占的存储单元
如果有 int a[100]
那么: a[10]的地址就是 &a[0] + 10 (实际上就是&a[0] + 40 个字节)
通过上述,我们可以了解到:对于线性表,他的存取时间性能为O(1) 通常把具有这一特点的存储结构称为随机存取结构

顺序存储结构的相关操作

针对于顺序存储一般有:获取,插入,删除基本操作,更多的就靠自己发挥啦!
首先,为了便于表示和理解:(其实就是人为命名了状态)

		#define OK 1
		#define ERROR 0
		#define True 1
		#define False 0
		Typedef int Status;

获取

获取实本质就是对于线性表L的第i个元素的读操作(并未删)

Status GetElem(SqList L, int I, ElemType *e)
{
	if(L.Length == 0  ||  i<1   ||   i>Length) //若为空表或者与操作的位置不合法即退出
	{
		return  ERROR; 
	}
	*e = L.data[i-1];
	return OK;
}

在获取时,注意几个点:①是否空表,②读取的位置是否合法 ,③注意用指针获取,而不是直接return

插入

E.g: 当在医院排队的时候,这时候突然有个伤者,头上正插了一把刀这个时候,肯定需要让伤者插队,那么插队是如何实现的?
图3-1
图3-2
根据上述流程图,插入算法的思路便可得出:
①插入时,如果位置不合理,直接异常退出
②如果线性表长度大于等于数组长度,直接异常退出或者动态扩容
③从最后一个元素开始向前遍历到第i个位置,分别将他们向后挪动一个位
④将要插入的元素填入i位置
⑤线性表长+1

代码实现如下:(暂时不考虑动态扩容)

Status ListInsert(SqList *L,int i,  Elemtype e)
{
	Status k;
	if(L->Length == MAXSIZE) //表长是否合法
	{
		return ERROR; //报错退出
	}
	if (i<1 || i>Length+1) // 操作位置是否合法
	{
		Return ERROR;
	}
	If(i<=L->Length) //操作位置合法
	{
		for(k=L->length-1 ; k>=i-1;k--)//将待插位置后的元素后移一位
		{
			L->data[k+1] = L->data[k];
		}
	}
	L->data[i-1] = e;  //元素插入
	L->Length += 1; //表长+1
	
	return  True;   
}

删除

如果你在食堂吃饭,前面有人插队,你和后面的同学必然都不愿意,所以在众人的声讨中,插队的同学被迫离开了,于是你和你后面的同学都往前挪动了一步.
上述,就是线性表的顺序存储结构的删除元素的过程
图4-1
图4-2

于是我们有了删除的思路:
①如果删除的位置不合理,退出
②取出删除元素
③从删除元素位置开始所有后面的元素往前挪一位
④表长-1

代码实现如下

Status ListDelete(SqList *L, int i, Elemtype *e) //这里的i是指第i个,从1开始,也就是常规习惯上的第i个
	{
		if(i>=L->Length || i<1)
			return ERROR;
		If(L->Length==0) //如果线性表为空
			return ERROR;
		*e = L->data[i-1];
		if (i < L->Length)
		{
			for(k = i; k<L->Length; k++)
			{
				L->data[k-1] = L->data[i];
			}
		}
		L-Length -- ;
		return True;
	}

顺序结构总结

对于上述操作无论是插入还是删除,时间复杂度表现上,最好的情况是O(1),最坏的情况便是O(n)
平均情况下,由于元素插入到第i个位置,或者删除第i个元素。无论i靠前还是靠后:
插入靠前,移动的元素多,插入靠后,移动元素少。最终平均移动次数和中间元素移动的次数相等:
即为,(n−1)/2
综上:在读取时其时间复杂度为O(1) 当进行删除插入时其时间复杂度为O(n)

图5

注:本文中示意图均来自《大话数据结构》
如有问题,请指正

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值