数据结构——链表(练习题)

news2024/12/21 23:35:30

大家好,我是小锋我们继续来学习链表。

我们在上一节已经把链表中的单链表讲解完了,大家感觉怎么样我们今天来带大家做一些练习帮助大家巩固所学内容。

1. 删除链表中等于给定值 val 的所有结点

. - 力扣(LeetCode)

我们大家来分析一下这个题,我们能想到的思路有两种,1,删除 2,插入

第一种,我们直接一个一个找当找到val我们就删除,然后继续重复下去。

第二种,我们创建一个新的头节点并沿着原节点一个一个走下去如果不是val我们就在新的头节点尾插。

第一种

#include<stdlib.h>
 struct ListNode* removeElements(struct ListNode* head, int val) {
     struct ListNode* ps = head;
     while (ps)
     {
         if (ps->val == val)
         {
             head = head->next;
             ps->next = NULL;
             ps = head;
         }
         else
         {
             struct ListNode* pt = ps->next;
             if (pt) 
             {
                 if (pt->val == val)
                 {
                     ps->next = pt->next;
                     pt->next = NULL;
                 }
                 else
                 {
                     ps = ps->next;
                 }

             }
             else 
             {
                 ps = ps->next;
             }
         }
     }
     return head;
 }

第二种

#include<stdlib.h>
 struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* pt=NULL;
    struct ListNode* ps=NULL;
    struct ListNode* cur=head;
    while(cur){
        if(cur->val==val){
            cur=cur->next;
        }
        else{
            if(ps){
                pt->next=cur;
                cur=cur->next;
                pt=pt->next;
                pt->next=NULL;
            }
            else{
                 ps=cur;
                cur=cur->next;
                ps->next=NULL;
                pt=ps;
            }
        }
    }
    return ps;
 }

反转一个单链表

. - 力扣(LeetCode)

我们大家来分析这道题,有很多种思路这里我向大家推荐两种

1,我们将链表的朝向改变让最后一个节点变成表头,然后依次改变每个节点的指向就完成了反转

2,我们找到最后一个节点然后依次将每个节点尾插。

第一种

# include<stdio.h>
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode*ps=head;
    if(ps){
    struct ListNode*pt=ps->next;
    while(pt)
    {
         struct ListNode*cur=pt->next;
        if(ps==head)
        {
            pt->next=ps;
            ps->next=NULL;
            ps=pt;
            pt=cur;
        }
        else
        {
            pt->next=ps;
            ps=pt;
            pt=cur;
        }
    }
    }
    else{
        return NULL;
    }
    return ps;
}

第二种

# include<stdio.h>
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode*ps=NULL;
    struct ListNode*cur=head;
    struct ListNode*pt=NULL;
    struct ListNode*tall=NULL;
    if(cur)
    {
        while(cur)
        {
            if(cur->next){
        while(cur->next->next)
        {
            cur=cur->next;
        }
        tall=cur;
        cur=cur->next;
        tall->next=NULL;
        }
        else
        {
            head=NULL;
        }
        if(ps)
        {
            
             pt->next=cur;
            pt=pt->next;
        }
        else
        {
            ps=cur;
            pt=ps;
        }
        cur=head;
    }
    }
    else
    {
        return NULL;
    }
    return ps;
}

返回链表的中间结点

. - 力扣(LeetCode)

这一道题的思路也有很多,我们这里主要用快慢指针的思路来解决

我们创建两个指针,都指向头节点,然后一个指针一次走两步,一个指针一次走一步当快的指针走到最后一个节点是慢的指针刚好走到中间节点。

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

输入一个链表,输出该链表中倒数第k个结点

这道题的思路在头节点定义两个指针先让一个指针先走k个然后再一起走当其中一个指针走到链表末尾时另一个指针就在倒数第k个。

typedef struct ListNode ListNode;
 struct ListNode {
     int val;
    struct ListNode *next;
 };
 

 struct ListNode* middleNode(int k, struct ListNode* head) {
	 struct ListNode* ps = head;
	 struct ListNode* pt = head;
	 if (head) {
		 while (k) {
			 if (ps) {
				 ps = ps->next;
			 }
			 else {
				 break;
			 }
			 k--;
		 }
		 while (ps) {
			 ps = ps->next;
			 pt = pt->next;
		 }
	 }
	 else {
		 return NULL;
	 }
	 if (k<=0) {
		 return pt;
	 }
	 else {
		 return NULL;
	 }
 }

下面这个是测试函数

int main() {
	 ListNode* n1 = (ListNode*)malloc(sizeof(ListNode));
	assert(n1);
	ListNode* n2 = (ListNode*)malloc(sizeof(ListNode));
	assert(n2);
	ListNode* n3 = (ListNode*)malloc(sizeof(ListNode));
	assert(n3);
	ListNode* n4 = (ListNode*)malloc(sizeof(ListNode));
	assert(n4);
    ListNode* n5 = (ListNode*)malloc(sizeof(ListNode));
    assert(n5);
	n1->val = 1;
	n2->val = 2;
	n3->val = 3;
    n4->val = 4;
    n5->val = 5;
	n1->next = n2;
	n2->next = n3;
	n3->next = n4;
    n4->next = n5;
    n5->next = NULL;
	ListNode* add= middleNode(6,NULL);
	if (add)
		printf("%d", add->val);
	else
		printf("NULL");


	return 0;
}

有序链表合并

. - 力扣(LeetCode)

这道题的解题思路

创建一个新的头节点然后建立两个指针分别指向两个升序链表对比两个节点的val,选小的尾插选中的那个节点的指针指向下一个节点,最后还没有走完的指针将全部节点都尾插。

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
     struct ListNode*ps=NULL;
    struct ListNode*cur=NULL;
    if(list1==NULL)
    return list2;
    if(list2==NULL)
    return list1;
    while(list1&&list2){
        if(list1->val>list2->val){
            if(ps){
                cur->next=list2;
                cur=cur->next;
                list2=list2->next;
            }
            else{
                ps=list2;
                cur=ps;
                list2=list2->next;
            }
        }
        else{
            if(ps){
                cur->next=list1;
                cur=cur->next;
                list1=list1->next;
            }
            else{
                ps=list1;
                cur=ps;
                list1=list1->next;
            }
        }
    }
    if(list1){
        cur->next=list1;
    }else{
        cur->next=list2;
    }
    return ps;
}

链表分割

这一道题我想的思路是创建一个头节点,把小于x的节点在原链表中删除后尾插该节点,然后在把该链表与原链表连接。

但是还有一种更好的方法,我们直接创建两个头节点分别尾插大于x和小于x的节点最后再连接。

无疑这一种方法更为简单。

我们来试试

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        ListNode*ps,*pt,*psd,*ptd;
        psd=ps=(ListNode*)malloc(sizeof(int)+sizeof(ListNode*));
        ptd=pt=(ListNode*)malloc(sizeof(int)+sizeof(ListNode*));
        ListNode*cur=pHead;
        while(cur){
        if(cur->val<x){
            psd->next=cur;
            psd=cur;
        }
        else{
            ptd->next=cur;
            ptd=cur;
        }
        cur=cur->next;
        }
        psd->next=pt->next;
        ptd->next=NULL;
        pHead=ps->next;
        free(ps);
        free(pt);
        return pHead;
    }
};

链表的回文结构

这一道题我们可以找到链表的中间节点把中间节点后面的反转然后从头与尾向中间比较如果都一样那么就是回文结构了。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        ListNode*ps=A;
        ListNode*pt=A;
        while(ps&&ps->next){
            ps=ps->next->next;
            pt=pt->next;
        }
        ListNode*cur=pt;
        ListNode*list=cur->next;
        ListNode*add=list->next;
        while(list){
            list->next=cur;
            cur=list;
            list=add;
            if(add)
            add=add->next;
        }
        pt->next=NULL;
        ListNode*are=A;
        while(cur){
            if(are->val!=cur->val){
                return false;
            }
            else{
            are=are->next;
            cur=cur->next;
            }
        }
        return true;
    }
};

相交链表

这道题我们的思路是分别找出长的链表与短的链表节点个数然后用长的节点数减去短的节点数得到的数就是长的链表比短的链表多出的节点个数然后创建两个指针long,short,long先走多出的个数然后再一起走当long与short指向的next相等时就找到了相交节点。

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int a=0;
    int b=0;
    int n=0;
    struct ListNode *cut=headA;
    while(cut->next){
        a++;
        cut=cut->next;
    }
    cut=headB;
    while(cut->next){
        b++;
        cut=cut->next;
    }
    struct ListNode *longg=headA;
    struct ListNode *shortt=headB;
    if(a<b){
        n=b-a;
         while(n--){
        shortt=shortt->next;
    }
    }
    else{
        n=a-b;
         while(n--){
        longg=longg->next;
    }
    }
    while(longg&&shortt){
        if(longg==shortt){
            return longg;
        }
        else{
             longg=longg->next;
             shortt=shortt->next;
        }
    }
    return NULL;
}

判断环形链表

让我们来看看这道题,我的思路是快慢指针,类似追击问题,我们创建两个指针一个指针以一次两个节点的速度走下去,一个指针一次一个节点走下去,如果是有环的链表那么指针一定会相交,如果不是环形链表那么快的会遇到NULL。

bool hasCycle(struct ListNode *head) {
    struct ListNode *quick=head;
    struct ListNode *siow=head;
    while(quick&&quick->next){
        quick=quick->next->next;
        siow=siow->next;
        if(quick==siow){
            return true;
        }
    }
    return false;  
}

找环形链表入口

先说一个结论:

让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环
运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇
这样看这道题是不是清晰明了
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *quick=head;
    struct ListNode *siow=head;
    while(quick&&quick->next){
        quick=quick->next->next;
        siow=siow->next;
        if(quick==siow){
            struct ListNode *ps=head;
            while(quick!=ps){
                quick=quick->next;
                ps=ps->next;
            }
            return ps;
        }

    }
    return NULL;
}

接下来大家思考几个问题

快指针一次走 3 步,走 4 步, ...n 步行吗?

  以上就是全部内容了,如果有错误或者不足的地方欢迎大家给予建议。 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

十四、MySQL日志之 binlog日志

目录 一、二进制日志&#xff08;Binary log&#xff09; 1、binlog主要应用场景&#xff1a; 2、查看默认情况 3、日志参数设置 &#xff08;1&#xff09;永久设置 &#xff08;2&#xff09;临时性设置 4、查看日志 5、删除二进制日志 总结&#xff1a; 一、二进制日…

【JavaWeb】Day23.maven——依赖管理

依赖管理 一.依赖配置 依赖&#xff1a;指当前项目运行所需要的jar包。一个项目中可以引入多个依赖。 例如&#xff1a;在当前工程中&#xff0c;我们需要用到logback来记录日志&#xff0c;此时就可以在maven工程的pom.xml文件中&#xff0c;引入logback的依赖。具体步骤如…

docker容器内存检测排查

查询容器使用内存 在运维当中&#xff0c;你会发现内存很彪的高&#xff0c;但是如何判断为什么会高&#xff0c;是什么样的程序造成的呢&#xff1f;赶快使用 top&#xff0c;或者 free -h或者 ps -v。是吗&#xff1f;道理是对的。 但是你会发现&#xff0c;全部都是docker…

探索Python人工智能在气象监测中的创新应用

Python是功能强大、免费、开源&#xff0c;实现面向对象的编程语言&#xff0c;在数据处理、科学计算、数学建模、数据挖掘和数据可视化方面具备优异的性能&#xff0c;这些优势使得Python在气象、海洋、地理、气候、水文和生态等地学领域的科研和工程项目中得到广泛应用。可以…

linux网络服务学习(4):SAMBA

1.什么是SAMBA SAMBA也是一种文件共享工具 &#xff08;1&#xff09;服务名&#xff1a;smb &#xff08;2&#xff09;软件名&#xff1a;samba &#xff08;3&#xff09;配置文件&#xff1a; /etc/samba/smb.conf /etc/samba/smb.conf.example &#xff08;4&#…

牛客NC26 括号生成【中等 递归 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/c9addb265cdf4cdd92c092c655d164ca 思路 答案链接&#xff1a;https://www.lintcode.com/problem/427/solution/16924 参考答案Java import java.util.*;public class Solution {/*** 代码中的类名、方法名、参…

#Linux(make工具和makefile文件以及makefile语法)

&#xff08;一&#xff09;发行版&#xff1a;Ubuntu16.04.7 &#xff08;二&#xff09;记录&#xff1a; &#xff08;1&#xff09;make为编译辅助工具&#xff0c;解决用命令编译工程非常繁琐的问题 &#xff08;2&#xff09;在终端键入make即可调用make工具&#xff0…

学习JavaEE的日子 Day29 yield,join,线程的中断,守护线程,线程局部变量共享,线程生命周期

Day29 多线程 12. 线程的礼让 Thread.yield(); 理解&#xff1a;此方法为静态方法&#xff0c;此方法写在哪个线程中&#xff0c;哪个线程就礼让 注意&#xff1a;所谓的礼让是指当前线程退出CPU资源&#xff0c;并转到就绪状态&#xff0c;接着再抢 需求&#xff1a;创建两个…

P8764 [蓝桥杯 2021 国 BC] 二进制问题

很板的一道题目&#xff0c;注意就是数组别开的太小 #include<bits/stdc.h> using namespace std; using ll long long; using pii pair<int,int>; #define int long long const int N 1e510; const int inf 0x3f3f3f3f; const int mod 1e97; int gcd(int a,…

【81-100】计算机网络基础知识(非常详细)从零基础入门到精通,看完这一篇就够了

【81-100】计算机网络基础知识&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了 以下是本文参考的资料 欢迎大家查收原版 本版本仅作个人笔记使用81、对于FIN_WAIT_2&#xff0c;CLOSE_WAIT状态和TIME_WAIT状态&#xff1f;你知道多少?82、你…

算法第三十四天-有效数独

有效数独 题目要求 解题思路 一个简单的方法是&#xff0c;遍历9*9书读三次&#xff0c;以确保&#xff1a; 行中没有重复的数字列中没有重复的数字3*3子数独中没有重复的数字 但是&#xff0c;实际上&#xff0c;所有的一切都以可以在一次迭代中完成 可以使用box_index (r…

Kubernetes Gateway API 介绍

Kubernetes Gateway API 诞生背景 在 kubernetes 中&#xff0c;流量的治理主要分为两个部分&#xff1a; 南北向流量东西向流量 南北向流量&#xff08;NORTH-SOUTH traffic&#xff09; 在计算机网络中&#xff0c;南北向流量通常指数据流量从一个**内部网络&#xff08;…

20231911马星 2022-2023-2 《网络攻防实践》实验四

1.实践内容 在网络攻防实验环境中完成TCP/IP协议栈重点协议的攻击实验&#xff0c;包括ARP缓存欺骗攻击、ICMP重定向攻击、SYN Flood攻击、TCP RST攻击、TCP会话劫持攻击。 1.1 ARP欺骗攻击&#xff1a; &#xff08;1&#xff09;ARP欺骗&#xff08;ARP spoofing&#xff09…

【算法-PID】

算法-PID ■ PID■ 闭环原理■ PID 控制流程■ PID 比例环节&#xff08; Proportion&#xff09;■ PID 积分环节&#xff08;Integral&#xff09;■ PID 微分环节&#xff08;Differential&#xff09; ■ PID PID 分别是 Proportion&#xff08;比例&#xff09;、 Integr…

如何购买小程序模板开发企业小程序

在当今数字化时代&#xff0c;小程序已成为企业展示与营销的重要工具。购买一个小程序模板&#xff0c;来快速上线自己的企业小程序&#xff0c;已成为当前最流行且性价比最高的开发方式。 乔拓云网站提供了丰富的小程序模板资源&#xff0c;无论你需要哪种风格或功能的小程序&…

WOT全球技术创新大会2024北京站:技术派与市场派共话AIGC新未来

WOT全球技术创新大会2024将在北京盛大开幕&#xff0c;聚焦AIGC时代的软件工程新范式、AI Agent探索与应用、多模态AIGC前沿探索以及大模型部署与应用等核心议题。此次大会将促进技术信仰派与市场信仰派间的深度对话与交流&#xff0c;共同探讨AIGC技术的未来发展方向。 在过去…

【Java程序设计】【C00351】基于Springboot的疫情居家办公系统(有论文)

基于Springboot的疫情居家办公系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 项目获取 &#x1f345;文末点击卡片获取源码&#x1f345; 开发环境 运行环境&#xff1a;推荐jdk1.8&#xff1b; 开发工具&#xff1a;eclipse以及i…

Flask python 开发篇:上传文件(在指定目录下创建文件夹)

flask上传文件以及常见问题 一、flask文档上传文件的介绍二、上传文件的实现2.1、生成一个from表单&#xff0c;用来提交图片2.2、编写上传的逻辑 三、运行代码、以及常见异常四、写在最后 一、flask文档上传文件的介绍 Flask上传文件的文档介绍&#xff0c;文件上传的基本思想…

快递鸟物流轨迹地图API接口,包裹行程尽在掌握!

在快节奏的现代生活中&#xff0c;物流行业作为连接生产者与消费者的桥梁&#xff0c;其重要性不言而喻。随着电子商务的飞速发展&#xff0c;人们对物流信息的实时性和准确性要求越来越高。为了满足这一需求&#xff0c;快递鸟物流轨迹地图API应运而生&#xff0c;为广大用户提…

WIFI驱动移植实验: wireless tools 工具测试

一. 简介 前面一篇文章交叉编译了 wireless tools 工具&#xff0c;并移植到开发板文件系统上。文章如下&#xff1a; WIFI驱动移植实验&#xff1a; wireless tools 工具移植-CSDN博客 本文对 所移植的操作 WIFI设备的工具 wireless tools进行测试。确认是否可以使用。 二…