考研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. …...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...

C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...
《Offer来了:Java面试核心知识点精讲》大纲
文章目录 一、《Offer来了:Java面试核心知识点精讲》的典型大纲框架Java基础并发编程JVM原理数据库与缓存分布式架构系统设计二、《Offer来了:Java面试核心知识点精讲(原理篇)》技术文章大纲核心主题:Java基础原理与面试高频考点Java虚拟机(JVM)原理Java并发编程原理Jav…...