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

今天是封校的第20天,我想回家,我裂开了…
(昨天没更新是因为又差点摆烂了…)
本文是对链表的继续学习,如果对链表还未明晰,可参考《数据结构》学习笔记(2)

静态链表

静态链表概述

在早期的Basic,Fortran等早期的编程语言中,由于没有指针,链表不能直接实现,有人想出这样的办法:
利用数组代替链表,每个数组元素都是两个数据域组成,data和cur。 数组每个下标都对应一个data和一个cur。数据域data存放数据元素,而游标cur相当于单链表中的next指针,存放该元素后继在数组中的下标。
上述这种数组描述的链表称为静态链表

静态链表的代码实现

代码实现静态链表:

#define MAXSIZE 1000 //假设链表最大长1000
	typedef struct
	{
		ElemType data;
		int cur;                  //游标cursor ,为0时,表示无指向
	}componet,StaticLinkList[MAXSIZE];

除此之外,我们将对数组的第一个和最后一个元素做特殊处理:不存数据。通常情况下,将未被使用的数组元素称为备用链表,数组的第一个元素,也就是下标为0的元素cur就存放备用链表的第一个结点的下标;而数组的最后一个元素的cur则存放第一个有数值的元素的下标,类似于单链表中的头结点作用,当整个链表为空时,则为0^2如下图:
图1
初始化数组状态如上图,代码实现如下:

/*spece[0].cur为头指针,"0"表示空指针*/
Status InitList(StaticLinkList space)
{
	int i;
	for(i=0;i<MAXSIZE-1;i++)
	{
		space[i].cur = i+1;
	} 
	space[MAXSIZE-1].cur = 0; /*目前静态链表为空,最后一个元素的cur为0*/
	return True;
}

循环链表

循环链表概述

对于一般的单链表而言,遍历到最后就结束了。在某次,你需要从链表上的中间结点开始,遍历整个链表的时候,对于单链表,而言如果,从当前中间结点开始,遍历到最后,就不能够遍历到前面的结点。因此,引出了循环链表,循环链表其实就是单链表中终端结点指针由空指针改为指向头结点,使整个链表形成一个环形,这样以来,就完美的解决了上述问题。

为了使空链表和非空链表处理一致,通常,将会设立一个头结点(这不是必须的)

如下图空循环链表和非空循环链表:
图2
图3 对于循环链表和单链表的主要差异就在于:单链表在判断p->nect==NULL是结束,而循环链表则是判断p->next不是头结点则循环不结束。
单链表中:我们可以利用O(1)的时间访问第一个结点,但是如果要访问最后一个结点,需要的时间是O(n)
对于循环链表来说,我们可以把这个时间减少到O(1),不使用头指针,而是使用 指向终端结点的尾指针 来表示循环链表
图4

循环链表的操作

如果要把两个循环链表合并成一个表时,有了尾指针就相对很简单:
图5只需要进行如下操作
图6
关键步骤代码:

p = rearA->next;                                   //保存A链表的头结点 即步骤①
rearA->next = rearB->next->next;      //将B链表的第一个结点接续在A链表的尾结点之后 即步骤②
rearB->next = p;                                                   //将B链表的尾结点和A链表的头结点续接起来,即步骤③
free(p); //释放空间

双向链表

双向循环链表的概述

对于传统的单链表,我们往往只能不断地向下一个节点索引,如果再次需要某节点的上一结点时,用以上介绍过的链表结构,要么从头结点再来一个指针直到当前结点的上一个,要么,循环链表索引一圈。
当然这种办法消耗的时间是相当多的。那么,有没有这么一种可能,我们在链表的结点上,再加入一个指针域,指向上一个结点,如此以来,牺牲了少量的空间,却节省大量的时间。使得这个链表正反都可以索引
那么这样的链表就称为双向链表
代码如下:

typedef struct Node
{
	ElemType data;
	struct Node *prior;
	struct Node *next;
}DulNode, *DulLinkList;

一般而言,双向链表是与循环链表相结合的,也就是双向循环链表。
如图:这是一个带头节点的空的双向循环链表
图7
图8
由于是双向循环链表,因此有以下:
p->next->prior = p = p->prior->next

双向循环链表的操作

在对于双向循环链表插入或者删除操作的时候一定注意先后顺序,正确顺序如下:
比如在对a(i)和a(i+1)之间插入时,
图9
代码实现:

	s->prior = p ;
	s->next  = p->next  ;   //将新的结点s与前后相接入
	p->next->prior = s;     //后一结点与s相接
	p->next = s;       //前一结点与s相接

删除时,只需要如下两步
图10

p->prior->next = p->next;//把p结点之前的结点的后指针阈指向p结点之后的结点
p->next->prior = p->prior;//把p结点之后的结点的前指针指向p之前的结点
free(p);  //释放p

对于双向链表而言,其比单链表稍复杂一点。插入和删除的时候都需要注意结点的前后衔接。双向链表虽然相比于单链表更占内存,但是其在操作上节省了很多时间。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值