顺序表和链表对应的经典算法

news2024/9/25 16:31:30
一,移除元素

思路:定义一个循环遍历数组,如果遇到的不是val就记录下来这个元素,如果不是就跳过

定义两个指针,一个用于保留非val元素,一个用于遍历nums

int removeElement(int* nums, int numsSize, int val)
{
      int*pst=nums;//用于遍历的指针
      int*prev=nums;//用于保留元素的指针
      int size = 0;//被保留下来的元素个数
  
      for(int i=0;i<numsSize;i++ )
      {
            if(pst[i]!=val)
            {
                prev[size]=pst[i];
                size++;
            }
      }
      return size;//题目要求只要返回保留的元素个数即可
}

二,合并两个有序数组

思路:边合并边排序

思路一:指定三个标记

               L1=m-1;

               L2=n-1;

               L3=m+n-1;

从后向前比较L1对应的数据与L2对应的数据的大小,谁大就把谁放在L3处,每次比较完,大的数据对应的标记向前走一个,L3也向走一个,最后会有两种情况

一种是L1对应的数据全部放入后三个空位,此时L1已经走到头部对应1的位置,L2还没有全部放入大的数组里面,因为数组是非递减排列的,所以最后只需将剩下L2所有元素一一放入大数组。

一种是L2对应的数据全部放入后三个空位,此时在大数组所有元素均已有序。

void merge(int*nums1,int nums1Size,int m,int*nums2,int nums2Size,int n)
{
    int L1=m-1;
    int L2=n-2;
    int L3=m+m-1;
    while(L1>=0&&L2>=0)
    {
        if(nums1[L1]>nums2[l2])
        {
            nums1[L3]=nums1[L1];
            L3--;
            L1--;
        }
        else
        {
            nums1[L3]=nums2[L2];
            L3--;
            L2--;
        }
    }
    while(L2>=0)//此时L1对应数据全部放入尾部,因为两数组均是递增,所以直接将nums2放入尾部即可
    {
        nums1[L3]=nums2[L2];
        L3--;
        L2--;
    }
}

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

分析:

本题需要有一个能够循环遍历的链表,并且每次数到第m个数都需要删除该节点。

int ysf(int n, int m ) 这个是题目给我们的函数,按照题目意思,我们需要在此函数里循环遍历链 表,删除m节点;

首先我们需要自己创建一个函数,这个函数能够将每个人包装成节点,其次还需要一个函数可以将每个节点连接起来。

包装节点函数可以这样写

#include<stdio.h>
#include<stdlib.h>
typedef struct ListNode ListNode;//将结构体重命名方便使用
 
ListNode*Newnode(int m)
{
    ListNode*newnode=(ListNode*)malloc(sizeof(ListNode));
    if(newnode==NULL)
    {
        perror("newnode");//如果开辟空间失败及时报错
        exit(1);//退出
    }
    //开辟成功,将m值放入放入节点
    newnode->val=m;
    newnode->next=NULL;//将指向下一节点的指针置空避免野指针
    return newnode;
}

有了包装节点的函数,

还需一个可以将其连接起来的函数

ListNode*Contact(int n) //一共有n个人,也就是n个节点
{
    ListNode*phead=Newnode(1);//先定一个头节点作为链表的头指向第一个人
    ListNode*cur=phead;//在cur中保留一份链表头节点
    int i = 0;
    for(i=2;i<=n;i++)从第二个人开始链结
    {
        ListNode*next = Newnode(i);
        cur->next=next;//使cur链接下一节点
        cur=cur->next;//使cur向后移动,作为新创建的节点
    }
    //到这里cur已成为尾节点
    cur->next=phead;//使尾节点的下一节点为头节点,成为循环链表
    return cur;//返回尾节点

}

这里有个疑惑,为什么我不返回头节点,而返回一个尾节点呢,因为在最后的主函数中要循环链表,如果返回头节点那么还没有循环时就已经是第一个人了,刚向下走一步就已经是第二个人了,不方便计数。

下面是主函数的定义

int ysf(int n,int m)
{
    int count = 1;//用来计数第几个人
    ListNode*prev=Newnode(m); //prev为尾节点
    ListNode*pcur=prev->next;//pcur为头节点
    while(pcur->next!=cpur)//开始循环,终止条件是下一个节点指向自己,说明只剩一个人
    {
        if(count==m)
        {
            //此时pcur为要删除的节点
            prev->next=pcur->next//使前置节点prev的下一节点指向pcur后一节点
            free(pcur);//删除当前节点
            pcur=prev->next;//使pcur重新指向被删除节点的后一节点
        }
        else
        {
            prev=pcur;//prev始终为pcur的前一节点
            pcur=pcur->next;
            count++; //既然不是要删的节点,就pcur指向下一个节点,count增加
        }
    }
//最后只剩下一人,返回它对应的人
    return pcur->val              
}

最后将三段代码合并即可


四,链表的中间节点

本题可以有两个思路,只介绍思路二。

思路一:寻常方法一一遍历计算节点个数找到中间节点

思路二:算法思想:快慢指针法,定义两个指针,当快指针走到尾节点或者NULL, 慢指针刚好走到中间节点。

如何使快指针走到尾,慢指针刚好是中间节点呢?可以使快指针每次走两步,慢指针每次走一步。


typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
    ListNode*fast,*slow;
    fast=slow=head;  //两个指针均从头开始
    while(fast&&fast->next)
    {
        slow=slow->next;//一次走一步
        fast=fast->next->next;//一次走两步
    }
    return slow;
}

五,合并两个有序链表

分析:

由两个链表合并为一个链表,我们可以创建第三个链表来存放。

定义三个指针,其中两个指针去遍历链表,哪个指针指向的节点较小,就将其放入第三个指针指向指向的链表中,被放入节点的指针向后移动一个单位。

typedef struct ListNode ListNode;

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    ListNode*L1=list1;
    ListNode*L2=list2;
    ListNode*newhead=NULL;
    ListNode*newptail=newhead;
    while(L1&&L2)
    {
        if(L1->val < L2->val)
        {
            if(newhead==NULL)// 如果新链表还没有放入节点,直接是其头尾指针指向第一个节点
            {
                newhead=newptail=L1;
                L1=L1->next;//被放入节点的指针向后移动
            }
            else
            {       //新链表中已经放入元素,直接尾节点指向被放入的节点,
                    //使被放入的节点为新的尾节点。
                newptail->next = L1;
                newptail = newptail->next;
                L1=L1->next;
            }
        }
        else
        {
            if(newhead==NULL)
            {
                newhead=newptail=L2;
                L2 = L2->next;
            }
            else
            {
                newptail->next = L2;
                newptail = newptail->next;
                L2=L2->next;
            }
        }
    }
    if(L1) //如果L1指向的链表还有元素未被放完,直接其尾插新的链表
    {
        newptail->next = L1;
    }
    if(L2) //如果L2指向的链表还有元素未被放完,直接其尾插新的链表
    {
        newptail->next = L2;
    }
    return newhead;
}
六,反转链表

分析:

一般单链表的性质就是单项连接不循环的,先要反转链表可能会不太好想。

这里有一种非常让人难以想到的方法:

可以定义三个指针,分别指向NULL,第一个节点和第三个节点。

以第二个指针不为空,也就是走到最后一个节点就结束为条件

每循环一次就是第一个指针指向第二个指针的节点,

然后第二个指针指向第三个指针的节点,最后第三个指针向后移动一个单位

这样一来就可以使链表反向。上面只展示循环的一个过程啦,后面的过程照着这样循环,

最后n2和n3都会为空,而n1会变成指向5节点的指针。

下面是代码:短小精悍

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode*head)
{
    if(head==NULL)
    {
        return head;
    }
    ListNode*n1=NULL;
    ListNode*n2=head;
    ListNode*n3=head->next;
    while(n2)
    {
        n2->next=n1;
        n1=n2;
        n2=n3;
        if(n3)
        {
           n3=n3->next;
        }
    }
    return n1;
}
七,移除链表元素

思路:

这题可以创建一个新的链表,在创建一个指针指向原来的链表,遍历原来的链表,只要是要删除的值就跳过,如果不是要删除的值,就把对应的节点尾插给新链表

typedef struct ListNode ListNode;

struct ListNode* removeElements(struct ListNode* head, int val) {
  
  if(head==NULL)
    {
        return  head;
    }
    ListNode*NewHead=NULL;
    ListNode*NewTail=NULL;
    ListNode*pcur=head;
    while(pcur)
    {
     if(pcur->val!=val)
     {
        //链表为空
        if(NewHead==NULL)
        {
            NewHead=NewTail=pcur;
        }
        else
        {     //不为空
            NewTail->next=pcur;//使新链表的尾节点为pcur
            NewTail=NewTail->next;//使NewTail指向尾节点
        }
     }
     pcur=pcur->next;
    }
    if(NewTail)//至关重要的一步
    {
        NewTail->next=NULL;//最后尾节点nxet要置为空,否则
        //新链表最后的元素会粘连原链表
    }
    return NewHead;
}

以上几题蕴含着一些巧妙的算法思想,希望对各位有帮助。

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

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

相关文章

基于WordPress开发微信小程序1:搭建Wordpress

2年前&#xff0c;在知乎上提问&#xff1a;多数公司为什么宁愿自研也不用wordpress二次开发建站&#xff1f; - 知乎 (zhihu.com)&#xff0c;收到了&#xff0c;很多回答 自己打算做一下提升&#xff0c;便有了自己基于wordpress开发微信小程序的想法 项目定位 基于wordpre…

ruoyi(若依)(el-menu也可参考)菜单栏过长显示省略号才显示气泡

一、背景 若依前后端分离的版本&#xff0c;新版本中优化了菜单名称过长悬停显示标题&#xff0c;但是是悬浮所有长度大于5的标题。可以查看提交记录&#xff1a;https://gitee.com/y_project/RuoYi-Cloud/commit/99932d91c0144da9f34f5bb05683cc0b86303217 但是我希望是只悬浮…

centos6和centos7无网络环境下安装fontconfig,配置中文字体

以centos6为例 1、查看系统版本 cat /etc/redhat-release 2、访问https://vault.centos.org下载相关rpm包 找到对应系统版本 3、下载相应的rpm包上传到服务器 dejavu-fonts-common-2.33-1.el6.noarch.rpm dejavu-sans-fonts-2.33-1.el6.noarch.rpm fontconfig-2.8.0-5.el6.…

【Python小游戏】五子棋小游戏(完整代码)

文章目录 写在前面Tkinter简介五子棋小游戏游戏介绍程序设计运行结果注意事项写在后面写在前面 本期内容:基于tkinter开发一个五子棋小游戏 实验环境 python3.11及以上pycharmtkinterTkinter简介 Tkinter是Python中最常用的图形用户界面(GUI)库之一,用于创建窗口、对话框…

Day 1. 学习linux高级编程之Shell命令和IO

1.C语言基础 现阶段学习安排 2.IO编程 多任务编程&#xff08;进程、线程&#xff09; 网络编程 数据库编程 3.数据结构 linux软件编程 1.linux&#xff1a; 操作系统&#xff1a;linux其实是操作系统的内核 系统调用&#xff1a;linux内核的函数接口 操作流程&#xff…

深度学习入门笔记(二)神经元的结构

神经网络的基本单元是神经元&#xff0c;本节我们介绍神经元的结构。 2.1 神经元 一个神经元是由下面 5 部分组成的&#xff1a; 输入&#xff1a;x1,x2,…,xk。权重&#xff1a;w1,w2,…,wk。权重的个数与神经元输入的个数相同。偏移项&#xff1a;可省略。激活函数&#…

IEEE Proc.|基于知识图谱的少样本和零样本学习综述

本文作者&#xff1a;陈矫彦&#xff08;曼彻斯特大学&牛津大学&#xff09;、耿玉霞&#xff08;浙江大学&#xff09;、陈卓&#xff08;浙江大学&#xff09;、Jeff Z. Pan&#xff08;爱丁堡大学&#xff09;、何源&#xff08;牛津大学&#xff09;、 Ian Horrocks&am…

Linux的权限 + 【提权 | 粘滞位】

Linux权限的概念 Linux下有两种用户&#xff1a;超级用户&#xff08;root&#xff09;、普通用户。 超级用户&#xff1a;可以在linux系统下做任何事情&#xff0c;不受限制普通用户&#xff1a;在linux下做有限的事情。超级用户的命令提示符是“#”&#xff0c;普通用户的命…

C++迷宫游戏详解

个人主页&#xff1a;[PingdiGuo_guo] 收录专栏&#xff1a;[C干货专栏] 大家好呀&#xff0c;我是PingdiGuo_guo&#xff0c;今天我们来学习用C实现一个迷宫游戏。 目录 1.迷宫的具体步骤 1.1.迷宫的初始化 1.2.寻路算法 1.DFS算法 2.BFS算法 1.3.移动 2.总结 C迷宫游…

音视频数字化(数字与模拟-录音机)

之前我们说了【数字与模拟-照相机】照相机的数字化,今天聊聊录音机。 说录音机之前,必须说说留声机。留声机是爱迪生1877年宣布发明成功的,研发过程相当复杂,但原理是简单的。 声音的本质是“波”,是物体振动产生的。以乐器为例,打击乐就是敲击(鼓、钹、木鱼、木琴、三…

向刻苦耐劳乐观向上的青年致敬

今晨互联网上的国际时事新闻报道&#xff0c;显得越来越真假难辨&#xff1b;特别是对俄乌战争、以巴战争、中美俄日朝印越和欧盟各国关系的新闻报道&#xff0c;可谓朝三暮四&#xff0c;一日多变&#xff0c;令人不知谁家的报道可信&#xff0c;便绕道行&#xff0c;不议为妙…

ES6-对象的解构赋值

一、区别一下数组的解构赋值 - 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的&#xff0c;变量的取值由它的位置决定&#xff1b;而对象的属性没有次序&#xff0c;变量必须与属性同名&#xff0c;才能取到正确的值二、说明 - 对象的解构赋值的内部机制&#…

XML详解

文章目录 XML简介语法约束DTDSchema 解析Jsoup使用对象详解JsoupDocumentElementsElementNode XML 简介 概述&#xff1a;Extensible Markup Language 可扩展标记语言 可扩展&#xff1a;标签都是自定义的。 功能 数据存储&#xff1a;XML 可以用来存储结构化数据&#xff0c…

mysql-FIND_IN_SET查询优化

优化前 SELECTuser_id,user_name,real_name,PASSWORD,real_org_id,real_org_name,real_dept_id,real_dept_name, STATUS FROMsys_user WHEREis_del 0 AND find_in_set( lilong, login_user_account ) 优化后 SELECTuser_id,user_name,real_name,PASSWORD,real_org_id,real…

虚拟机Windows Server 2016 安装 MySQL8

目录 一、下载MySQL8 1.下载地址&#xff1a; 2.创建my.ini文件 二、安装步骤 第一步&#xff1a;命令窗口 第二步&#xff1a;切换目录 第三步&#xff1a;安装服务 第四步&#xff1a;生成临时密码 第五步&#xff1a;启动服务 第六步&#xff1a; 修改密码 三…

《A++ 敏捷开发》- 6 估算软件规模

为什么要估规模 规模可以帮我们&#xff1a; 依据历史数据策划&#xff0c;例如估算工作量、工期。归一(Normalize)不同项目作比较。知道现在水平。 依据历史数据策划先把项目分成组件&#xff0c;参考以往类似的组件所花工作量&#xff0c;估算整个项目的总工作量。规模大小…

时间回显+选择(年月日时分秒

一、获取某个时间 1、Date获取Date类型 <el-form-item label"时间" name"endTime"><el-date-picker type"datetime" v-model"editForm.endTime"></el-date-picker> </el-form-item> 效果如图&#xff1a; …

关于爬取所有哔哩哔哩、任意图片、所有音乐、的python脚本语言-Edge浏览器插件 全是干货!

这些都是现成的并且实时更新的&#xff01;从次解放双手&#xff01; 首先有自己的edge浏览器基本上都有并且找到插件选项 1.哔哩哔哩视频下载助手&#xff08;爬取哔哩哔哩视频&#xff09; bilibili哔哩哔哩视频下载助手 - Microsoft Edge Addons 下面是效果&#xff1a; 2.图…

办公软件巨头CCED、WPS面临新考验,新款办公软件异军突起

办公软件巨头CCED、WPS的成长经历 众所周知&#xff0c;CCED和WPS在中国办公软件领域树立了两大知名品牌的地位。然而&#xff0c;它们的成功并非一朝一夕的成就&#xff0c;而是历经了长时间的发展与积淀。 在上世纪80年代末至90年代初&#xff0c;CCED作为中国大陆早期的一款…