【追求卓越03】数据结构--链表练习题

引导

        链表是我们工作和面试的中常常会遇到的知识点,只有长时间的练习和思考才能游刃有余。故总结以下几个比较经典的链表题和对应的代码,进行参考。

链表的反转

思路:

  1. 将链表遍历,将每个节点拷贝一份,之后再将所有的节点反向链接。该方法简单,但是我并不喜欢。因为空间复杂度为O(n),时间复杂度也为O(n).
  2. 利用递归,将先遍历到最后节点,再返回,将每个节点的指向上一个节点。头节点指向null。

#include<stdlib.h>
typedef struct node{
     int num;
     struct node * next;
}Node;
int insertnode(Node* head,Node* newNode)
{
        if(head == NULL)
        {
                printf("head is null,insert fail\n");
            return -1;
        }
        Node* temp = head;
        while(temp->next!= NULL)
        {
            temp = temp->next;
        }
        temp->next = newNode;
    return 0;
}
int print_list(Node* head)
{
        while(head!=NULL)
        {
            printf("%d\n",head->num);
                head = head->next;
        }
    return 0;
}
Node* rollback(Node* head)
{
        Node* temp = head->next;
        Node* newhead = NULL;
        if(temp != NULL)
        {
           newhead = rollback(temp);
        }
        else
        {
                return head;
        }
        temp->next = head;
        head->next = NULL;
    return newhead;
}
int main()
{
        Node * head = (Node*)malloc(sizeof(Node));
        head->num = 1;
        head->next = NULL;
    int i = 0;
        for(i = 2 ; i < 5 ; i ++)
        {
            Node * NewNode = (Node*)malloc(sizeof(Node));
                NewNode->num = i;
                NewNode->next = NULL;
                insertnode(head,NewNode);
        }       
        print_list(head);
        Node* Newhead = rollback(head);
        print_list(Newhead);
        return 0;
}

单向链表中环的检测

        该题,我觉得可以拓展到以下三个问题:

  1. 1.检测链表中是否存在环?
  2. 2.能够求出环的长度?
  3. 3.能否求出起始点到环入口的长度?

检测链表中是否存在环

思路:

  1. 使用快慢指针,快指针指向NULL时,则不存在环;若快指针和慢指针重合,则说明有环

#include<stdlib.h>
typedef struct node{
        int num;
        struct node * next;
}Node;
int insertnode(Node* head,Node* newNode)
{
        if(head == NULL)
        {
                printf("head is null,insert fail\n");
            return -1;
        }
        Node* temp = head;
        while(temp->next!= NULL)
        {
            temp = temp->next;
        }
        temp->next = newNode;
    return 0;
}
int print_list(Node* head)
{
        while(head!=NULL)
        {
            sleep(1);
            printf("%d\n",head->num);
            head = head->next;
        }
    return 0;
}
int ring_check(Node* head)
{
    int result = -1;
    Node* fast=head;
    Node* slow=head;
    while(fast != NULL)
    {
        if(slow->next != NULL)
        slow = slow->next;
       if(fast->next != NULL && fast->next->next != NULL)
       fast = fast->next->next;
       else
       break;
       if(slow == fast)
       {
           printf("number = %d\n",slow->num);
           result = 1;
           break;
       }
    }
    return result;
}
int main()
{
        Node * head = (Node*)malloc(sizeof(Node));
        head->num = 1;
        head->next = NULL;
        Node * temp = NULL;
        int i = 0;
        for(i = 2 ; i < 2 ; i ++)
        {
                Node * NewNode = (Node*)malloc(sizeof(Node));
                NewNode->num = i;
                NewNode->next = NULL;
                insertnode(head,NewNode);
                if(i == 14)/
*
决定环的入口点*
/
                {
                        temp = NewNode;
                }
                if(i == 19)
                {
                        NewNode->next = temp;
                }
        }
        int resulte = ring_check(head);
        //print_list(head);
        if(resulte == 1)
        {
            printf("list exist ring\n");
        }
        else
        {
            printf("list don't exit ring\n");
        }
        return 0;
}

求出环的长度

思路:

  1. 建立在问题一的基础之上:
  2. 当第一次相遇之后,说明该链表存在环。
  3. 而快慢指针从一个环中同一点进行移动,下一次相遇就是链表的长度。

int ring_len(Node* head)
{
    int first = -1;
    int len = 0;
    Node* fast=head;
    Node* slow=head;
    while(fast != NULL)
    {
       if(slow->next != NULL)
       slow = slow->next;
       if(fast->next != NULL && fast->next->next != NULL)
           fast = fast->next->next;
       else
               break;
       if(first == 1)
          len ++;
       if(slow == fast)
       {
           printf("number = %d\n",slow->num);
           if(first == -1)
           {
               first = 1;
           }
           else
           break;
       }
    }
    return len;
}

计算头节点到入口点的距离

思路:
依据:快指针和慢指针相遇时,慢指针肯定还没有超过整个链表长度。而快指针应该是超过链表加上nr(n,表示正整数,r表示环的长度)
现做这样的假设:
链表的整个长度是L
头节点到入口点的距离为a
第一次相遇点距离入口点为X,并走了s步
得到以下公式:
2s -s = nr
x+a = s
可以得到a= (n-1)r + (r-x)
其中r-x表示相遇点到入口点的距离。
故:head节点,第一次相遇节点分别出发。再次相遇肯定是入口点

Node* ring_meet(Node* head)
{
 Node* resulte = NULL;
 Node* fast=head;
 Node* slow=head;
 while(fast != NULL)
 {
    if(slow->next != NULL)
    slow = slow->next;
       if(fast->next != NULL && fast->next->next != NULL)
           fast = fast->next->next;
       else
           return resulte;
       if(slow == fast)
       {
           printf("number = %d\n",slow->num);
           break;
       }
    }
    resulte = head;
    int len = 0;
    while(resulte != slow)
    {
        resulte= resulte->next;
        slow = slow->next;
        len++;
    }
    printf("len = %d\n",len);
    return resulte;
}

如何判断两个链表是否相交

该问题其实就是环检测的变种。只要将其中一个链表尾节点指向头节点。再检测另一条链表中是否存在环即可。

两个有序的链表合并

思路:

遍历其中一个链表,将节点与另一链表进行比较,进行插入。

Node * list_merge(Node*L1 , Node*L2)
{
    Node * head= (Node*)malloc(sizeof(Node));
    Node* cur = head;
    while(L1 != NULL && L2 != NULL)
    {
        if(L1->num <= L2->num )
        {
            cur->next = L1;
            L1 = L1->next;
        }
        else
        {
            cur->next = L2;
            L2 = L2->next;
        }
        cur=cur->next;
    }
    if(L1 == NULL)
    {
       cur->next=L2;
    }
    if(L2 == NULL)
    {
       cur->next=L1;
    }
    return head->next;
}

删除链表中指定节点

思路:

  1. 遍历链表,当遇到节点相同的,便删除对应节点。这样的事件复杂度为O(n)
  2. 将节点的下一个节点赋值为本节点,之后指向node->next->next;这个思路的时间复杂度是O(1)。但是你需要考虑节点的位置;
  3. 在链表头
  4. 在链表尾
  5. 在链表中间

int delete_node(Node* head,Node* delete)
{
    if(delete==NULL )
    {
        return 0;
    }
    if(delete->next == NULL)
    {
        /
*last node*
/
        while(head->next != delete)
        {
                head=head->next;
        }
        head->next = NULL;
        free(delete);
        return 0;
    }
    delete->num = delete->next->num;
    Node * temp = delete->next;
    delete->next = delete->next->next;
    free(temp);
    return 0;
}

平均复杂度为O(1)。

求链表中的中间节点

思路:(当链表长度为偶数,取相邻两个节点的第一个)

  1. 遍历链表,找到尾节点。并记录链表长度。再从头结点遍历,达到中间节点即可。这种方式事件复杂度为O(n),空间复杂度O(1)。但感觉太low了,并不喜欢。
  2. 使用快慢指针,当快指针达到尾节点时,慢节指针肯定是在中间节点

Node* mid_node(Node* head)
{
    if(head == NULL)
    {
        return NULL;
    }
    Node* fast=head;
    Node* slow = head;
    while(fast->next != NULL && fast->next->next != NULL)
    {
        fast=fast->next->next;
        slow=slow->next;
    }
    return slow;
}

约瑟夫问题

约瑟夫问题,是我偶然看到的一个算法题。感觉很有意思,就记录下来了。

故事:

        据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

        该问题拓展很多,这里我给出的问题,有100个人,每数到3,就剔除,输出剔除顺序。

例如: 123456

输出:364251

思路:

        实现起来应该是很简单的,就是有N个节点的环,从头节点开始,依次数数,当数到3时,就将节点删除,一直重复到只有一个节点。

int Joseph(Node* head)
{
    int i = 1;
    if(head ==NULL)
    {
         printf("list is empty\n");
    }
    while(head->next != head)
    {
        i++;
        if(i%3 == 0)
        {
             i=1;
             Node* temp = head->next;
             head->next = head->next->next;
             printf("%d\n",temp->num);
             free(temp);
        }
        head=head->next;
    }
    printf("last is %d\n",head->num);
}

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

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

相关文章

向日葵x华测导航:远程控制如何助力导航测绘设备运维

导航测绘在各个领域均在发挥积极作用&#xff0c;其中RTK载波相位差分技术是导航测绘领域所常用的主流技术&#xff0c;该技术基于卫星定位系统的基础定位数据&#xff0c;可以实现在野外实时获取厘米级精度的定位数据&#xff0c;一定程度上省去了事后解算的麻烦。相应的&…

XSLVGL2.0 User Manual 外设管理器(v2.0)

XSLVGL2.0 开发手册 XSLVGL2.0 User Manual 外设管理器 1、概述2、特性3、APIs3.1、xs_peripherals_listen3.2 xs_peripherals_unlisten3.3、xs_peripherals_register_prepost3.4 xs_peripherals_unregister_prepost3.5 xs_peripherals_access3.6、xs_peripherals_set_valid_t…

(论文阅读46-50)图像描述2

46.文献阅读笔记 简介 题目 Learning a Recurrent Visual Representation for Image Caption Generation 作者 Xinlei Chen, C. Lawrence Zitnick, arXiv:1411.5654. 原文链接 http://www.cs.cmu.edu/~xinleic/papers/cvpr15_rnn.pdf 关键词 2014年rnn图像特征和文本特…

验证码 | 可视化一键管控各场景下的风险数据

目录 查看今日验证数据 查看未来趋势数据 验证码作为人机交互界面经常出现的关键要素&#xff0c;是身份核验、防范风险、数据反爬的重要组成部分&#xff0c;广泛应用网站、App上&#xff0c;在注册、登录、交易、交互等各类场景中发挥着巨大作用&#xff0c;具有真人识别、身…

Leo赠书活动-10期 【AIGC重塑教育 AI大模型驱动的教育变革与实践】文末送书

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…

新手做抖店,这6点建议一定要收好,能让你不亏钱!

我是电商珠珠 我呢&#xff0c;目前身居郑州。 电商这个行业也做了5年多了&#xff0c;抖店从20年开始做&#xff0c;到现在也已经快3年了。 其实&#xff0c;我做抖店期间呢&#xff0c;踩过很多坑&#xff0c;所以今天就把我所踩过的坑&#xff0c;给做抖店的新手总结了6点…

QT mysql 数据库线程池 与数据库操作封装

最近事情比较多很久没有写学习笔记了&#xff0c;数据库线程池&#xff0c; 数据库封装&#xff0c;虽说数据库操作有很多不需要写sql 的&#xff0c;ORM 封装的方式去操作数据库。但是从业这些年一直是自己动手写sql &#xff0c;还是改不了这个习惯。不说了直接上代码。 数据…

【23真题】劝退211!今年突变3门课!

今天分享的是23年云南大学847&#xff08;原827&#xff09;的考研试题及解析。同时考SSDSP的院校做一个少一个&#xff0c;珍惜&#xff01;同时考三门课的院校&#xff0c;复习压力极大&#xff0c;但是也会帮大家劝退很多人&#xff0c;有利有弊&#xff0c;请自行分析~ 本…

YOLOv5 环境搭建

YOLOv5 环境搭建 flyfish 环境 Ubuntu20.04 驱动、CUDA Toolkit、cuDNN、PyTorch版本对应 1 NVIDIA驱动安装 在[附加驱动界]面安装驱动时&#xff0c;需要输入安全密码&#xff0c;需要记下&#xff0c;后面还需要输入这个密码 重启之后有的机器会出现 perform mok manage…

二十三种设计模式-解密状态模式:优雅地管理对象状态

在软件开发中&#xff0c;经常会遇到需要根据对象的状态来改变其行为的情况。传统的实现方式可能涉及到大量的条件语句或者使用标志位来跟踪状态&#xff0c;导致代码复杂、难以维护。 而状态模式&#xff08;State Pattern&#xff09;可以提供一种优雅且灵活的解决方案&#…

Android修行手册-溢出父布局的按钮实现点击

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

【EI会议征稿】第五届人工智能、网络与信息技术国际学术会议(AINIT 2024)

第五届人工智能、网络与信息技术国际学术会议&#xff08;AINIT 2024&#xff09; 2024 5th International Seminar on Artificial Intelligence, Networking and Information Technology 第五届人工智能、网络与信息技术国际学术会议&#xff08;AINIT 2024&#xff09;将于…

Java File

SpringBoot get file path 通過ClassLoader獲得class path&#xff0c;Debug 或者 Release 不同。 加載Bean file ImportResource(locations {“classpath:bean-spring.xml”}) get file Value(“classpath:data/input.txt”) private Resource inputResource; ClassPat…

MongoDB——golang操作(链接,CURD,聚合)

MongoDB golang操作 中文文档 链接 package mainimport ("context""fmt""log""go.mongodb.org/mongo-driver/mongo""go.mongodb.org/mongo-driver/mongo/options" )func main() {// 设置客户端连接配置clientOptions : o…

变态跳台阶,剑指offer

目录 题目&#xff1a; 我们直接看题解吧&#xff1a; 相似题目&#xff1a; 解题方法&#xff1a; 审题目事例提示&#xff1a; 解题思路&#xff1a; 代码实现&#xff1a; 题目地址&#xff1a; 【剑指Offer】9、变态跳台阶 难度&#xff1a;简单 今天刷变态跳台阶&#xf…

sd-webui-controlnet代码分析

controlnet前向代码解析_Kun Li的博客-CSDN博客文章浏览阅读1.5k次。要分析下controlnet的yaml文件&#xff0c;在params中分成了4个部分&#xff0c;分别是control_stage_config、unnet_config、first_stage_config、cond_stage_config。其中control_stage_config对应的是13层…

Maven依赖管理项目构建工具(保姆级教学---下篇)

对于Maven依赖管理项目构建工具的介绍&#xff0c;我们将其分为上篇和下篇。如果您对文章感兴趣&#xff0c;您可以在此链接中找到上篇详细内容&#xff1a; Maven依赖管理项目构建工具&#xff08;保姆级教学上篇&#xff09;-CSDN博客 一、Maven依赖传递和依赖冲突 1. …

left join查询耗时太慢,添加索引解决问题

背景 因为最近自己用的小app越用感觉加载越慢&#xff0c;以为是自己app开发逻辑出现问题了&#xff0c;结果才发现是自己很早以前的代码用到的是left join多表联查&#xff0c;以前因为数据少&#xff0c;所以没有感觉&#xff0c;现在数据量稍微一大&#xff0c;耗时就非常严…

珠宝饰品配送经营小程序商城作用如何

饰品有较强的价值/品牌之分&#xff0c;贵的上万元&#xff0c;便宜的几毛钱&#xff0c;适应不同消费群体和需求&#xff0c;对于珠宝类商家及小饰品商家来说&#xff0c;市场中都有着海量用户。 相较于以前等客上门&#xff0c;用户们的消费方式只有同城&#xff0c;如今互联…

psutil - Python中用于进程和系统监控的跨平台库

1、简介 psutil&#xff08;进程和系统实用程序&#xff09;是一个跨平台库&#xff0c;用于检索 Python 中运行的进程和系统利用率&#xff08;CPU、内存、磁盘、网络、传感器&#xff09;的信息。 它主要用于系统监控、分析和限制进程资源以及管理正在运行的进程。 它实现…