单链表经典算法

一,移除链表元素

思路一

遍历数组,如果遇到链表中的元素等于val的节点就执行删除操作

typedef struct ListNode ListNode;
 
 struct ListNode* removeElements(struct ListNode* head, int val) {
  
    if(head==NULL)
    {
        return NULL;
    } 
     ListNode*pnewhead=(ListNode*)malloc(sizeof(ListNode));
    pnewhead->next=head;
    ListNode*pcur=head;
    ListNode*prev=pnewhead;
    while(pcur)
    {
        if(pcur->val==val)
        {
            prev->next=pcur->next;
            free(pcur);
            pcur=NULL;
            pcur=prev->next;
        }
        else
        {
            prev=pcur;
            pcur=pcur->next;
            
        }
    }
    return pnewhead->next;
 }

思路二

建立一个新的链表,遇到的节点里面存的数据如果不等于val的值的话就将这个节点尾插到建立的新的链表的后面

typedef struct ListNode ListNode;
 struct ListNode*removeElement(struct ListNode*head,int val)
 {
    ListNode*pcur=head;
    ListNode*newhead,*newtail;//建立新的链表
    newhead=newtail=NULL;
    while(pcur)//遍历链表
    {
        if(pcur->val!=val)
        {
            if(newhead==NULL)
            {
                newhead=newtail=pcur;//新链表为空,将当前的节点赋值给新的链表
            }else
            {
                newtail->next=pcur;//不为空,插到新链表的后面
                newtail=newtail->next;
            }
        }
        pcur=pcur->next;
    }
    if(newtail)//如果链表的不为空的话,就让尾节点的后面为空
    {
        newtail->next=NULL;
    }
    return newhead;
 }
 

代码说明

 if(newtail)//如果链表的不为空的话,就让尾节点的后面为空
 {
     newtail->next=NULL;
 }

因为链表在插入的时候,当前节点的后面还有节点,插入的时候会后面的节点会跟在后面,所以要将原链表的尾节点的后面的节点置为空,比如下面的

当要将上面的链表中的4处于的节点的位置插入到下面0位于的节点的后面,插入的不是4,而是4和4链接的5位于的节点,插入的是后面的一串,这和顺序表不一样 

二.反转链表

思路

这里可以定义三个指针,一个指向当前节点,一个指向当前节点的上一个节点,一个指向当前节点的下一个节点,直接让当前节点指向上一个节点

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
    ListNode*prev=NULL;//前驱节点
    ListNode*pcur=head;//当前节点
    ListNode*back=NULL;//当前节点的下一个节点
     if(head==NULL)
    {
        return NULL;
    }
   
    if(head->next==NULL)
    {
        return head;
    }
    while(pcur)
    {
        pcur->next=prev;
         prev=pcur;
        pcur=back;
        if(back!=NULL){
        back=back->next;
        }
    }
    return prev;
}

三.将两个升序链表合并成为一个新的升序链表

思路:定义一个新的无效链表头(里面没有数据,在后续的程序中不需要判断该链表是否是空链表,能够对代码进行优化,有返回值的时候直接返回这个链表头的下一个节点就可以了),以及两个指针,分别指向两个升序链表,比较两个链表里面的值,谁小就把谁放到新链表的后面,然后这个指针指向下一个节点就行了

typedef struct ListNode ListNode;
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    ListNode*pcur1=list1;//定义指针1
    ListNode*pcur2=list2;//定义指针2
    if(list1==NULL)
    {
        return list2;//为空链表的话返回另一个链表
    }
    if(list2==NULL)
    {
        return list1;//为空的话返回另一个链表
    }
    ListNode*phead=(ListNode*)malloc(sizeof(ListNode));
    ListNode*pcur3=phead;
    while(pcur1&&pcur2)
    {
        if(pcur1->val<=pcur2->val)
        {
            pcur3->next=pcur1;
            pcur3=pcur3->next;
            pcur1=pcur1->next;
        }
        else
        {
             pcur3->next=pcur2;
            pcur3=pcur3->next;
            pcur2=pcur2->next;
        }
    }
    if(pcur2==NULL)
    {
        pcur3->next=pcur1;//插入的是该节点以及该节点后面的节点,一步到位
    }
    if(pcur1==NULL)
    {
       
       pcur3->next=pcur2;
    }
    return phead->next;

}

四.链表的中间节点

思路:定义两个指针,一个快指针,一个慢指针,满指针一次走一格,快指针一次走两格,最后返回慢指针就行了

typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
    ListNode*fast,*slow;
    fast=head,slow=head;
    if(head->next==NULL)
    {
        return head;
    }
    while(fast&&fast->next)
    {
        slow=slow->next;
        
        fast=fast->next->next;
            
        
    }
    return slow;
    
}

五,分割链表

思路:定义两个新的链表,遍历原链表,原链表里面的节点里面的值和x比较,小的尾插在第一个链表后面,大于等于的尾插在第二个链表的后面,最后连接两个链表

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){
  ListNode*pcur=head;
  ListNode*pcur1=(ListNode*)malloc(sizeof(ListNode));
  ListNode*pcur2=(ListNode*)malloc(sizeof(ListNode));
  ListNode*head1=pcur1;
  ListNode*head2=pcur2;
  if(head==NULL)
  {
    return NULL;
  }
  if(head->next==NULL)
  {
    return head;
  }

  while(pcur)
  {
    if(pcur->val<x)
    {
        pcur1->next=pcur;
        pcur1=pcur1->next;
    }
    else
    {
        pcur2->next=pcur;
        pcur2=pcur2->next;
    }
    pcur=pcur->next;
  }
  pcur2->next=NULL;
  pcur1->next=head2->next;
 return head1->next;
}

 注意:上面的代码为什么要有下面的这句话嘞?

pcur2->next=NULL;

 原因是插入链表节点的时候,后面带着的节点是跟在本节点的后面的,插的时候就顺带着了,本节点后面不置为空就会造成死循环

六.环形链表的约瑟夫问题 

什么是环形链表的约瑟夫问题,先看一看下面的故事:

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

第一步:创建一个环形链表

第二部:定义一个变量,初值为1,如果该变量不等于m,该变量加1,继续遍历链表,等于,删除该节点,变量重新等于1

typedef struct ListNode ListNode;
//产生一个节点
 ListNode*buynode(int x)
 {
    ListNode*newnode=(ListNode*)malloc(sizeof(ListNode));
    newnode->val=x;
    newnode->next=NULL;
    return newnode;
 }
//建立一个环形链表
 ListNode*creatcircle(int n)
 {
    ListNode*phead=buynode(1);
    ListNode*pcur=phead;
    phead->val=1;
    for(int i=2;i<=n;i++)
    {
        pcur->next=buynode(i);
        pcur=pcur->next;
        
    }
   pcur->next=phead;
   return phead;
 }
int ysf(int n, int m )
 {
   
    ListNode*phead=creatcircle(n);
    ListNode*pcur=phead;
    ListNode*prev=NULL;
    int count=1;
    while(pcur->next!=pcur)
    {
        if(count==m)
        {
            prev->next=pcur->next;
            free(pcur);
            pcur=NULL;
            count=1;
            pcur=prev->next;
        }
        else 
        {
            prev=pcur;
            pcur=pcur->next;
            count++;
        }
        
    }
    return pcur->val;
}

七.结语

在链表中,最值得注意的是,尾插链表,插入的是该节点和该节点后面的节点,也就是一串节点

在插入链表的时候,记得要将该节点后面置为空

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

14.集合、常见的数据结构

集合 概念 Java中的集合就是一个容器&#xff0c;用来存放Java对象。 集合在存放对象的时候&#xff0c;不同的容器&#xff0c;存放的方法实现是不一样的&#xff0c; Java中将这些不同实现的容器&#xff0c;往上抽取就形成了Java的集合体系。 Java集合中的根接口&#x…

MVC和DDD的贫血和充血模型对比

文章目录 架构区别MVC三层架构DDD四层架构 贫血模型代码示例 充血模型代码示例 架构区别 MVC三层架构 MVC三层架构是软件工程中的一种设计模式&#xff0c;它将软件系统分为 模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xff08;Contro…

前端工程化03-贝壳找房项目案例JavaScript常用的js库

4、项目实战&#xff08;贝壳找房&#xff09; 这个项目包含&#xff0c;基本的ajax请求调用,内容的渲染&#xff0c;防抖节流的基本使用&#xff0c;ajax请求工具类的封装 4.1、项目的接口文档 下述接口文档&#xff1a; 简述内容baseURL&#xff1a;http://123.207.32.32…

SQL——高级教程【菜鸟教程】

SQL连接 左连接&#xff1a;SQL LEFT JOIN 关键字 左表相当于主表&#xff0c;不管与右表匹不匹配都会显示所有数据 右表就只会显示和左表匹配的内容。 //例显示&#xff1a;左表的name&#xff0c;有表的总数&#xff0c;时间 SELECT Websites.name, access_log.count, acc…

【机器学习-15】决策树(Decision Tree,DT)算法介绍:原理与案例实现

前言 决策树算法是机器学习领域中的一种重要分类方法&#xff0c;它通过树状结构来进行决策分析。决策树凭借其直观易懂、易于解释的特点&#xff0c;在分类问题中得到了广泛的应用。本文将介绍决策树的基本原理&#xff0c;包括熵和信息熵的相关概念&#xff0c;以及几种经典的…

上位机开发PyQt5(二)【单行输入框、多行输入框、按钮的信号和槽】

目录 一、单行输入框QLineEdit QLineEdit的方法&#xff1a; 二、多行输入框QTextEdit QTextEdit的方法 三、按钮QPushButton 四、按钮的信号与槽 信号与槽简介&#xff1a; 信号和槽绑定&#xff1a; 使用PyQt的槽函数 一、单行输入框QLineEdit QLineEdit控件可以输入…

双向链表专题

文章目录 目录1. 双向链表的结构2. 双向链表的实现3. 顺序表和双向链表的优缺点分析 目录 双向链表的结构双向链表的实现顺序表和双向链表的优缺点分析 1. 双向链表的结构 注意&#xff1a; 这⾥的“带头”跟前面我们说的“头节点”是两个概念&#xff0c;带头链表里的头节点…

Redis 实战1

SDS Redis 只会使用 C 字符串作为字面量&#xff0c; 在大多数情况下&#xff0c; Redis 使用 SDS &#xff08;Simple Dynamic String&#xff0c;简单动态字符串&#xff09;作为字符串表示。 比起 C 字符串&#xff0c; SDS 具有以下优点&#xff1a; 常数复杂度获取字符串…

JavaEE >> Spring MVC(2)

接上文 本文介绍如何使用 Spring Boot/MVC 项目将程序执行业务逻辑之后的结果返回给用户&#xff0c;以及一些相关内容进行分析解释。 返回静态页面 要返回一个静态页面&#xff0c;首先需要在 resource 中的 static 目录下面创建一个静态页面&#xff0c;下面将创建一个静态…

[嵌入式系统-53]:嵌入式系统集成开发环境大全 ( IAR Embedded Workbench(通用)、MDK(ARM)比较 )

目录 一、嵌入式系统集成开发环境分类 二、由MCU芯片厂家提供的集成开发工具 三、由嵌入式操作提供的集成开发工具 四、由第三方工具厂家提供的集成开发工具 五、开发工具的整合 5.1 Keil MDK for ARM 5.2 IAR Embedded Workbench&#xff08;通用&#xff09;、MDK&…

01.本地工作目录、暂存区、本地仓库三者的工作关系

1.持续集成 1.持续集成CI 让产品可以快速迭代&#xff0c;同时还能保持高质量。 简化工作 2.持续交付 交付 3.持续部署 部署 4.持续集成实现的思路 gitjenkins 5.版本控制系统 1.版本控制系统概述2.Git基本概述3.Git基本命令 2.本地工作目录、暂存区、本地仓库三者的工作关系…

抖音评论区精准获客自动化获客释放双手

挺好用的&#xff0c;评论区自动化快速获客&#xff0c;如果手动点引流涨&#xff0c;那就很耗费时间了&#xff0c;不是吗&#xff1f; 网盘自动获取 链接&#xff1a;https://pan.baidu.com/s/1lpzKPim76qettahxvxtjaQ?pwd0b8x 提取码&#xff1a;0b8x

leetcode84柱状图中最大的矩形

题解&#xff1a; - 力扣&#xff08;LeetCode&#xff09; class Solution {public int largestRectangleArea(int[] heights) {Stack<Integer> stack new Stack<>();int maxArea Integer.MIN_VALUE;for(int i 0;i < heights.length;i){int curHeight hei…

YOLOV8添加SKATTENTION

修改ultralytics.nn.modules._init_.py https://zhuanlan.zhihu.com/p/474599120?utm_sourcezhihu&utm id0 https://blog.csdn.net/weixin 42878111/article/details/136060087 https://blog.csdn.net/gg 51511878/aricle/details/138002223 . 最后输出层不一样。

JAVA面试之MQ

如何保证消息的可靠传输&#xff1f;如果消息丢了怎么办 数据的丢失问题&#xff0c;可能出现在生产者、MQ、消费者中。 &#xff08;1&#xff09;生产者发送消息时丢失&#xff1a; ①生产者发送消息时连接MQ失败 ②生产者发送消息到达MQ后未找到Exchange(交换机) ③生产者发…

一对一WebRTC视频通话系列(一)—— 创建页面并显示摄像头画面

本系列博客主要记录WebRtc实现过程中的一些重点&#xff0c;代码全部进行了注释&#xff0c;便于理解WebRTC整体实现。 一、创建html页面 简单添加input、button、video控件的布局。 <html><head><title>WebRTC demo</title></head><h1>…

单片机编程实例400例大全(100-200)

今天继续分享单片机编程实例第100-200例。 今天的实例会比前面100复杂一些&#xff0c;我大概看了下&#xff0c;很多都具备实际产品的参考价值。 今天继续分享单片机编程实例第100-200例。 今天的实例会比前面100复杂一些&#xff0c;我大概看了下&#xff0c;很多都具备实际…

计算机毕业设计hadoop+spark+hive知识图谱音乐推荐系统 音乐数据分析可视化大屏 音乐爬虫 LSTM情感分析 大数据毕设 深度学习 机器学习

黄河科技学院本科毕业设计 任务书 工 学部 大数据与计算机应用 科教中心 计算机科学与技术 专业 2018 级普本1/专升本1班 学号 学生 指导教师 毕业设计题目 基于实时音乐数据挖掘的个性化推荐系统设计与优化 毕业设计工作内容与基本…

频分复用系统设计及其MATLAB实现

引言 随着通信技术的飞速发展&#xff0c;通信系统的容量需求不断增长。频分复用&#xff08;Frequency Division Multiplexing, FDM&#xff09;作为一种重要的多路复用技术&#xff0c;被广泛应用于现代通信系统中。本文将介绍频分复用系统的设计原理&#xff0c;并展示如何…

【Docker学习】docker start深入研究

docker start也是很简单的命令。但因为有了几个选项&#xff0c;又变得复杂&#xff0c;而且... 命令&#xff1a; docker container start 描述&#xff1a; 启动一个或多个已停止的容器。 用法&#xff1a; docker container start [OPTIONS] CONTAINER [CONTAINER...] 别名&…
最新文章