了解单链表

news2025/9/22 1:36:25

27. 移除元素 - 力扣(LeetCode)

思路一: 创建新的数组,遍历原数组,将不为val的值放到新数组当中。空间复杂度不为O(1)

思路二:双指针法

我们设置两个指针src(源数据)和dst(目标数据)分别指向数组的第一个位置,如果src指向的数值是我们要删除的数据,那么src++,如果src要的数据不是我们要删除的数据,那么把src的数据赋值给dst,并让src++,dst++。

int removeElement(int* nums, int numsSize, int val) {
    int src,dst;
    src=dst=0;
    while(src<numsSize)//numsSize表示数组的长度
    {
        if(nums[src]==val)
        {
            src++;
        }
        else
        {
            nums[dst]==nums[src];
            dst++;
            src++;
        }
        return dat;//此时dst的值就是新数组的有效长度
    }
    
}

88. 合并两个有序数组 - 力扣(LeetCode)

思路一:将num2中数据依次放入到num1数组的后面,用排序算法对num1进行排序

思路二:

 

l1和l2进行比较。   

思路三:

从后往前比大小:比谁大,谁大谁就往后放

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    //nums1Size:nums1数组的长度
    //nums2Size:nums2数组的长度
    int l1=m-1;
    int l2=n-1;
    int l3=m+n-1;
    while(l1>=0&&l2>= 0)//只要有一个条件为假,就跳出循环
    {
        if(nums1[l1]<nums2[l2])
        {
            nums1[l3--]=nums2[l2--];
        }
        else
        {
            nums1[l3--]=nums1[l1--];
        }

    }
    //出了循环有两种情况:l1大于等于0或者l2大于等于0,不存在l1和l2同时大于等于0的情况
    //只需要处理一种情况,那就是l2大于等于0,说明l2中的数据还没有完全放入num1中
    while(l2>=0)
    {
        nums1[l3--]=nums2[l2--];
    }
//此时nums1中包含了nums2中的数据,num1为升序数组
}

  我们需要有一个定义链表的节点的结构,并且将它们连接在一起,就成了链表。

 SList.h

typedef int SLDataType;
struct SListNode
{
    SLDataType data;
    struct SListNode*next;//指向下一节点的指针
}SLTNode;

void SLTPrint(SLTNode*phead);
void SLTPushBack(SLTNode* phead,SLTDataType x);
void SLTPushFront(SLTNode* phead,SLTDataType x);

SList.c

void SLTPrint(SLTNode* phead)
{
   SLTNode*pcur=phead;
   while(pcur)
   {
       printf("%d->",pcur->data);
       pcur=pur->next;
    }
   printf("\n");
}
//申请新的节点
SLTNode*SLTBuyNode(SLTDataType x)
{
  
   SLTNode*newnode=(SLTNode*)malloc(sizeof(SLTNode));
   if(newnode==NULL)
   {
      perror("malloc fail!");
      exit(1);//异常退出,正常退出为0
   }
   newnode->data=x;
   newnode->next=NULL;
   
   return newnode;
}
//尾插
void SLTPushBack(SLTNode**phead,SLTDataType x)
{
   assert(pphead);
   SLTNode*newnode=SLTBuyNode(x);//在创建 空间之前判断空间是否够用
   if(phead==NULL)//处理空链表和非空链表两种情况
   {
      phead=newnode;
    }
   else
   {
   //找尾
   SLNode*ptail=phead;
   while(ptail->next)
   {
       ptail=ptail->next;//ptail指向的就是尾结点
    }
    ptail->next=newnode;//完成了尾插的动作
    }
}
//头插
 void SLTPushFront(SLTNode**phaed,SLTDataType x)
{
    assert(pphead);
    STNode*newnode=SLBuyNode(x);
    newnode->next=*phead;
    *pphead=newnode;
 }
//尾删
void SLTPopBack(SLTNode**pphead)
{
    assert(pphead&&*pphead);//链表不能为空
    //链表只有一个节点
    if((*pphead)->next==NULL)//->优先级高于*
    {
        free(*pphead);
        *pphead=NULL;
     }
    else{//链表有多个节点
    SLTNode*prev=*pphead;
    SLTNode*ptail=*pphead;
    while(ptail->next)
    {
        prev=ptail;
        ptail=ptail->next;
     }
    free(ptail);
    ptail=NULL;
    prev->next=NULL;
    }
}
//头删
void SLPopFront(SLTNode**pphead)
{
    //链表不能为空
    assert(pphead&&*pphead);//链表不能为空
    SLTNode*next=(*pphead)->next;//->优先级高于*
    free(*pphead);
    *pphead=next;
}
//查找
SLTNode* SLTFind(SLTNode* phead,SLTDataType x)
{
      SLTNode*pcur=phead;
      while(pcur)//等价于pcur不等于空
      {
         if(pcur->data==x)
         {
            return pcur;
         }
         pcur=pcur->next;
      }
      return pcur;
}
//在指定位置之前插入数据
void SLTInsert(SLTNode**pphead,SLTNode*pos,SLTDataType x)
{
    assert(pphead&&*pphead);//如果没有这个数据,就不能插入数据
    assert(pos);
//在指定位置之前插入数据
//找pos指针的前一个节点
    STNode*newnode=SLBuyNode(x);
    if(pos==*pphead)
    {
        SLTPushFront(pphead,x);
    }
    else
    {
    SLTNode*prev=*pphead;//初始情况下指向第一个节点
    while(prev->next!=pos)
    {
        prev=prev->next;
    }
    // 把prev newnode pos三者连接在一起
    newnode->next=pos;
    pre->next=newnode;
    }
}
//在指定位置之后插入数据
void SLTInsertAfter(SLTNode**pphead,SLTNode*pos,SLTDataType x)
{
    assert(pos);
    STNode*newnode=SLBuyNode(x);
    newnode->next=pos->next;   
    pos->next=newnode;
}
//删除pos节点
void SLTErase(SLTNode** pphead,SLTNode*pos)
{
     assert(pphead&&*pphead);//链表不能为空
     assert(pos);
     if(pos==*pphead)
     {
        SLTNode* next=(*pphead)->next;//先把头结点的下一个节点储存起来
        free(*pphead);
           *pphead=next;//或者直接采用SLTPopFront(pphead);
     }
     else
     {
        SLTNode*prev=*pphead;
        while(prev->next!=pos)
        {
            prev=prev->next;
         }
         free(pos);
        pos=NULL;
      }
}
//删除pos之后的节点
void SLTEraseAfter(SLTNode* pos)
{
    assert(pos&&pos->next);
    SLTNode*del=pos->next;
    pos->next=del->next;
    free(del);
    del=NULL;

}
//销毁链表(销毁一个一个的节点)   
void SListDestory(SLTNode**pphead)
{
    assert(pphead&&*pphead);
    SLTNode*pcur=*pphead;
    while(pcur)
    {
         SLTNode*next=pcur->next;
         free(pcur);
         pcur=next;
     }
    *pphead=NULL;
}
          

如果链表为空,不能对空指针进行解引用,代码会报错。

但是当我们运行之后发现,形参改变了,实参并没有改变。

把头结点释放掉, 再把*pphead走到next指针当中。

当pos=*pphead时,走不通。 

上面这两种插入节点的方式是否相同?

1  newnode->next=pos->next;   pos->next=newnode;

2  pos->next=newnode;   newnode->next=pos->next;

 

像下面这么操作,是否可行呢? 

这样操作就把节点4释放了。我们可以创建一个临时变量del。

test.c

#include"SList.h"
void SListTest()
{
  //链表是由一个一个的节点组成
  //创建几个节点
  SLNode*node1=malloc(sizeof(SLTNode));//对于节点,我们不会涉及到增容的概念,所以我们使用malloc,而不是使用realloc
  node->data=1;
  SLNode*node2=malloc(sizeof(SLTNode));
  node->data=2;
  SLNode*node3=malloc(sizeof(SLTNode));
  node->data=3;
  SLNode*node4=malloc(sizeof(SLTNode));
  node->data=4;//创建好了4个节点,但是此时这四个节点不能相互找到
  //通过每个节点里的next指针,将各个节点连接起来
  node1->next=node2;
  node2->next=node3;
  node3->next=node4;
  node4->next=NULL;
//调用链表的打印
  //再定义一个节点,指向node1,然后作为实参传入
  SLTNode*plist=node1;
  SLTPrint(plist);

}

int main()
{
    return 0;
}

尾插

要找到尾结点,再把尾结点和新节点连接起来。我们让尾结点的下一节点不要指向NULL,而是指向newNode。这样就实现了尾插。

如果我们设置找到ptail的循环条件是while(ptail!=NULL),那么此时不满足。应该是ptail->next不为空。

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

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

相关文章

MOS管的判别符号记忆与导通条件

参考链接 MOS管的判别与导通条件 (qq.com)https://mp.weixin.qq.com/s?__bizMzU3MDU1Mzg2OQ&mid2247520228&idx1&sn5996780179fbf01f66b5db0c71622ac3&chksmfcef6c86cb98e590e3d3734ee27797bdded17b6b648b3b0d3b1599e8a4496a1fa4e457be6516&mpshare1&…

[CUDA 学习笔记] 矩阵转置算子优化

矩阵转置算子优化 矩阵转置是一种基础的矩阵操作, 即将二维矩阵的行列进行反转. 本文主要围绕行主序的二维单精度矩阵的转置考虑相关的优化. 以下 kernel 笔者均是在 NVIDIA V100 (7.0 算力) 上进行测试的, 且选择矩阵的行列维度大小为 M2300 N1500. Version 0. 朴素实现 _…

流量分组新增两大新规则;Network SDK更新618大促版本;综合报表支持实时新用户指标 | TopOn产品更新

「TopPro 每月产品速递」是由TopOn最新推出的产品专栏&#xff0c;将会以月为周期梳理TopOn最新产品动态&#xff0c;致力于为互联网从业者提供优质服务&#xff0c;引领行业产品发展。 TopPro | 四月产品速递 2023.04.01-04.27 01 流量分组新增两大新规则 // 功能描述 *…

面向AI编程,AI可以为我们做哪些事情

本来这篇文章是2023-10月发出的&#xff0c;放在草稿箱比较久了。今天重新捡起来发下。内容很长&#xff0c;很干。希望对大家有启发&#xff0c;编程路上提升效率。 背景 基本上以前我们出了bug都是百度&#xff0c;但随着AI的出现&#xff0c;对标百度给出的答案。发现AI实在…

python爬虫-------JsonPath(第十九天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

Pytorch中nn.Linear使用方法

nn.Linear定义一个神经网络的线性层&#xff1a; torch.nn.Linear(in_features, # 输入的神经元个数out_features, # 输出神经元个数biasTrue # 是否包含偏置)nn.Linear其实就是对输入&#xff08;n表示样本数量&#xff0c;i表示样本特…

国产低代码工具,轻松搞定数据迁移

在日常的业务系统升级或者数据维护过程中&#xff0c;数据迁移是各个企业用户不得不面临的问题&#xff0c;尤其是数据迁移过程中要保障数据完整性、统一性和及时性&#xff0c;同时也需要注意源数据中的数据质量问题&#xff0c;比如缺失、无效、错误等问题&#xff0c;需要在…

Kubernetes中安装部署Nacos集群

目录 1、Nacos安装包的准备 1.1 下载安装包 1.2 解压安装包 1.3 修改配置文件 application.properties 1.4 bin目录下创建 docker-startup.sh 1.5 将nacos-server-1.2.1目录打包成nacos-server-1.2.1.tar.gz 2、 nacos镜像制作 2.1 Dockerfile文件编写 2.2 制作镜像…

单片机入门还能从51开始吗?

选择从51单片机开始入门还是直接学习基于ARM核或RISC核的单片机&#xff0c;取决于学习目标、项目需求以及个人兴趣。每种单片机都有其特定的优势和应用场景&#xff0c;了解它们的特点可以帮助你做出更合适的选择。 首先&#xff0c;我们说一下51单片机的优势&#xff1a; 成熟…

外包干了17天,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四年的功能…

【石上星光】context,go的上下文存储并发控制之道

目录 1 引言2 What&#xff1f;3 How&#xff1f; 3.1 用法一、上下文数据存储3.2 用法二、并发控制 3.2.1 场景1 主动取消3.2.2 场景2 超时取消 3.3 用法三、创建一个空Context&#xff08;emptyCtx&#xff09; 4 Why&#xff1f; 4.1 go中的上下文思想 4.1.1 上下文是什么…

技术小课堂:100%CC防护是怎么实现的?

大家好&#xff0c;今天我们深入探讨的是如何有效地实现CC攻击的100%防护&#xff0c;以及传统防护手段存在的局限性和我们的定制化解决方案的优势。 传统的CC防护措施通常依赖于全局性的访问频率控制或在防火墙级别设置固定的访问次数限制。这种方式看似简单直接&#xff0c;…

安全大脑与盲人摸象

21世纪是数字科技和数字经济爆发的时代&#xff0c;互联网正从网状结构向类脑模型进行进化&#xff0c;出现了结构和覆盖范围庞大&#xff0c;能够适应不同技术环境、经济场景&#xff0c;跨地域、跨行业的类脑复杂巨型系统。如腾讯、Facebook等社交网络具备的神经网络特征&…

[方案实操|数据技术]数据要素十大创新模式(1):基于区块链的多模态数据交易服务平台

“ 区块链以其公开共享、去中心化、不可篡改、可追溯和不可抵赖等优势&#xff0c;吸引了包括金融业、医疗业和政府部门等众多利益相关方的极大兴趣&#xff0c;被认为是解决数据安全交换问题的合适方案。” 武汉东湖大数据科技股份有限公司凭借基于区块链的多模态数据交易服务…

交换机的基本原理与配置_实验案例一:交换机的初始配置

1、实验环境 实验用具包括一台Cisco交换机&#xff0c;一台PC&#xff0c;一根Console 线缆。 2、需求描述 如图5.17所示&#xff0c;实验案例一的配置需求如下。 通过PC连接并配置一台Cisco交换机。在交换机的各个配置模式之间切换。将交换机主机的名称改为BDON 3、推荐步…

OpenHarmony应用编译 - 如何在源码中编译复杂应用(4.0-Release)

文档环境 开发环境&#xff1a;Windows 11 编译环境&#xff1a;Ubuntu 22.04 开发板型号&#xff1a;DAYU 200&#xff08;RK3568&#xff09; 系统版本&#xff1a;OpenHarmony-4.0-Release 功能简介 在 OpenHarmony 系统中预安装应用的 hap 包会随系统编译打包到镜像中&a…

C语言—每日选择题—Day68

第一题 1、运行以下C语言代码&#xff0c;输出的结果是&#xff08;&#xff09; #include <stdio.h> int main() {char *str[3] {"stra", "strb", "strc"};char *p str[0];int i 0;while(i < 3){printf("%s ",p);i;} retur…

Path Aggregation Network for Instance Segmentation

PANet 摘要1. 引言2.相关工作3.框架 PANet 最初是为 proposal-based 实例分割框架提出来的&#xff0c;mask 是实例的掩码&#xff0c;覆盖了物体包含的所有像素&#xff0c;proposal 在目标检测领域是可能存在目标的区域。在实例分割中&#xff0c;首先利用RPN(Region Proposa…

【并发】第四篇 原子操作系列-AtomicInteger原子操作类详解

导航 一. 简介二. 源码分析三. 原子操作原理三. 实际用途1. 标志位2. 唯一标识生成器3. 计数器一. 简介 AtomicInteger是Java中提供的一种线程安全的原子操作类,用来实现对整数类型的原子操作。它可以在多线程环境下保证对整数的原子性操作,而不需要使用synchronized关键字或…

小样本计数网络FamNet(Learning To Count Everything)

小样本计数网络FamNet(Learning To Count Everything) 大多数计数方法都仅仅针对一类特定的物体&#xff0c;如人群计数、汽车计数、动物计数等。一些方法可以进行多类物体的计数&#xff0c;但是training set中的类别和test set中的类别必须是相同的。 为了增加计数方法的可拓…