数据结构和算法学习笔记(3)——线性表结构(顺序结构和链式结构)

线性表概念

定义由一个或者多个数据元素组成的有序序列
注意点1、他是一个序列,有先来后到
2、每个元素有且只有一个前驱和后续,但是第一个没前驱,最后一个没后继.
3、线性表是有限个的
4、线性表的元素> =0
类型顺序存储结构和链式存储结构

顺序存储结构

#define MAXSIZE 20		//设置大小
typedef int ElemType;	//这里把int重新定义元素类型
typedef struct
{
	ElemType data[MAXSIZE];	//数组的长度
	int length;				//线性表长度
}Sqlist;

总结一下顺序存储结构的三个属性

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

注意点:在上面的定义中ElemType data[MAXSIZE]是数组的长度,而int length是线性表长度。数组长度是存放线性表的存储空间的总长度,一般初始化后不会表化,而线性表长度是指表中的元素个数会变化。

顺序存储结构线性表操作方式

注意:这里的顺序线性表都依照上文定义的Sqlist结构体,与元素类型为ElemType

获取元素

注意:要先做一下判断是不是非法输入。

//顺序线性表L,索引i,返回的元素放在e中
int GetElem(Sqlist L,int i,ElemType *e){
	if(L.lengt == 0 || i<0 || i>L.lengt)
	{
		return -1;	//表示失败
	}else{
		*e = L.data[i];
		return 0;	//表示成功
	}
}
插入元素

插入一个元素,后面的的元素往后移动

int ListInsert(Sqlist *L,int i,ElemType e){
	int tmp = 0;
	if(L->lenght == MAXSIZE || i<0||i>L->lenght){
		return -1;
	}
	if(i<=L->lenght)
	{
		for(tmp = L->lenght-1; tmp>=i ;tmp--)
		{
			L->data[tmp+1] = L->data[tmp];
		}
	}
	L->data[i-1] = e;
	L->lenght++;
	return 0;
}
删除元素

删除一个元素,后面的的元素往前移动,这里ElemType *e保存被删除的值

int ListDelete(Sqlist *L,int i,ElemType *e){
	int tmp = 0;
	if( i<0||i>L->lenght){
		return -1;
	}
	*e = L->data[i];
	if(i<=L->lenght)
	{
		for(tmp = i; tmp<L->lenght-1 ;tmp++)
		{
			L->data[tmp] = L->data[tmp+1];
		}
	}
	L->lenght--;
	return 0;
}
顺序存储结构线性表总结
适用场合适用于不经常插入和删除,更多的是存取元素的操作
最坏情况插入和删除都是最后一个元素,复杂度为O(1)
最好情况插入和删除都是第一个元素,复杂度为O(n)
平均情况O((n-1)/2) =O(n)
优点不需要为了维持逻辑关系而额外增加存储空间,可以快速存取元素
缺点插入和删除需要大规模移动,容易产生内存碎片(有的空间空着没元素)

链式存储结构

定义用容易的存储单元存储线性表的数据元素,这组存储单元可以在内存中未被占用的任意位置。
结构概述在链式存储结构中,除了要存储数据元素信息外,还要存储他的后续元素的存储地址。

这里存放数据的地方叫数据域,存放地址的地方叫指针域
单链表只有一个指针域的称为单链表。一般头结点的数据域放置链表长度或者不放数据
typedef struct Node{
	ElemType data;		//数据域
	struct Node* next;	//指针域
}Node_T;

链式存储结构线性表操作方式

获取元素

获取的元素保存在e中

int GetElem(Node_T*L,int i,ElemType *e)
{
	int tmp;
	Node_T* p;
	p = L->next;
	tmp = 1;
	while(p && tmp <i)	//下个节点不为空,且还没遍历到
	{
		p = L->next;
		++tmp;
	}
	if(!p||tmp>i){	//遍历完或者出错
		return -1
	}
	*e = p->data;
	return 0;
}
插入元素

在序号i处插入元素

//这里使用Node_T**是为保护头结点
int ListInsert(Node_T** L,int i,ElemType e)
{
	int tmp;
	Node_T* p,newNode;
	p = *L;
	tmp = 1;
	while(p && tmp <i)	//下个节点不为空,且还没遍历到
	{
		p = L->next;
		++tmp;
	}
	if(!p||tmp>i){	//遍历完或者出错
		return -1
	}
	newNode = (Node_t*)malloc(sizeof(Node_t));
	newNode->data = e;
	newNode->next = p->next;
	p->next= newNode;
	
	return 0;
}
删除元素

在序号i处删除元素,用e来保存被删除结点的数据域

//这里使用Node_T**是为保护头结点
int ListDelete(Node_T** L,int i,ElemType *e)
{
	int tmp;
	Node_T* p,nextNode;
	p = *L;
	tmp = 1;
	while(p && tmp <i)	//下个节点不为空,且还没遍历到
	{
		p = L->next;
		++tmp;
	}
	if(!p||tmp>i){	//遍历完或者出错
		return -1
	}
	nextNode = p->next;
	p->next = nextNode->next;
	
	//保存数据域,删除结点
	*e = nextNode->data;
	free(nextNode);
	nextNode = NULL;
	
	return 0;
}
头插法(不怎么常用)

头插法创建链表示例

void CreateListHead(Node_T** L,int n){
	Node_T* p;
	int i;
	srand(time(0));	//初始化随机种子
	*L = (Node_T*)malloc(sizeof(Node_T));
	for(i = 0;i<n ;i++){
		p = (Node_T*)malloc(sizeof(Node_T));
		p = data = rand()%100+1;
		p->next = (*L)->next;
		(*L)->next = p;
	}
}
尾插法(常用)

尾插法创建链表示例

void CreateListHead(Node_T** L,int n){
	Node_T* p ,tmp;
	tmp = *L;
	int i;
	srand(time(0));	//初始化随机种子
	*L = (Node_T*)malloc(sizeof(Node_T));
	for(i = 0;i<n ;i++){
		p = (Node_T*)malloc(sizeof(Node_T));
		p = data = rand()%100+1;
		tmp->next = p;
		tmp = p;	//游标往后移动
	}
}
销毁链表
int ClearList(Node_T** L){
	Node_T* p ,tmp;
	p = (*L)->next;
	while(p){
		tmp = p->next;
		free(p);
		p = tmp;
	}
	(*L)->next = NULL;
	return 0;
}
链式存储结构线性表总结
适用场合适用于插入、删除多个数据
最坏情况插入和删除都是最后一个元素,复杂度为O(n)
最好情况插入和删除都是第一个元素,复杂度为O(1)
平均情况O((n-1)/2) =O(n)
优点插入和删除元素只要简单指针赋值,而且不会产生内存碎片,比较灵活应变
缺点需要额外的空间来存储指针

简单看来链式存储的优势不是很大,但是如果要一次插入或删除多个元素就会快很多,因为插入元素的时间复杂度为O(n),但是我们获取了指针域后,接下来的元素时间复杂度都为O(1)。

链式存储结构线性表和顺序存储结构线性表对比

比较方式单链表结构顺序存储结构
存储方式用容易的存储单元存放线性表的元素用一段连续的存储单元一次存储线性表的数据元素
时间性能查找O(n)
插入和删除:计算位置后为O(1)
查找O(1)
插入和删除:O(n)
空间性能不需要预先分配,元素个数不受限制需要预先分配空间,容易出现溢出或者浪费

综上:需要常常需要读取的时候用顺序结构,常常要删除插入的情况使用链式结构

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值