408考研-数据结构-线性表循环链表

本文详细介绍了静态链表和双向链表的结构,包括数组实现的静态链表的插入和删除方法,以及头插法和尾插法的构建过程。同时讨论了双向链表的特性,特别是循环链表中指针的操作和区别。
摘要由CSDN通过智能技术生成

线性表-静态链表

用数组来实现的链式结构,数组的元素可以看成是一个节点,包括data和next。

在这里插入图片描述

注:

  • 插入元素,和单链表修改元素类似,都是需要修改被插入元素的next和上一个元素的next。只是静态链表不需要移动元素,删除元素同理,不需要移动元素。
  • 这里游标区,是指向了下一个元素,在数组中表现为下标的形式。(因为可以通过数组下标来找到下一个元素,也可以是真实的地址,虽然一般不常用,但会考)

在这里插入图片描述

双向链表

相比原来的单链表多了一个指向前一个节点的指针prior

priordatanext
typedef struct DNode		//定义双链表结点类型
{
	ElemType data;
	struct DNode* prior;	//指向前驱结点
	struct DNode* next;		//指向后继结点
} DLinkNode;

建表

void CreateListF(DLinkNode*& L, ElemType a[], int n)
//头插法建双链表
{
	DLinkNode* s;
	L = (DLinkNode*)malloc(sizeof(DLinkNode));  	//创建头结点
	L->prior = L->next = NULL;
	for (int i = 0; i < n; i++)
	{
		s = (DLinkNode*)malloc(sizeof(DLinkNode));//创建新结点
		s->data = a[i];
		s->next = L->next;			//将结点s插在原开始结点之前,头结点之后
		if (L->next != NULL) L->next->prior = s;
		L->next = s; s->prior = L;
	}
}


void CreateListR(DLinkNode*& L, ElemType a[], int n)
//尾插法建双链表
{
	DLinkNode* s, * r;
	L = (DLinkNode*)malloc(sizeof(DLinkNode));  	//创建头结点
	L->prior = L->next = NULL;
	r = L;					//r始终指向终端结点,开始时指向头结点
	for (int i = 0; i < n; i++)
	{
		s = (DLinkNode*)malloc(sizeof(DLinkNode));//创建新结点
		s->data = a[i];
		r->next = s; s->prior = r;	//将结点s插入结点r之后
		r = s;
	}
	r->next = NULL;				//尾结点next域置为NULL
}

插入节点:

bool ListInsert(DLinkNode*& L, int i, ElemType e)
{
	int j = 0;
	DLinkNode* p = L, * s;
	if (i <= 0) return false;		//i错误返回假
	while (j < i - 1 && p != NULL)
	{
		j++;
		p = p->next;
	}
	if (p == NULL)				//未找到第i-1个结点
		return false;
	else						//找到第i-1个结点p
	{
		s = (DLinkNode*)malloc(sizeof(DLinkNode));	//创建新结点s
		s->data = e;
		s->next = p->next;		//将结点s插入到结点p之后
		if (p->next != NULL)
			p->next->prior = s;
		s->prior = p;
		p->next = s;
		return true;
	}
}
  • 我想要插入到第五个位置上,就需要连接在第四个元素的后面,第四个元素称之为结点p
  • 先节点赋值,然后先连接好等待插入节点的next,然后再去节点的prior,为什么呢?因为如果你先把p节点的next给了指向了s,那后面的节点你就找不到了,无法操作。

删除结点:

bool ListDelete(DLinkNode*& L, int i, ElemType& e)
{
	int j = 0;
	DLinkNode* p = L, * q;			//q是要删除的节点,p是它前面的一个节点
	if (i <= 0) return false;		//i错误返回假
	while (j < i - 1 && p != NULL)
	{
		j++;
		p = p->next;
	}
	if (p == NULL)				//未找到第i-1个结点
		return false;
	else						//找到第i-1个结点p
	{
		q = p->next;				//q指向要删除的结点
		if (q == NULL)
			return false;		//不存在第i个结点
		e = q->data;
		p->next = q->next;		//从单链表中删除*q结点
		if (p->next != NULL) p->next->prior = p;  //如果p的next为空就没prior
		free(q);				//释放q结点
		return true;
	}
}

注:

  • 删除节点的话,两句重要的操作语句前后顺序可以是任意的
  • 但是对于增加节点来说,就尤其需要注意,防止断链找不到节点的问题

相邻节点交换

设有一个循环双向链表,有一个节点指针为p,编写一个函数使得p与其右边的节点进行交换

void swap(DLinkNode* L, int m) {
	DLinkNode* p = L;
	while (m--) {
		p = p->next;
		if (p == NULL) {
			return;
		}
	}
	DLinkNode* q = p->next;
	p->next = q->next;
	q->next->prior = p;
	p->prior->next = q;
	q->prior = p->prior;
	p->prior = q;
	q->next = p;
}

在这里插入图片描述

循环链表

和普通的单链表相比:

  • 没有空指针域(没有指针时指向空的)
  • 判断是否为尾节点的标志的是p->next==L (p->next == L->next)
  • 如果是循环的双向链表,则能更快的找到尾节点
  • 注意最后一个节点的下一个节点是头节点还是第一个节点,不同的题目设定不同
  • 在实际使用的过程中,仅含有尾指针的循环链表会更加便利,因为可以通过尾指针来操作尾部的元素,也能快速定位到头节点(第一个结点)。但如果是单向循环链表,想要删除最后的一个节点,仍然需要去找到最后一个节点的前一个节点,这一点对于单向链表仅有尾指针时是非常费时间的。

在这里插入图片描述
在这里插入图片描述

总结:

线性表的难点还是插入和删除操作,数组实现的顺序线性表增删需要移动元素,链表实现的线性表增删的指针域的变化,头插法尾查法的具体步骤和实现,及其其中的细节。总体内容不多,但常考。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

沐沐沐沐沐雪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值