考研408每周一题(2019 41)
2019年(单链表)
41.(13分)设线性表L=(a1,a2,a3,...,a(n-2),a(n-1),an)采用带头结点的单链表保存,链表中的结点定义如下:
typedef struct node {int data;struct node *next;
} NODE; 
请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各个结点,得到线性表L'=(a1,an,a2,a(n-1),a3,a(n-2),...)。要求:
(1)给出算法的基本设计思想
我们将n用数字代入进去,比如n=7,那么L也就是如下图所示
| a1 | a2 | a3 | a4 | a5 | a6 | a7 | 
重新排列组合之后的L'
| a1 | a7 | a2 | a6 | a3 | a5 | a4 | 
很容易就能发现一下规律,将链表L断开(断链),将链表尾进行反转(逆置),最后重新组合成一条新的链表。这个我们用三个函数(list_spilt、list_reverse、list_merge)来对链表L进行操作。
(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释
环境:Visual Studio 2022
语言:C++
代码如下图所示:
链表断链
//链表断链
void list_spilt(LinkList L, LinkList& L2) {LinkList q, p;L2 = (LinkList)malloc(sizeof(Lnode));//将p和q进行初始化p = q = L->next;//需要对当前指针进行判断//如果当前指针为空的情况//开始遍历while (p) {p = p->next;//防止链表只有一个结点的情况if (p == NULL) {break;}p = p->next;//为了偶数个的情况进行判断if (p == NULL) {break;}q = q->next;}//L2的相关操作//将L2的链表头节点指向当前链表的中间结点qL2->next = q->next;//将中间结点q的next置为NULL(即为L链表的断链)q->next = NULL;
} 
顾名思义就是将链表一分为二,这里我们用快慢指针,快指针p走两步,慢指针q走一步,保证快指针始p终走的比慢指针q多一个单位,因此 ,循环的条件就是快指针p不为空,考虑到p为空的情况,循环即结束。

当进入到第四次循环,也就是p->next==NULL的时候,此时q->next指向a4如上图所示。
从q这里断链,L2中的数据也就包含a5,a6,a7。
时间复杂度:因为p每次移动两步(即为两个结点),故其循环的次数就是n/2,忽略首项系数就是O(n)。
注意:但凡涉及到链表的结构修改操作,需要在函数的形参上加上&(取地址符),C++的引用操作
链表反转(逆置)
//链表反转(逆置)
void list_reverse(LinkList L2) {LinkList r, s, t;r = L2->next;//链表为空的情况if (r == NULL) return;s = r->next;//链表只有一个结点的时候if (s == NULL) return;t = s->next;while (t) {s->next = r;//指针反转r = s;s = t;t = t->next;}s->next = r;//逆置后,链表的第一个结点即为尾结点L2->next->next = NULL;//L2指向现链表的头结点sL2->next = s;
} 
这里我们用三个指针操控,r,s,t。由于链表的特性,我们只需要改变指针的指向即可完成反转操作。需要判断两种情况。即链表为空的情况和链表只有一个结点的情况。直接返回即可。
这里我们用户距离最远的t作为循环的结束条件,只要t==NULL,循环即结束。
将s->next指向r,将s赋给r,t赋给s,t=t->next即可完成一次逆置操作,但因为一开始t是领先r两个位置的,故判断t==NULL循环结束时,实际上还有一次逆置操作没有完成,这里我们只需要将r的地址赋给s->next即可,这样便完成了逆置操作。剩下的就是些收尾工作。
时间复杂度:reverse函数只遍历了L2链表,遍历次数也是n/2,故时间复杂度为O(n)
注意:原先的链表头结点已经变成了尾结点,我们需要手动将其next置为空
而此时的链表头既是s,将s的地址赋给L2->next即可完成链表逆置的全部工作。
链表合并
//链表合并
void list_merge(LinkList L, LinkList L2) {LinkList p, q, pcur;p = L2->next;//p指L2的第一个结点pcur = L->next;//pcur始终指向组后的链表q = pcur->next;//q指向L1的第一个结点while (p && q) {pcur->next = p;p = p->next;pcur = pcur->next;pcur->next = q;q = q->next;pcur = pcur->next;}//任何一个链表都可能剩余一个结点,放进来即可if (p != NULL) {pcur->next = p;}if (q != NULL) {pcur->next = q;}
} 
链表合并操作我们同样需要三个指针,一个指向L,一个指向L2,一个指向L’,循环的条件,判断L和L2链表当前不为空, 因为一开始即对pcur进行赋值为L->next,故往后操作只需要直接让其next指向L2->next也是p即可。个人感觉有点两个字符串交叉合并的意思。
一次操作:
pcur指向p(L2->next),p往后移动一步,再让pcur往后移动一步,让pcur指向q(L->next),q往后移一步,pcur再往后移动一步
- pcur->next = p;
 - p = p->next;
 - pcur = pcur->next;
 - pcur->next = q;
 - q = q->next;
 - pcur = pcur->next;
 
时间复杂度:merge函数while的循环次数也是n/2,故时间复杂度为O(n)
即是以上六步,最后奇数个数据的链表会剩余一个结点的情况,我们直接将其放入新链表L’即可。
以下是全部代码:
#include<stdio.h>
#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));ElemType num;LinkList q, p;q = L;scanf_s("%d", &num);while (num != 9999) {p = (LinkList)malloc(sizeof(Lnode));p->data = num;q->next = p;q = p;scanf_s("%d", &num);}p->next = NULL;
}
//链表断链
void list_spilt(LinkList L, LinkList& L2) {LinkList q, p;L2 = (LinkList)malloc(sizeof(Lnode));//将p和q进行初始化p = q = L->next;//需要对当前指针进行判断//如果当前指针为空的情况//开始遍历while (p) {p = p->next;//防止链表只有一个结点的情况if (p == NULL) {break;}p = p->next;//为了偶数个的情况进行判断if (p == NULL) {break;}q = q->next;}//L2的相关操作//将L2的链表头节点指向当前链表的中间结点qL2->next = q->next;//将中间结点q的next置为NULL(即为L链表的断链)q->next = NULL;
}
//链表反转(逆置)
void list_reverse(LinkList L2) {LinkList r, s, t;r = L2->next;//链表为空的情况if (r == NULL) return;s = r->next;//链表只有一个结点的时候if (s == NULL) return;t = s->next;while (t) {s->next = r;//指针反转r = s;s = t;t = t->next;}s->next = r;//逆置后,链表的第一个结点即为尾结点L2->next->next = NULL;//L2指向现链表的头结点sL2->next = s;
}
//链表合并
void list_merge(LinkList L, LinkList L2) {LinkList p, q, pcur;p = L2->next;//p指L2的第一个结点pcur = L->next;//pcur始终指向组后的链表q = pcur->next;//q指向L1的第一个结点while (p && q) {pcur->next = p;p = p->next;pcur = pcur->next;pcur->next = q;q = q->next;pcur = pcur->next;}//任何一个链表都可能剩余一个结点,放进来即可if (p != NULL) {pcur->next = p;}if (q != NULL) {pcur->next = q;}
}//链表输出
void list_printf(LinkList L) {L = L->next;while (L) {printf("%3d ", L->data);L = L->next;}
}
int main() {//建立链表LinkList L, L2;//尾插法list_tail_insert(L);list_printf(L);//链表断链list_spilt(L, L2);printf("\n----------------list_spilt-----------------\n");list_printf(L2);//链表逆置list_reverse(L2);printf("\n----------------list_reverse---------------\n");list_printf(L2);//链表合并list_merge(L, L2);printf("\n----------------list_merge-----------------\n");list_printf(L);return 0;
} 
代码效果:
偶数情况:

 单数情况:
(3)说明你所设计的算法的时间复杂度
以上三个函数总的运行次数为(3/2)n,忽略首项系数,即为O(n)
相关文章:
考研408每周一题(2019 41)
2019年(单链表) 41.(13分)设线性表L(a1,a2,a3,...,a(n-2),a(n-1),an)采用带头结点的单链表保存,链表中的结点定义如下: typedef struct node {int data;struct node *next; } NODE; 请设计一个空间复杂度为O(1)且时间上尽可能高效的算法&…...
Angular学习笔记(一)
以下内容基于Angular 文档中文版的学习 目录 使用Angular CLI 工具创建项目 HTML标签中{{}}插入值,[]绑定属性,()绑定事件,[(ngModel)]双向绑定 绑定属性 类和样式绑定 事件绑定 双向绑定 循环 IF 定义输入属性 定义输出事件 特殊符号 模板引用变量 页面跳转(路由…...
Linux用户和权限 —— 操作演示
Linux用户和权限——操作演示认知root用户用户、用户组管理查看权限控制修改权限控制- chmod修改权限控制- chownLinux系列: Linux基本命令 —— 操作演示 认知root用户 root用户(超级管理员) 无论是Windows、MacOS、Linux均采用多用户的管理模式进行权限管理。…...
【华为OD机试真题2023 JAVA】单核CPU任务调度
华为OD机试真题,2023年度机试题库全覆盖,刷题指南点这里 单核CPU任务调度 知识点队列优先级队列 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 现在有一个CPU和一些任务需要处理,已提前获知每个任务的任务ID、优先级、所需执行时间和到达时间。 CPU同时只…...
News乐鑫科技亮相德国嵌入式展 Embedded World 2023!
3 月 14 日,德国纽伦堡嵌入式展 Embedded World 2023 火热启幕。本届 Embedded World 主题为 “embedded. responsible. sustainable”,乐鑫科技 (688018.SH) 携众多 AIoT 科技成果亮相展会,致力于打造更智能、更互联、更绿色的物联网未来。…...
java如何创建线程
java如何创建线程1. java如何创建线程1.1 通过继承Thread类来创建线程1.2 通过实现Runnable接口来创建线程1.3 通过匿名内部类来创建线程1.4 lambda表达式1.5 通过实现Runnable接口的方式创建线程目标类的优缺点1. java如何创建线程 一个线程在Java中使用一个Thread实例来描述…...
要是早看到这篇文章,你起码少走3年弯路,20年老程序员的忠告
文章目录前言一、程序员的薪资是怎么样的?二、我现在的情况适合做程序员吗?三、大学期间到底应该学些什么?四、工作还是考研?五、总结前言 我是龙叔,一名工作了20多年的退休老程序员。 如果你在工作之前看到这篇文章…...
IP地址的分类
1. 前言 最初设计互联网络时,为了便于寻址以及层次化构造网络,每个IP地址包括两个标识码(ID),即网络ID和主机ID。 同一个物理网络上的所有主机都使用同一个网络ID,网络上的一个主机(包括网络上工…...
win10下使用docker运行部署nginx,mysql
一、docker的步骤:1.进入docker官网下载安装包2.打开控制面板 - 程序和功能 - 启用或关闭Windows功能,勾选Hyper-V,然后点击确定即可,如图:3.重新启动电脑4.启动Docker在桌面找到Docker for Windows快捷方式࿰…...
sprinboot车辆充电桩
sprinboot车辆充电桩演示录像2022开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:ecli…...
仿京东放大镜效果的实现
仿京东放大镜 (1) 整个案例可以分为三个功能模块 (2) 鼠标经过小图片盒子, 黄色的遮挡层 和 大图片盒子显示,离开隐藏2个盒子功能 (3)黄色的遮挡层跟随鼠标功能。 (4&…...
ESP32设备驱动-LM35温度传感器驱动
LM35温度传感器驱动 文章目录 LM35温度传感器驱动1、LM35介绍2、硬件准备3、软件准备4、驱动实现1、LM35介绍 LM35 系列是精密集成电路温度传感器,其输出电压与摄氏(摄氏度)温度成线性比例。 因此,LM35 优于以开尔文校准的线性温度传感器,因为用户无需从其输出中减去较大…...
基于深度学习的犬种识别软件(YOLOv5清新界面版,Python代码)
摘要:基于深度学习的犬种识别软件用于识别常见多个犬品种,基于YOLOv5算法检测犬种,并通过界面显示记录和管理,智能辅助人们辨别犬种。本文详细介绍博主自主开发的犬种检测系统,在介绍算法原理的同时,给出Py…...
【IDEA插件开发】环境搭建
基础信息 GRADLE 7.5.1 IDEA IntelliJ IDEA 2020.1.1 (Ultimate Edition) Build #IU-201.7223.91, built on April 30, 2020 Licensed to https://zhile.io You have a perpetual fallback license for this version Subscription is active until July 8, 2089 Runtime ve…...
【蓝桥杯专题】 DP(C++ | 洛谷 | acwing | 蓝桥)
菜狗现在才开始备战蓝桥杯QAQ 文章目录【蓝桥杯专题】 DP(C | 洛谷 | acwing | 蓝桥)AcWing 1205. 买不到的数目Acwing 1216. 饮料换购【模拟】01背包271. 杨老师的照相排列最长公共上升子序列PPPPPPPP总结【蓝桥杯专题】 DP(C | 洛谷 | acwi…...
咪咕MGV3201_ZG_GK国科6323_UWE5621DS_免拆卡刷固件包
咪咕MGV3201_ZG_GK国科6323_UWE5621DS_免拆卡刷固件包 特点: 1、适用于对应型号的电视盒子刷机; 2、开放原厂固件屏蔽的市场安装和u盘安装apk; 3、修改dns,三网通用; 4、大量精简内置的没用的软件,运行…...
重构数据-Change Value to Reference将实值对象改为引用对象三
重构数据-Change Value to Reference将实值对象改为引用对象三 1.将实值对象改为引用对象 1.1.实值对象和引用对象区别 下面通过客户Customer和订单Order两个对象介绍下它们的区别 值对象:当一个客户Customer下了多个订单Order后,每个订单类都将创建一…...
计算机网络——通信专业面试问题学习笔记
文章目录1、计算机网络这门课学了什么?目录里有多少章?2、Internet的概念与发展史3、什么是交换?三种交换方式4、OSI的七层协议, TCP/IP的四层协议, 五层协议5、WAN 、LAN 、MAN、PAN这些能分的清楚吗?全称分别都是什么࿱…...
代码随想录算法训练营第三十天 | 332.重新安排行程 51. N皇后 37. 解数独 总结
打卡第30天,回溯算法第二刷。 今日任务 332.重新安排行程51.N皇后37.解数独总结 332.重新安排行程 给你一份航线列表 tickets ,其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从…...
Windows权限提升—MySQL数据库提权
Windows权限提升—MySQL数据库提权1. 前言2. 数据库提权介绍2.1. 常见数据库端口2.2. MySQL数据库提权条件2.3. MySQL数据库提权类型3. MySQL中UDF提权3.1. UDF提权介绍3.2. UDF提权思路3.3. UDF提权步骤3.3.1. 获取外连数据库3.3.1.1. 外连数据库3.3.1.2. 连接数据库3.3.1.3. …...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...
Python学习(8) ----- Python的类与对象
Python 中的类(Class)与对象(Object)是面向对象编程(OOP)的核心。我们可以通过“类是模板,对象是实例”来理解它们的关系。 🧱 一句话理解: 类就像“图纸”,对…...
Docker环境下安装 Elasticsearch + IK 分词器 + Pinyin插件 + Kibana(适配7.10.1)
做RAG自己打算使用esmilvus自己开发一个,安装时好像网上没有比较新的安装方法,然后找了个旧的方法对应试试: 🚀 本文将手把手教你在 Docker 环境中部署 Elasticsearch 7.10.1 IK分词器 拼音插件 Kibana,适配中文搜索…...
Ubuntu 安装 Mysql 数据库
首先更新apt-get工具,执行命令如下: apt-get upgrade安装Mysql,执行如下命令: apt-get install mysql-server 开启Mysql 服务,执行命令如下: service mysql start并确认是否成功开启mysql,执行命令如下&am…...
