单链表的应用

文章目录

  • 目录
    • 1. 单链表经典算法OJ题目
      • 1.1 [移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/description/)
      • 1.2 [链表的中间节点](https://leetcode.cn/problems/middle-of-the-linked-list/description/)
      • 1.3 [反转链表](https://leetcode.cn/problems/reverse-linked-list/description/)
      • 1.4 [合并两个有序链表](https://leetcode.cn/problems/merge-two-sorted-lists/description/)
      • 1.5 [分割链表](https://leetcode.cn/problems/partition-list-lcci/description/)
      • 1.6 [环形链表的约瑟夫问题](https://www.nowcoder.com/practice/41c399fdb6004b31a6cbb047c641ed8a)
    • 2. 基于单链表再实现通讯录项目

目录

  • 单链表经典算法OJ题目
  • 基于单链表再实现通讯录项目

1. 单链表经典算法OJ题目

1.1 移除链表元素

移除链表元素

#include <stdio.h>typedef struct ListNode
{int val;struct ListNode* next;
}ListNode;struct ListNode* removeElements(struct ListNode* head, int val)
{//定义新链表的头尾指针ListNode* newHead, * newTail;newHead = newTail = NULL;ListNode* pcur = head;while (pcur){//不是val,尾插到新链表if (pcur->val != val){if (NULL == newHead){//链表为空newHead = newTail = pcur;}else{//链表不为空newTail->next = pcur;newTail = newTail->next;}pcur = pcur->next;}else{ListNode* del = pcur;pcur = pcur->next;free(del);del = NULL;}}if (newTail)//为了防止传过来的是空链表,newTail为空;或者链表中都是同一个值,而正好删除的是这个值,删完之后新链表中newTail依然是空{newTail->next = NULL;}return newHead;
}

1.2 链表的中间节点

链表的中间节点

typedef struct ListNode
{int val;struct ListNode* next;
}ListNode;struct ListNode* middleNode(struct ListNode* head)
{ListNode* slow, * fast;slow = fast = head;//满足任意一个条件就跳出循环while (fast && fast->next)//有一个为假都不应该进入循环{//慢指针每次走一步,快指针每次走两步slow = slow->next;fast = fast->next->next;}return slow;
}

1.3 反转链表

反转链表

#include <stdio.h>typedef struct ListNode
{int val;struct ListNode* next;
}ListNode;struct ListNode* reverseList(struct ListNode* head)
{//处理空链表if (NULL == head){return head;}//先创建三个指针ListNode* n1, * n2, * n3;n1 = NULL, n2 = head, n3 = head->next;//遍历原链表,修改节点指针的指向while (n2){//修改n2的指向n2->next = n1;//修改三个指针的位置n1 = n2;n2 = n3;if (n3){n3 = n3->next;}}return n1;
}

1.4 合并两个有序链表

合并两个有序链表

#include <stdio.h>typedef struct ListNode
{int val;struct ListNode* next;
}ListNode;struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{if (NULL == list1){return list2;}if (NULL == list2){return list1;}ListNode* l1, * l2;l1 = list1, l2 = list2;ListNode* newHead, * newTail;newHead = newTail = NULL;while (l1 && l2){if (l1->val < l2->val){//l1小,插入到新链表中if (NULL == newHead){//链表为空,头尾指针都指向该节点newHead = newTail = l1;}else{//链表不为空newTail->next = l1;newTail = newTail->next;}l1 = l1->next;}else{//l2小,插入到新链表中if (NULL == newHead){//链表为空newHead = newTail = l2;}else{//链表不为空newTail->next = l2;newTail = newTail->next;}l2 = l2->next;}}//跳出循环存在两种情况:要么l1走到空了l2不为空,要么l2走到空了l1不为空//不可能存在都为空的情况if (l1){newTail->next = l1;}if (l2){newTail->next = l2;}return newHead;
}

但是我们会发现以上代码在l1小或l2小时把数据插入到新链表中都要判断链表是否为空,出现了代码的重复,我们应该如何优化呢?

代码重复的根源在于链表可能会出现为空的情况,那么我们就创建一个头节点(这里的头就是带头链表中的头,是哨兵位,不存储有效的数值),让链表不可能存在为空的情况,就可以避免代码重复。

#include <stdio.h>
#include <stdlib.h>typedef struct ListNode
{int val;struct ListNode* next;
}ListNode;struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{if (NULL == list1){return list2;}if (NULL == list2){return list1;}ListNode* l1, * l2;l1 = list1, l2 = list2;ListNode* newHead, * newTail;newHead = newTail = (ListNode*)malloc(sizeof(ListNode));while (l1 && l2){if (l1->val < l2->val){//l1小,插入到新链表中newTail->next = l1;newTail = newTail->next;l1 = l1->next;}else{//l2小,插入到新链表中newTail->next = l2;newTail = newTail->next;l2 = l2->next;}}//跳出循环存在两种情况:要么l1走到空了l2不为空,要么l2走到空了l1不为空//不可能存在都为空的情况if (l1){newTail->next = l1;}if (l2){newTail->next = l2;}//malloc了空间,但是这块空间实际用不了,应该将其释放掉ListNode* ret = newHead->next;free(newHead);newHead = newTail = NULL;return ret;
}

1.5 分割链表

分割链表

#include <stdio.h>
#include <stdlib.h>typedef struct ListNode
{int val;struct ListNode* next;
}ListNode;struct ListNode* partition(struct ListNode* head, int x)
{if (NULL == head){return head;}//创建带头的大小链表ListNode* lessHead, * lessTail;ListNode* greaterHead, * greaterTail;lessHead = lessTail = (ListNode*)malloc(sizeof(ListNode));greaterHead = greaterTail = (ListNode*)malloc(sizeof(ListNode));//遍历原链表,将节点放到对应的新链表中ListNode* pcur = head;while (pcur){if (pcur->val < x){//放到小链表中lessTail->next = pcur;lessTail = lessTail->next;}else{//放到大链表中greaterTail->next = pcur;greaterTail = greaterTail->next;}pcur = pcur->next;}greaterTail->next = NULL;//大小链表进行首尾相连lessTail->next = greaterHead->next;ListNode* ret = lessHead->next;free(greaterHead);greaterHead = greaterTail = NULL;free(lessHead);lessHead = lessTail = NULL;return ret;
}

1.6 环形链表的约瑟夫问题

著名的Josephus问题:
据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到⼀个洞中,39个犹太人决定宁愿死也不要被人抓到,于是决定了一个自杀方式,41个人排成⼀个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下⼀个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

环形链表的约瑟夫问题

#include <stdio.h>
#include <stdlib.h>typedef struct ListNode
{int val;struct ListNode* next;
}ListNode;ListNode* BuyNode(int x)
{ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));if (NULL == newNode){perror("BuyNode");exit(1);}newNode->val = x;newNode->next = NULL;return newNode;
}ListNode* createList(int n)
{ListNode* phead = BuyNode(1);ListNode* ptail = phead;for (int i = 2; i <= n; i++){ptail->next = BuyNode(i);ptail = ptail->next;}//链表要首尾相连使其循环起来ptail->next = phead;return ptail;//返回ptail的目的是避免prev为空,解决m = 1时出现的问题;这样写既能知道第一个节点的前驱节点,也能够通过尾节点找到第一个节点
}int ysf(int n, int m)
{//创建不带头单向循环链表ListNode* prev = createList(n);//定义prev来接收尾节点指针//逢m删除节点ListNode* pcur = prev->next;int count = 1;while (pcur->next != pcur){if (m == count){//删除当前节点pcurprev->next = pcur->next;free(pcur);//删除pcur节点之后,要让pcur走到新的位置,count置为初始值pcur = prev->next;count = 1;}else{//pcur往后走prev = pcur;pcur = pcur->next;count++;}}//此时pcur节点就是幸存下来的唯一的一个节点return pcur->val;
}

2. 基于单链表再实现通讯录项目

这里基于单链表实现通讯录项目和之前基于顺序表实现通讯录项目的步骤大致相同,思路是相通的,因此可以参考之前顺序表的应用这篇文章。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/312724.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CTFHUB-技能树-Web前置技能-文件上传(无验证,JS前端验证,前端验证)

CTFHUB-技能树-Web前置技能-文件上传&#xff08;无验证&#xff0c;JS前端验证&#xff0c;前端验证—.htaccess&#xff09; 文章目录 CTFHUB-技能树-Web前置技能-文件上传&#xff08;无验证&#xff0c;JS前端验证&#xff0c;前端验证—.htaccess&#xff09;文件上传无验…

GPT-3.5和GPT-Plus的区别

GPT-3.5和GPT-Plus都是OpenAI开发的大型语言模型,但它们之间有一些区别: GPT-3.5就是大家熟知的ChatGPT GPT-Plus 是Open AI 的更强的AI模型GPT-4版本。两者区别是&#xff1a; 模型规模:GPT-Plus是GPT-3的一个更大版本,参数量更多。而GPT-3.5是GPT-3的一个优化版本,在参数量…

✌粤嵌—2024/3/11—跳跃游戏

代码实现&#xff1a; 方法一&#xff1a;递归记忆化 int path; int used[10000];bool dfs(int *nums, int numsSize) {if (path numsSize - 1) {return true;}for (int i 1; i < nums[path]; i) {if (used[path i]) {continue;}path i;used[path] 1;if (dfs(nums, num…

双指针的引入和深入思考(持续更新中)

目录 1.引入双指针 2.使用场景 3.例题引入 1.引入双指针 当我们需要维护某个区间性质的或者是求满足某些性质的区间的长度时&#xff0c;对于一个区间是由左右端点的&#xff0c;我们有简单的枚举左右端点的O()的时间的做法&#xff0c;当时在大多数题目中是不可行的&#…

百度OCR身份证识别C++离线SDKV3.0 C#对接

百度OCR身份证识别C离线SDKV3.0 C#对接 目录 说明 效果 问题 项目 代码 下载 说明 自己根据SDK封装了动态库&#xff0c;然后C#调用。 SDK 简介 本 SDK 适应于于 Windows 平台下的⾝份证识别系统,⽀持 C接⼜开发的 SDK,开发者可在VS2015 下⾯进⾏开发&#xff08;推荐…

Day08React——第八天

useEffect 概念&#xff1a;useEffect 是一个 React Hook 函数&#xff0c;用于在React组件中创建不是由事件引起而是由渲染本身引起的操作&#xff0c;比如发送AJAx请求&#xff0c;更改daom等等 需求&#xff1a;在组件渲染完毕后&#xff0c;立刻从服务器获取频道列表数据…

Appium的使用:混合APP切换上下文

网上别的文章说要把移动端的webview设置成调试模式,才能看到下图信息。 但我这里是直接在Android Studio新建了一个空白活动,然后放的webview控件,写的webview代码,直接部署到模拟器上,在确定adb可以连接到模拟器后,在桌面浏览器输入chrome://inspect/#devices后就可以看…

【代码】Python3|Requests 库怎么继承 Selenium 的 Headers (2024,Chrome)

本文使用的版本&#xff1a; Chrome 124Python 12Selenium 4.19.0 版本过旧可能会出现问题&#xff0c;但只要别差异太大&#xff0c;就可以看本文&#xff0c;因为本文对新老版本都有讲解。 文章目录 1 难点解析和具体思路2 注意事项2.1 PDF 资源获取时注意事项2.2 Capabiliti…

IntelliJ IDEA配置类注释模板和方法注释模板

配置类注释模板和方法注释模板 IDEA模板预定义变量类注释模方法注释模板方法参数优化 IDEA模板 在IDEA中&#xff0c;自带的注释模板可能不满足自身需求或者不满意&#xff0c;此时可以通过配置IDEA模板来解决。 预定义变量 内置模板是可编辑的&#xff0c;除了静态文本、代码和…

关于Git的一些基础用法

关于Git的一些基础用法 1. 前言2. 使用GitHub/gitee创建项目2.1 创建账号2.2 创建项目2.3 下载仓库到本地2.4 提交代码到远端仓库2.5 查看日志2.6 同步远端仓库和本地仓库 1. 前言 首先说一个冷知识&#xff08;好像也不是很冷&#xff09;&#xff0c;Linux和git的创始人是同…

Python贡献度分析(帕累托分析)

贡献度分析又称帕累托分析&#xff0c;它的原理是帕累托法则&#xff0c;又称20/80定律。同样的投入放在不同的地方会产生不同的效益。例如&#xff0c;对一个公司来讲&#xff0c;80%的利润常常来自于20%最畅销的产品&#xff0c;而其他80%的产品只产生了20%的利润 对餐饮企业…

【Leetcode每日一题】 分治 - 颜色分类(难度⭐⭐)(57)

1. 题目解析 题目链接&#xff1a;75. 颜色分类 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 2.算法原理 算法思路解析 本算法采用三指针法&#xff0c;将数组划分为三个区域&#xff0c;分别用于存放值为0、1和2的元素。通过…

Promise模块化编程ES6新特性

文章目录 Promise&模块化编程1.Promise基本介绍2.快速入门1.需求分析2.原生ajax jQuery3.Promise使用模板 3.课后练习1.原生ajax jQuery2.promise 4.模块化编程基本介绍5.CommonJS基本介绍6.ES5模块化编程1.题目2.示意图3.代码实例—普通导入导出function.jsuse.js 4.代码…

Spring容器结构

文章目录 1.基本介绍1.Spring5官网2.API文档3.Spring核心学习内容4.几个重要概念 2.快速入门1.需求分析2.入门案例1.新建Java项目2.导入jar包3.编写Monster.java4.src下编写Spring配置文件1.创建spring配置文件&#xff0c;名字随意&#xff0c;但是需要放在src下2.创建Spring …

C语言-指针

1. 指针是什么 指针理解的2个要点&#xff1a; 1.1. 指针是内存中一个最小单元的编号&#xff0c;也就是地址 1.2 平时口语中说的指针&#xff0c;通常指的是指针变量&#xff0c;是用来存放内存地址的变量 总结&#xff1a;指针就是地址&#xff0c;口…

电力系统卫星授时信号安全隔离装置防护方案

电力系统是国家关键基础设施&#xff0c; 电力安全关系国计民生&#xff0c; 是国家安全的重要保障&#xff0c; 与政治安全、经济安全、 网络安全、社会安全等诸多领域密切关联。电网运行情况瞬息万变&#xff0c;为了在其发生事故时能够及时得到处理&#xff0c;需要统一的时…

2.6 类型安全配置属性

无论是Propertes配置还是YAML配置&#xff0c;最终都会被加载到Spring Environment中。 Spring提供了注解Value以及EnvironmentAware接口来将Spring Environment 中的数据注入到属性上&#xff0c;SpringBoot对此进一步提出了类型安全配置属性(Type-safeConfiguration Propert…

【华为笔试题汇总】2024-04-17-华为春招笔试题-三语言题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是KK爱Coding &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为近期的春秋招笔试题汇总&#xff5e; &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f…

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第五套

华为海思校园招聘-芯片-数字 IC 方向 题目分享——第五套 (共9套&#xff0c;有答案和解析&#xff0c;答案非官方&#xff0c;仅供参考&#xff09;&#xff08;共九套&#xff0c;每套四十个选择题&#xff09; 部分题目分享&#xff0c;完整版获取&#xff08;WX:didadida…

OSPF的P2P和Broadcast

OSPF为什么会有P2P和BROADCAST两种类型 OSPF&#xff08;开放最短路径优先&#xff09;协议中存在P2P&#xff08;点对点&#xff09;和BROADCAST&#xff08;广播多路访问&#xff09;两种网络类型&#xff0c;主要是为了适应不同类型的网络环境和需求。具体分析如下&#xf…