30.链表练习题(1)(王道2023数据结构2.3.7节1-8题)

2023-09-20 14:25:20

【前面使用的所有链表的定义在第29节】

试题1:

设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点。

首先来看非递归算法,暴力遍历:

int Del(LinkList &L,ElemType x){
//此函数实现删除链表中为x的元素
	LNode *p,*q;
	p = L;  //p指向头结点
	q = L->next;  //q指向首元结点
	while(q->next!=NULL){
		if(q->data == x){
			p->next = q->next;
			free(q);
			q = p->next;
		}
		else{
			p = p->next;
			q = q->next;
		}
	}
	return 0;
}

int main(){
	LinkList L;
	InitList(L);
	Create(L);
	PrintList(L);
	Del(L, 3);
	PrintList(L);
	return 0;
}

然后看递归算法:

int Del(LinkList &L,ElemType x){
//此函数实现递归删除链表中为x的元素
	LNode *p;
	if(L==NULL)
		return 0;
	if(L->data==x){
		p = L;
		L = L->next;
		free(p);
		Del(L, x);
	}
	else{
		Del(L->next, x);
	}
	return 0;
}

int main(){
	LinkList L;
	InitList(L);
	Create(L);
	PrintList(L);
	Del(L, 3);
	PrintList(L);
	return 0;
}

这里分析一下怎么递归的:从头开始,如果首元结点就是被删掉的x那很显然;如果不是,这时候执行Del(L->next, x),如果第2个是被删掉的元素,进入if(L->next->data==x)分支,此时p=L实际上执行p=L->next,p指向了第2个被删除的结点;第2行L = L->next执行的是L->next=L->next->next,把首元结点的next域修改为指向第3个结点;然后free(p)释放空间,最后继续执行Del(L,x)相当于Del(L->next, x),这时L->next是第3个结点,依次递归。

试题2:(与题1差不多)

试题3:L是带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值

此题可以使用栈来解决,这里主要提书上的递归方法:

void AdversePrint(LinkList L){
//此函数实现反向打印链表L的元素
	if(L!=NULL){
		AdversePrint(L->next);  //递归
		printf("[%d] ", L->data);  //打印当前元素
	}
}

int main(){
	LinkList L;
	InitList(L);
	Create(L);
	PrintList(L);
	AdversePrint(L->next); //带头结点的链表,这里L->next指向首元结点
	return 0;
}

试题4:编写在带头结点的单链表L中删除一个最小值结点的高效算法。

(注意不要写野指针!)

void Deletexmin(LinkList &L){
//此函数实现删除链表最小值元素
	LNode *p, *q, *m, *n;
	int a;
	p = L;  //p指向头结点
	q = L->next;  //q指向首元结点
	a = q->data;  //首元结点元素赋给a
	m = p;
	n = q;
	while (q->next != NULL){
		q = q->next;  //指针后移
		p = p->next;  //指针后移
		if(q->data < a){
			a = q->data;  //更新a
			m = p;  //记录当前最小值的前驱结点
			n = q;  //记录当前最小值结点
		}
	}
	m->next = n->next;
	free(n);
}

int main(){
	LinkList L;
	InitList(L);
	Create(L);
	PrintList(L);
	Deletexmin(L);
	PrintList(L);
	return 0;
}

试题5:将单链表的元素就地逆置

利用头插法重新建立链表:

void ReverseL(LinkList &L){
//此函数实现逆置单链表所有元素
	LNode *p, *q;
	p = L;
	q = L->next;  //q指向首元结点
	p = q;
	q = q->next;  //q指向第二个结点
	p->next = NULL;
	if(q==NULL)
		return ;
	else{
		while (q!=NULL){
			p = q->next;  //p移向首元结点
			q->next = L->next; 
			L->next = q;  //修改头结点指针,头插法
			q = p;
		}	
	}
}

int main(){
	LinkList L;
	InitList(L);
	Create(L);
	PrintList(L);
	ReverseL(L);
	PrintList(L);
	return 0;
}

试题6:有一个带头结点的单链表L,设计算法使其递增有序。

采用插入排序的思想:

void SortL(LinkList &L){
//此函数实现递增排序单链表所有元素
	LNode *p, *q, *r;
	p = L->next;  //p工作在排好序的链表
	q = p->next;  //q是待排序元素,即第二个结点,断开之后的第一个结点
	r = q->next;  //r在q之后
	p->next = NULL;  //断开
	while(q!=NULL){
		r = q->next;
		p = L;  
		while(q->data > p->next->data && p->next!=NULL){
			p = p->next;
		}
		q->next = p->next;
		p->next = q;
		q = r;
	}
}

int main(){
	LinkList L;
	InitList(L);
	Create(L);
	PrintList(L);
	SortL(L);
	PrintList(L);
	return 0;
}

输出:

请输入要输入元素的个数:5
请输入第1元素的值:5
请输入第2元素的值:3
请输入第3元素的值:1
请输入第4元素的值:2
请输入第5元素的值:4
当前单链表的所有元素:[5] [3] [1] [2] [4]
当前单链表的所有元素:[1] [2] [3] [4] [5]

试题7:(修改试题1的参数条件if(q->data == x)即可)

试题8:求两个链表的公共链表

如果有公共链表,一定是这样的Y型拓扑结构:

int LengthL(LinkList L){
//此函数实现求解链表长度
	LNode *p;
	p = L;
	int i = 0;
	while(p->next!=NULL){
		p = p->next;
		i++;
	}
	return i;
}

LinkList Search_1st_common(LinkList L1,LinkList L2){
//此函数实现查找两个链表的公共结点
	int L1length = LengthL(L1);
	int L2length = LengthL(L2);
	printf("%d", LengthL(L1));
	printf("%d", LengthL(L2));

	int delta = 0;  //记录长链表比短链表多多少
	LNode *longList, *shortList;

	if(L1length > L2length){
		longList = L1->next;  //L1更长,longList指向L1首元结点
		shortList = L2->next;
		delta = L1length - L2length;
	}
	else{
		longList = L2->next;  //L2更长,longList指向L2首元结点
		shortList = L1->next;
		delta = L2length - L1length;
	}
	printf("%d", longList->data);
	printf("%d", shortList->data);
	printf("%d", delta);

	for (int i = 0; i < delta;i++){ // 移动longList指针至delta位置
		longList = longList->next;
	}
	printf("%d", longList->data);

	//经过以上移动,此时longList指针与shortList指针指的剩余长度一样
	while (longList!=shortList && longList != NULL){
		longList = longList->next;
		shortList = shortList->next;
	}
	return longList;
}

void PrintResult(LinkList L){
	if(L == NULL)
		printf("公共结点不存在!");
	else
		PrintList(L);
}

int main(){
	LinkList L1,L2;
	InitList(L1);
	Create(L1);
	PrintList(L1);
	InitList(L2);
	Create(L2);
	PrintList(L2);
	PrintResult(Search_1st_common(L1, L2));
	return 0;
}

输出:

请输入要输入元素的个数:2
请输入第1元素的值:1
请输入第2元素的值:2
当前单链表的所有元素:[1] [2]
请输入要输入元素的个数:5
请输入第1元素的值:3
请输入第2元素的值:4
请输入第3元素的值:5
请输入第4元素的值:6
请输入第5元素的值:7
当前单链表的所有元素:[3] [4] [5] [6] [7]
253136公共结点不存在!

请输入要输入元素的个数:2
请输入第1元素的值:1
请输入第2元素的值:2
当前单链表的所有元素:[1] [2]
请输入要输入元素的个数:3
请输入第1元素的值:3
请输入第2元素的值:4
请输入第3元素的值:5
当前单链表的所有元素:[3] [4] [5]
233114公共结点不存在!

在写这段代码的时候踩了一个坑:大家观察下面两段代码:

void Search_1st_common(){
//此函数实现查找两个链表的公共结点
	int L1length = 3;
	int L2length = 5;
	int delta = 0;  //记录长链表比短链表多多少

	if(L1length > L2length){
		delta = L1length - L2length;
	}
	else{
		delta = L2length - L1length;
	}
	printf("%d", delta);
}

int main(){
	Search_1st_common();
	return 0;
}
void Search_1st_common(){
//此函数实现查找两个链表的公共结点
	int L1length = 3;
	int L2length = 5;
	int delta = 0;  //记录长链表比短链表多多少

	if(L1length > L2length){
		int delta = L1length - L2length;
	}
	else{
		int delta = L2length - L1length;
	}
	printf("%d", delta);
}

int main(){
	Search_1st_common();
	return 0;
}

打印delta的结果分别是2和0.后一段代码中if...else...结构体内相当于重新定义了一个delta,当结构体执行结束后又被释放掉了,所以delta的返回结果是0.

更多推荐

GO学习之切片操作

GO系列1、GO学习之HelloWorld2、GO学习之入门语法3、GO学习之切片操作4、GO学习之Map操作5、GO学习之结构体操作6、GO学习之通道(Channel)7、GO学习之多线程(goroutine)8、GO学习之函数(Function)9、GO学习之接口(Interface)10、GO学习之网络通信(Ne

RL — 强化学习算法概述

一、说明在本系列中,我们检查了许多强化学习(RL)算法,例如,MoJoCo任务的策略梯度方法,Atari游戏的DQN和机器人控制的基于模型的RL。虽然许多算法都是针对特定领域引入的,但这种联系只能是遗留的。在本文中,我们将概述这些算法,并讨论它们在选择使用什么方法时的一般权衡。二、无模型算法RL算法可分为基于模型的算法

飞书ChatGPT机器人 – 打造智能问答助手实现无障碍交流

文章目录前言环境列表1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10.机器人测试前言在飞书中创建chatGPT机器人并且对话,在下面操作步骤中,使用

静态代码分析基础知识及分析工具

安全之安全(security²)博客目录导读ATF(TF-A)/OPTEE之静态代码分析汇总目录一、静态代码分析介绍二、静态代码分析工具三、Sonarlint静态代码分析工具介绍1.定义2.特性3.SonarQube的官方文档一、静态代码分析介绍根据维基百科,静态代码检查又称为静态程序分析,是指在不运行计算机程序的条件

WAIC2023:图像内容安全黑科技助力可信AI发展

目录0写在前面1AI图像篡改检测2生成式图像鉴别2.1主干特征提取通道2.2注意力模块2.3纹理增强模块3OCR对抗攻击4助力可信AI向善发展总结0写在前面2023世界人工智能大会(WAIC)已圆满结束,恰逢全球大模型和生成式人工智能蓬勃兴起之时,今年参会的人们更加关注AIGC技术在未来可以如何作用于人们的生活。自AI

公网访问的Linux CentOS本地Web站点搭建指南

文章目录前言1.本地搭建web站点2.测试局域网访问3.公开本地web网站3.1安装cpolar内网穿透3.2创建http隧道,指向本地80端口3.3配置后台服务4.配置固定二级子域名5.测试使用固定二级子域名访问本地web站点前言在web项目中,部署的web站点需要被外部访问,则需要一个媒介,通过把资源放在这个媒介中

PSO粒子群优化算法

PSO粒子群优化算法算法思想matlab代码python代码算法思想粒子群算法(ParticleSwarmOptimization)优点:1)原理比较简单,实现容易,参数少。缺点:1)易早熟收敛至局部最优、迭代后期收敛速度慢的。算法拓展针对标准PSO的缺点,通常有如下的改进:实现参数的自适应变化。引入一些其他机制。比如

Mysql和ES、Redis数据同步方案汇总

文章目录前言一、数据同步方案1.同步双写2.异步双写([MQ](https://so.csdn.net/so/search?q=MQ&spm=1001.2101.3001.7020)方式)3.基于Mysql表定时扫描同步4.基于[Binlog](https://so.csdn.net/so/search?q=Binlo

AIGC数据处理与存储解决方案

针对在AIGC的场景下,如何解决在AIGC训练过程中数据的存储和数据处理的问题,杨冠军从三个方面进行介绍与解读:一是AIGC对存储提的新需求;二是介绍腾讯云可以给用户提供的整体存储解决方案;三是腾讯云提供的整体数据处理方案。AIGC的新需求:模型训练与应用推理的述求我国每年产生的数据量呈现非常大的增长趋势,这个前提还是

【JavaSE笔记】继承与多态(万字详解)

一、前言在Java的核心概念中,继承和多态无疑是重要的一环。它们都是Java以及其他许多面向对象编程语言的基石,为我们提供了强大的工具来创建模块化,可重用和易于维护的代码。继承让我们可以创建新的类,通过继承现有类的属性和方法,来复用代码并添加或覆盖特定的行为。这为我们提供了一种强大的方式来组织和结构化我们的代码,使我们

【活动总结】0730-COC深圳社区AI●CMeetup第4期——畅谈AI+智能制造与机器人的现状与未来

【活动总结】0730-COC深圳社区AI●CMeetup第4期——畅谈AI+智能制造与机器人的现状与未来在过去的半年里,AI相关技术取得了革命性突破,CSDNCMeet策划推出系列研讨会,深度探讨技术更新后的开发实践。然而,更重要的是如何对AI实践应用,如何在最大程度上发挥AI的产业价值,提升生产效率。因此,AIMee

热文推荐