【数据结构与算法】单链表的综合运用:1.合并两个有序链表 2.分割链表 3.环形链表的约瑟夫问题

【数据结构与算法】单链表的综合运用:1.合并两个有序链表 2.分割链表 3.环形链表的约瑟夫问题
在这里插入图片描述
🔥小龙报:个人主页
🎬作者简介:C++研发,嵌入式,机器人等方向学习者
❄️个人专栏:《C语言》《【初阶】数据结构与算法》
永远相信美好的事情即将发生
在这里插入图片描述

文章目录


前言

链表是C语言数据结构的核心内容,也是算法面试的高频考点,其灵活的指针操作与逻辑构建对编程思维要求颇高。本文聚焦链表经典实操题型,从合并有序链表、分割链表到环形链表约瑟夫问题,由浅入深拆解解题思路,结合哨兵位、循环计数等实用技巧,通过清晰的算法原理与完整代码实现,帮读者吃透链表操作逻辑,夯实数据结构基础。

一、合并两个有序链表

1.1题目

链接:合并两个有序链表

在这里插入图片描述

1.2 算法原理

核心:判断大小 + 链表为插 + 建立一个哨兵位
和合并两个有序数组的思路一样,定义四个指针
newhead和newtail:新链表的头尾节点
pcur1和pcur2:分别指向两个要合并的链表的头节点
技巧:可以malloc一块空间让newhead和newtail指向这块空间,使其成为首元节点(哨兵位),这样在插入时可以免去链表为空情况的判断,最后返回新链表的下一个节点即可。
哨兵位:数值域不存储有效数据,指针域存储有效地址

1.3代码

/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ typedef structListNode ListNode;structListNode*mergeTwoLists(structListNode* list1,structListNode* list2){ ListNode* newhead =(ListNode*)malloc(sizeof(ListNode)); ListNode* pcur1 = list1;; ListNode* pcur2 = list2; ListNode*newtail = newhead; newtail->next = NULL;while(pcur1 && pcur2){if(pcur1->val <= pcur2->val){ newtail->next = pcur1; newtail = newtail->next; pcur1 = pcur1->next;}else{ newtail->next = pcur2; newtail = newtail->next; pcur2 = pcur2->next;}}//为遍历完的链表直接接上新链表尾部节点if(pcur1) newtail->next = pcur1;if(pcur2) newtail->next = pcur2;return newhead->next;}

注:大家也可以free掉我们手动开辟的节点空间来养成良好的编程习惯,因为这是算法题,在程序执行完后会会自动回收笔者主要讲解思路,就不主动free但大家在写工程时不要的空间要及时释放养成良好编程习惯

二、分割链表

2.1题目

链接:分割链表

在这里插入图片描述

2.2 算法原理

创建两个新链表,list1和list2分别存放小于x和大于或等于x的节点,最后让list1的尾指针指向list2的第一个元素即可。
:list2作为新链表的后半部分,最后一个节点的next要及时置NILL,防止死循环
技巧:依旧可以使用哨兵位,并把哨兵位的next初始化为NULL可以避免合并时一条链表为空的特殊判断造成要写大量特判代码。

2.3代码

/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ typedef structListNode ListNode;structListNode*partition(structListNode* head,int x){if(head == NULL)return head;//指向小于x链表的头节点 ListNode* list1 =(ListNode*)malloc(sizeof(ListNode)); ListNode* tail1 = list1;//指向大于x链表的头节点 ListNode* list2 =(ListNode*)malloc(sizeof(ListNode)); ListNode* tail2 = list2;//防止单个节点链表出现非法解引用 list1->next = NULL; list2->next = NULL; ListNode* pcur = head;while(pcur){if(pcur->val < x){ tail1->next = pcur; tail1 = tail1->next;}else{ tail2->next = pcur; tail2 = tail2->next;} pcur = pcur->next;} tail1->next = list2->next;//防止死循环 tail2->next = NULL;return list1->next;}

注:大家也可以free掉我们手动开辟的节点空间来养成良好的编程习惯,因为这是算法题,在程序执行完后会会自动回收笔者主要讲解思路,就不主动free但大家在写工程时不要的空间要及时释放养成良好编程习惯

三、环形链表的约瑟夫问题

3.1题目

链接:环形链表的约瑟夫问题

在这里插入图片描述

3.2 算法原理

核心:利用循环链表 + 循环计数
定义一个指针v指尾节点,一个指针指向头结点,利用一个变量s来循环技术,当s == m时让h指向的当前元素出队即可

在这里插入图片描述

3.3代码

typedef structListNode ListNode;//创建节点 ListNode*BuyNode(int x){ ListNode* newnode =(ListNode*)malloc(sizeof(ListNode)); newnode->val = x; newnode->next = NULL;return newnode;}//创建环形链表 ListNode*CyclicList(int n){ ListNode* head =BuyNode(1); ListNode* tail = head;for(int i =2;i <= n;i++){ tail->next =BuyNode(i); tail = tail->next;} tail->next = head;return tail;}intysf(int n,int m ){ ListNode* prev =CyclicList(n); ListNode* phead = prev->next;int count =1;//计数while(phead != prev){if(count == m){ prev->next = phead->next;free(phead); phead = prev->next; count =1;}else{ prev = phead; phead = phead->next; count++;}}return phead->val;}

总结与每日励志

✨本文系统讲解了链表操作的三大经典题型:合并有序链表通过哨兵位简化插入逻辑,分割链表采用双链表分类处理,环形链表约瑟夫问题巧妙结合循环计数。每种解法均配有清晰的算法图解和完整代码实现,帮助读者深入理解链表操作的核心逻辑与实用技巧。掌握这些题型不仅能提升面试竞争力,更能培养扎实的数据结构思维。坚持每日练习,保持对算法的热情与专注,终将在编程之路上收获成长与突破。永远相信美好的事情即将发生!

在这里插入图片描述

Read more

【算法】计算程序执行时间(C/C++)

【算法】计算程序执行时间(C/C++)

引言 我们在写算法时要考虑到算法的执行效率,有的题目规定了时间限制,我们需要在这个时间之内去解决问题。如果我们需要比对算法的好坏,就需要输出这个程序运行了多长时间。 在C或C++中计算程序执行时间,可以使用多种方法,下面我介绍几种比较常见且好用的几种方法,大家可以选择适合自己的一种记住就可以了。 方法1:使用 clock() 函数(C/C++) 在C/C++中,<time.h>库提供了clock()函数。这个方法是博主比较推荐的一个,非常简便,且易懂,它用于测量程序的CPU时间。clock() 函数返回程序从启动到函数被调用时所经过的时钟周期数。这个函数主要用于测量程序的CPU时间消耗,而不是实际的墙钟时间(即从墙上的时钟测量的时间)。 函数原型 clock_t clock(void); * clock_t 类型,表示自程序启动以来的时钟周期数。  使用实例: 以下是使用clock()函数计算递归与非递归程序执行时间的示例代码: #include<iostream&

By Ne0inhk
TOON:一种为大模型设计的JSON压缩型数据结构

TOON:一种为大模型设计的JSON压缩型数据结构

目录 TOON:一种为大模型设计的JSON压缩型数据结构 一、精准定义,什么是 TOON? 1、JSON 数据格式的局限性 2、TOON 的结构与优势 3、TOON 数据结构的主要特征 4、媒体类型与文件拓展名 二、举例:JSON 与 TOON 描述同一组数据分别是什么样 三、结语         作者:watermelo37         ZEEKLOG优质创作者、华为云云享专家、阿里云专家博主、腾讯云“创作之星”特邀作者、火山KOL、支付宝合作作者,全平台博客昵称watermelo37。         一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。 --------------------------------------------------------------------- 温柔地对待温柔的人,包容的三观就是最大的温柔。 ---------------------------------------------------------------------

By Ne0inhk
算法王冠上的明珠——动态规划之路径问题(第一篇)

算法王冠上的明珠——动态规划之路径问题(第一篇)

目录 1. 什么叫路径类动态规划 一、核心定义(通俗理解) 二、核心特征(识别这类问题的关键) 2. 动态规划步骤 状态表示 状态转移方程 初始化 填表顺序 返回值 3. 例题讲解 3.1 LeetCode62. 不同路径 3.2 LeetCode63. 不同路径 II 3.3 LeetCodeLCR 166. 珠宝的最高价值 今天我们来聊一聊动态规划的路径类问题。 1. 什么叫路径类动态规划 路径类动态规划是 动态规划的一个重要分支,核心解决 “从起点到终点的路径相关问题”—— 比如 “路径总数”“最短路径长度”“路径上的最大 / 最小和” 等,其本质是通过 “状态递推” 避免重复计算,高效求解多阶段决策的路径问题。 一、

By Ne0inhk
【数据结构】常见时间复杂度以及空间复杂度

【数据结构】常见时间复杂度以及空间复杂度

时间复杂度与空间复杂度 * 一、复杂度的概念 * 二、时间复杂度 * 1、大O的渐进表示法 * 2、函数clock计算运算时间 * 3、常见复杂度对比 * 3.1常数项复杂度 * 3.2线性时间复杂度 * 案例1 * 案例2 * 3.3平方阶复杂度 * 3.4对数复杂度 * 3.5递归函数 * 单递归 * 双递归 * 三、空间复杂度 * 冒泡排序O(1) * 三个反置O(N) 一、复杂度的概念 * 一个算法的好坏,主要是对比两者的时间和空间两个维度,也就是时间和空间复杂度。 * 时间复杂度主要衡量一个算法运行的快慢,空间复杂度主要衡量一个算法运行需要的额外空间 二、时间复杂度 * 算法的时间复杂度是一个函数式T(N),算法中的基本操作的执行次数,为算法的时间复杂度。 * 注:编译器的不同,编译所需要的时间也不同。越新的编译器,编译的时间往往比旧的编译器快 * 当一个算法函数式为T(

By Ne0inhk