2019_41 考研408
2019年(单链表)
41.(13分)设线性表

采用带头结点的单链表保存,链表中的结点定义如下:
typedef struct node {
int data;
struct node* next;
}NODE;
请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各结点,得到线性表L'=(q,a,,a,an-1,as,an-2y…)。要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
(3)说明你所设计的算法的时间复杂度。
思路:因为题目要求要空间复杂度为O(1),所以我们不能再额外申请空间了,然后再找到链表的中间结点,将其一分为二,分为L和L2的单链表,并将L2链表进行原地逆置,最后再将L和L2进行混合合并。
一、找到中间结点,并一分为二。
思路:定义两个指针p1和p2,p1指针每次走两步,p2指针每次走一步,当p1指针走到最后,p2指针必定走到中间结点。(写代码的过程中还应该注意总结点是奇数还是偶数)

代码段:
void find_middle(LinkList L,LinkList &L2) //寻找链表中间结点,并设置好L2链表
{L2 = (LinkList)malloc(sizeof(LNode)); //设置第二条链表的头结点 LinkList pcur,ppre; //双指针法,pcur跨两步,ppre跨一步。 ppre = pcur = L->next; //一开始都指向第一个结点,即首元结点 while(pcur) {pcur = pcur->next;if(pcur == NULL) //防止pcur为空 {break;}pcur = pcur->next; //若此处pcur为空,则不满足循环条件 if(pcur == NULL) //为了使得偶数个,ppre依然指向a1,a2到a6中的a3结点 {break;}ppre = ppre->next;}L2->next = ppre->next; //由L2头结点指向后面一半链表,L2的第一个结点是此时ppre所指向的结点 ppre->next = NULL; //此时的ppre为前一半链表的最后一个结点,最后一个结点的指针域应该为NULL
}
二、将L2原地逆置
思路:分别定义3个指针r、s、t,让r、s、t分别指向前三个结点,再让第二个结点指向第一个结点,然后r、s、t同时向后移动一位,再让第三个结点指向第二个结点,然后r、s、t同时向后移动一位,如此往复循环,当t为null时循环结束。因为原有链表的头结点变成链表最后一个结点,最后一个结点应该指向NULL,最后让L2头结点指向新的首元结点s。

代码段:
void reverse(LinkList L2) //逆转。因为L2的头结点不会发生改变
{LinkList r,s,t;r = L2->next; //一开始r指向首元结点 if(r == NULL){return ;//链表为空 }s = r->next; //一开始r指向s if(s == NULL){return;//链表只有1个结点 } t = s->next; //一开始让s指向twhile(t){s->next = r; //原地逆置,让s指向r r = s; //以下3句,是3个指针同时向后移动一位 s = t;t = t->next; } s->next = r;L2->next->next = NULL;//逆置后,原本链表的第一个结点的指针域为空。即逆置后新链表的最后一个结点。 L2->next = s; //此时s是逆置后链表的第一个结点,L2的头结点应该指向它
}
三、将L与L2进行混合合并
思路:将L与L2链表合并,合并时分别轮流放入一个结点。定义3个指针pc、p、q,一开始指针pc指向L链表的首元结点,指针p指向L链表的第二结点,指针q指向L2链表的首元结点。并且让pc指针始终指向合并后新链表的尾部,使用p指针始终指向链表L待放入的结点,q指针始终指向链表L2待放入的结点。

代码段:
void merge(LinkList L,LinkList L2) //将L与L2混合并合并
{LinkList pcur,p,q;pcur = L->next; //pcur一开始指向L链表的首元结点。pcur始终指向组合后新链表的链表尾p = pcur->next; //p指向L链表的第二个结点。p用来遍历L链表。 q = L2->next; //q指向L2链表的首元结点。q用来遍历L2的链表。 while(p!=NULL && q!=NULL) //以下步骤画图,就会非常的直观。 {pcur->next = q;q = q->next;pcur = pcur->next;pcur->next = p;p = p->next;pcur = pcur->next; } //任何一个链表都可能剩余一个结点,放进来即可。 if(p!=NULL){pcur->next = p;}if(q!=NULL){pcur->next = q;}
}
总代码:
#include<stdio.h> //2019年考研408真题,第41题
#include<stdlib.h>typedef int ElemType;
typedef struct LNode{ElemType data; //数据域 struct LNode *next; //指针域
}LNode,*LinkList;void list_tail_insert(LinkList &L) //尾插法建立链表
{L = (LinkList)malloc(sizeof(LNode));L->next = NULL;ElemType x;scanf("%d",&x);LNode *s;//用来指向申请的新结点LNode *r=L;//r始终指向链表尾部while(x != 999){s = (LinkList)malloc(sizeof(LNode));s->data = x;r->next = s; //r->next指向s结点r = s; //r要指向新的尾部 scanf("%d",&x); } r->next = NULL; //让尾结点的next为NULL
}void find_middle(LinkList L,LinkList &L2) //寻找链表中间结点,并设置好L2链表
{L2 = (LinkList)malloc(sizeof(LNode)); //设置第二条链表的头结点 LinkList pcur,ppre; //双指针法,pcur跨两步,ppre跨一步。 ppre = pcur = L->next; //一开始都指向第一个结点,即首元结点 while(pcur) {pcur = pcur->next;if(pcur == NULL) //防止pcur为空 {break;}pcur = pcur->next; //若此处pcur为空,则不满足循环条件 if(pcur == NULL) //为了使得偶数个,ppre依然指向a1,a2到a6中的a3结点 {break;}ppre = ppre->next;}L2->next = ppre->next; //由L2头结点指向后面一半链表,L2的第一个结点是此时ppre所指向的结点 ppre->next = NULL; //此时的ppre为前一半链表的最后一个结点,最后一个结点的指针域应该为NULL
} void reverse(LinkList L2) //逆转。因为L2的头结点不会发生改变
{LinkList r,s,t;r = L2->next; //一开始r指向首元结点 if(r == NULL){return ;//链表为空 }s = r->next; //一开始r指向s if(s == NULL){return;//链表只有1个结点 } t = s->next; //一开始让s指向twhile(t){s->next = r; //原地逆置,让s指向r r = s; //以下3句,是3个指针同时向后移动一位 s = t;t = t->next; } s->next = r;L2->next->next = NULL;//逆置后,原本链表的第一个结点的指针域为空。即逆置后新链表的最后一个结点。 L2->next = s; //此时s是逆置后链表的第一个结点,L2的头结点应该指向它
}void merge(LinkList L,LinkList L2) //将L与L2混合并合并
{LinkList pcur,p,q;pcur = L->next; //pcur一开始指向L链表的首元结点。pcur始终指向组合后新链表的链表尾p = pcur->next; //p指向L链表的第二个结点。p用来遍历L链表。 q = L2->next; //q指向L2链表的首元结点。q用来遍历L2的链表。 while(p!=NULL && q!=NULL) //以下步骤画图,就会非常的直观。 {pcur->next = q;q = q->next;pcur = pcur->next;pcur->next = p;p = p->next;pcur = pcur->next; } //任何一个链表都可能剩余一个结点,放进来即可。 if(p!=NULL){pcur->next = p;}if(q!=NULL){pcur->next = q;}
}void print_list(LinkList L) //打印输出链表
{L = L->next;while(L != NULL){printf("%3d",L->data);L = L->next;}printf("\n");
}int main()
{LinkList L; //L是头指针 LinkList search; //用来存储拿到的某一个结点 list_tail_insert(L); //输入数据可以为数据 print_list(L);//链表打印LinkList L2=NULL; find_middle(L,L2); //寻找中间结点,并返回第二条链表 。只有一个结点时,L2中是没有结点的 printf("-----------------------------\n");print_list(L);print_list(L2);printf("-----------------------------\n");reverse(L2);print_list(L2);printf("-----------------------------\n");merge(L,L2);free(L2);print_list(L);return 0;
}
相关文章:

2019_41 考研408
2019年(单链表)41.(13分)设线性表采用带头结点的单链表保存,链表中的结点定义如下:typedef struct node {int data;struct node* next;}NODE;请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各结点,得到线性表L(q,a,,a,an…...

Linux账号与用户组
目录 用户标识符:UID与GID 用户账号 /etc/passwd文件结构 1、账号名称 2、密码 3、UID 4、GID 5、用户信息说明栏 6、家目录 7、shell /etc/shadow文件结构 1、账号名称 2、密码 3、最近修改密码的日期 4、密码不可被修改的天数(与第三字…...

有趣的Hack-A-Sat黑掉卫星挑战赛——定位卫星Jackson
国家太空安全是国家安全在空间领域的表现。随着太空技术在政治、经济、军事、文化等各个领域的应用不断增加,太空已经成为国家赖以生存与发展的命脉之一,凝聚着巨大的国家利益,太空安全的重要性日益凸显[1]。而在信息化时代,太空安…...

JAVA集合专题3 —— vector + LinkedList + Set
目录vector的特点LinkedList底层结构模拟双向链表比较ArrayList和LinkedListSet接口基本介绍Set接口的遍历方式Set接口实现类对象的特点Set接口实现类HashSet模拟HashSet/HashMap的底层结构vector的特点 Vector底层是一个对象数组Vector是线程同步的,即线程安全的&…...

Scout:一款功能强大的轻量级URL模糊测试与爬取工具
关于Scout Scout是一款功能强大的轻量级URL模糊测试与爬取工具,可以帮助广大研究人员进行URL模糊测试,并爬取目标Web服务器中难以扫描发现的VHSOT、文件和目录等资源。 项目中包含了一个完整的字典文件,并尽可能地提供了更多的便携性&#…...

leaflet 解决marker呈现灰色边框的问题
第052个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet示例中处理marker外面有灰色边框的问题,请看未处理会后的图片。 处理后的结果非常满意,不再显示灰色边框。处理方法参考源代码。 直接复制下面的 vue+openlayers源代码,操作2分钟即可运行实现效果; 注意…...
MySQL JSON类型字段的查找与更新
MySQL 提供了丰富的函数用于 JSON 类型字段的查找与更新,详见官方文档。 创建一个表 t1,basic_info 字段为JSON类型: CREATE TABLE t1 (id int(11) NOT NULL AUTO_INCREMENT,basic_info json DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CH…...

element Ui树状图控件 spring boot Vue 实现角色授权功能
目录 前言: 二. element ui 2.1官网提供的核心代码 三.表结构 编辑 四.后端 4.1功能分析 4.2实体类 4.3 查询全部权限显示的结果 4.2修改角色权限的后台方法 五.vue 5.0代码总览 5.1树形图 5.2所需要的绑定数据 5.3所需方法 前言: 先上图…...

已解决sc delete MongoDB卸载MongoDB拒绝访问。
已解决sc delete MongoDB卸载MongoDB拒绝访问。 文章目录报错问题报错翻译报错原因解决方法联系博主免费帮忙解决报错报错问题 粉丝群里面的一个小伙伴遇到问题跑来私信我,想卸载MongoDB数据库,但是发生了报错(当时他心里瞬间凉了一大截&…...

python的opencv操作记录11——阈值分割
文章目录传统图像处理分割阈值分割一个应用场景opencv库中的阈值分割固定阈值THRESH_OTSU 大津法阈值自适应阈值传统图像处理分割 现在提到图像分割,很多人会直接想到当前火爆的深度学习的各种分割网络,比如实例分割,语义分割等。其实在传统…...

Python-项目实战--飞机大战-英雄登场(7)
目标设计英雄和子弹类使用pygame.key.get_pressed()移动英雄发射子弹1.设计英雄和子弹类1.1英雄需求游戏启动后,英雄出现在屏幕的水平中间位置,距离屏幕底部120像素英雄每隔0.5秒发射一次子弹,每次连发三枚子弹英雄默认不会移动,需…...

寒假安全作业nginx-host绕过实例复现
1.测试环境搭建 LNMP架构的话,肯定就是linux、nginx、mysql、php四大组件。在后面的复现中我们还会用到https的一部分知识,故这里的nginx就需要使用虚拟主机并且配置https证书,且具有php解析功能。 1.1 基础nginx配置 #1.创建web目录 mkdir …...

RocketMQ-消息消费模式 顺序消费
RocketMQ-消息消费模式 顺序消费RocketMQ-消息消费模式集群模式集群模式的演示(本身就默认)Rocketmq存储队列广播模式顺序消费如何改实现顺序消费RocketMQ-消息消费模式 集群模式 在消费模式为集群的情况下,如果机器是集群的,消息只会给集群中的其中一台机器消费到 集群模…...

一、Java并发编程之线程、synchronized
黑马课程 文章目录1. Java线程1.1 创建和运行线程方法一:Thread方法二:Runnable(推荐)lambda精简Thread和runnable原理方法三:FutureTask配合Thread1.2 查看进程和线程的方法1.3 线程运行原理栈与栈帧线程上下文切换1.…...

12.hadoop系列之MapReduce分区实践
本文我们学习MapReduce默认分区以及自定义分区实践 当我们要求将统计结果按照条件输出到不同文件(分区),比如按照统计结果将手机归属地不同省份输出到不同文件中(分区) 1.默认Partitioner分区 public class HashPartitioner<K, V> extends Partitioner<…...

有了独自开,一个人就是一个团队
文章目录 简单介绍优点 优秀案例平台福利总结 简单介绍 独自开是一个基于商品与服务交易全流程的PaaS开发平台。对于开发者,独自开可以协助开发者一个人独自开发一套系统。 优点 独自开有独创的分层标准化平台架构,可以满足系统的任何个性化需求。 …...

web期末复习 2023.02.11
文章目录Web 的概念Web 组成用户通过浏览器请求资源的过程:HTML 超文本标记语言CSS插入样式表的方法有三种:对象,类,实例一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:JavaScript 用法什么是 Java Server Pages?JSP 注释JSP 的 J…...
第44章 用户密码实体及其约束规则的定义实现
1 说明: 由当前程序需要兼容实现多种用户密码的加密操作,所以必须把“CustomerPassword”定义为实体类,该类用于用于把加密方式、密钥及其加密后的密码持久化到“CustomerPassword”表中,以便用为用户登录操作提供验证支撑。 如果…...

聊聊并发与锁
持续坚持原创输出,点击蓝字关注我吧1.并发与并行并发可以充分地利用 CPU 资源,一般都会使用多线程实现。多线程的作用是提高任务的平均执行速度,但是会导致程序可理解性变差,编程难度加大。关于对并发与并行的概念,大家…...

开源项目 —— 原生JS实现斗地主游戏 ——代码极少、功能都有、直接粘贴即用
目录 效果如下 目录结构 GameEntity.js GrawGame.js konva.min.js PlayGame.js veriable.js index.html 结语: 前期回顾 卡通形象人物2 写代码-睡觉 丝滑如德芙_0.活在风浪里的博客-CSDN博客本文实现了包含形象的卡通小人吃、睡、电脑工作的网页动画https://…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...