数据结构:单向链表

目录

结构体

创建链表

插入链表

头插法

尾插法

遍历打印

更新链表指定节点

查找链表指定节点

删除链表指定节点

销毁链表

找到元素中间位置

 找到链表倒数第k个节点

链表元素倒置

链表元素排序

冒泡排序

选择排序


链表
    1.空间可以不连续,访问元素不方便
    2.链表需要更大的空间存放数据和节点地址
    3.链表空间不连续,使得理论上长度是无限的
    4.链表的插入和删除效率很高

结构体

typedef int DataType;
typedef struct node
{DataType data;struct node *pnext;
}LinkNode;

创建链表

LinkNode *CreateLinklist()
{LinkNode *pHead=NULL;pHead=malloc(sizeof(LinkNode));if(pHead==NULL){return NULL;}pHead->pnext=NULL;return pHead;
}

插入链表

头插法

int HeadInsertLink(LinkNode *pHead,DataType data)
{LinkNode *pTmpnode=NULL;
//申请一个新的节点空间pTmpnode=malloc(sizeof(LinkNode));if(pTmpnode==NULL){return -1;}
//为节点data赋值pTmpnode->data=data;
//新节点的pnext指向头结点的pnextpTmpnode->pnext=pHead->pnext;
//头结点的pnext指向新节点pHead->pnext=pTmpnode;return 0;
}

尾插法

int TailInsertLinkList(LinkNode *pHead, DataType TmpData)
{LinkNode *ptmpnode=NULL;LinkNode *Newnode=NULL;ptmpnode=pHead;
//找到最后一个节点(最后一个节点的特点是pnext为空)while (ptmpnode->pnext!=NULL){ptmpnode=ptmpnode->pnext;}
//申请一个新的节点空间Newnode=malloc(sizeof(LinkNode));if(Newnode==NULL){return -1;}
//为节点数据空间赋值Newnode->data=TmpData;
//新节点的pnext指向NULLNewnode->pnext=NULL;
//最后一个节点next指向当前节点,当前节点变为最后一个节点ptmpnode->pnext=Newnode;return 0;
}

遍历打印

int Showlist(void *Element,void *arg)
{int *data = Element;printf("%d  ",*data);return 0;
}
int ShowLinkList(LinkNode *pHead,int (*pFun)(void *Element,void *arg),void *arg)
{LinkNode *pTmpnode=NULL;pTmpnode=pHead->pnext;int ret=0;while(pTmpnode!=NULL){ret=pFun(&pTmpnode->data,arg);if(ret!=0){break;}pTmpnode=pTmpnode->pnext;}return 0;
}

更新链表指定节点

int UpdateLinkList(LinkNode *pHead, DataType OldData, DataType NewData)
{LinkNode *pTmpnode=NULL;pTmpnode=pHead->pnext;while(pTmpnode!=NULL){   if(pTmpnode->data==OldData){pTmpnode->data=NewData;}pTmpnode=pTmpnode->pnext;}return 0;
}

查找链表指定节点

LinkNode *FindLinkList(LinkNode *pHead, DataType TmpData)
{LinkNode *pTmpnode=NULL;pTmpnode=pHead;while(pTmpnode->data!=TmpData){pTmpnode=pTmpnode->pnext;}return pTmpnode;
}

删除链表指定节点

int DeleteLinklist(LinkNode *pHead,DataType data)
{LinkNode *pTmpnode=NULL;LinkNode *pPreNode=NULL;pTmpnode=pHead;pPreNode=pHead;while(pTmpnode!=NULL){if((pTmpnode->data!=data)) //如果不是要被删除的节点{pPreNode=pTmpnode;//保存此节点pTmpnode=pTmpnode->pnext;//指向下一个节点}else{   //前一个节点的pnext指向要被删除节点的后一个节点pPreNode->pnext=pTmpnode->pnext;free(pTmpnode);//释放要被删除的节点pTmpnode=pPreNode->pnext;//循环遍历下一个节点}}return 0;}

销毁链表

int DestoryLinklist(LinkNode **pHead)
{LinkNode *pTmpnode=NULL;LinkNode *pTmpnext=NULL;pTmpnode=*pHead;while(pTmpnode!=NULL){  //保存下一个节点pTmpnext=pTmpnode->pnext;free(pTmpnode);//释放当前节点pTmpnode=pTmpnext; //指向下一个节点}*pHead=NULL;//头结点指向空return 0;
}

找到元素中间位置

算法:

       快指针pFast每次走2步
       慢指针pSlow每次走1步
       快指针到达末尾时,慢指针所在的位置即为中间位置

LinkNode *FindMidLinkNode(LinkNode *pHead)
{LinkNode *pFast=pHead->pnext;LinkNode *pSlow=pHead->pnext;while(pFast!=NULL){
//快节点先走两步,若是只有一个节点或两个节点,就跳出循环,此时慢节点指向第一个节点pFast=pFast->pnext;if(pFast==NULL){break;}pFast=pFast->pnext;if(pFast==NULL){break;}
//快节点走完两步,慢节点走一步pSlow=pSlow->pnext;}return pSlow;
}

 找到链表倒数第k个节点

算法:

         快指针先走k步
         慢指针和快指针每次走1步(快指针总是领先慢指针k步)
          当快指针走到末尾时,慢指针即指向链表倒数第k个节点

LinkNode *FindKthLinkNode(LinkNode *pHead,int k)
{int i=0;LinkNode *pFast=pHead->pnext;LinkNode *pSlow=pHead->pnext;
//快节点先走k步for(i=0;i<k;i++){pFast=pFast->pnext;if(pFast->pnext==NULL){return NULL;}}
//快慢节点每次都走1步,当快节点到达末尾时,慢节点的位置就是第k个节点while(pFast!=NULL){pFast=pFast->pnext;pSlow=pSlow->pnext;}return pSlow;
}

链表元素倒置

算法

        使用头插法将链表元素开始到结尾重新插入链表中,即第一个插入后第二个插入,第一个就在末尾,以此类推实现倒置

int ReverseLinkList(LinkNode *pHead)
{LinkNode *pInsertNode=pHead->pnext;LinkNode *pTmpNode=pHead->pnext;pHead->pnext=NULL;while(pTmpNode!=NULL){//保留革命火种pTmpNode=pTmpNode->pnext;//将剩余链表的第一个插入头结点pnextpInsertNode->pnext=pHead->pnext;pHead->pnext=pInsertNode;//插入节点向后移动pInsertNode=pTmpNode;}return 0;
}

链表元素排序

冒泡排序

int BubbleLinkList(LinkNode *pHead)
{LinkNode *ptmpNode1=NULL;LinkNode *ptmpNode2=NULL;LinkNode *pEnd=NULL;DataType pTmpData;
//没有元素或只有一个元素直接返回if(pHead->pnext==NULL ||pHead->pnext->pnext==NULL){return -1;}while(1){ptmpNode1=pHead->pnext;ptmpNode2=pHead->pnext->pnext;
//最后一次只有两个元素,此时链表已经排好序,pEnd和pTmpNode
相等,直接结束外层循环        if(ptmpNode2==pEnd){break;}//第一次排序结束时标志为pTmpNode=NULL,但是pEnd此时还是NULL,所以这里直接写成pEndwhile(ptmpNode2!=pEnd){
//相邻节点作比较,将大数往后挪if(ptmpNode1->data > ptmpNode2->data){pTmpData=ptmpNode1->data;ptmpNode1->data=ptmpNode2->data;ptmpNode2->data=pTmpData;}
//一直向后遍历ptmpNode1=ptmpNode1->pnext;ptmpNode2=ptmpNode2->pnext;}   
//当ptmpNode2走到NULL或者end时,ptmpNode1就是此时保存的数据最大节点,下一次就不用遍历此节点 pEnd=ptmpNode1;}return 0;
}

选择排序

pTmpNode负责遍历后面的节点,当找到比pMinNode节点更小的值时,更新pMinNode,然后比较pSwapNode与pMinNode值的大小,将小的值存放在pSwapNode节点的数据中,pSwap再指向像一个节点,进行下一轮比较

//选择排序
int SelectSortLinkList(LinkNode *pHead)
{LinkNode *pSwapNode=pHead->pnext;LinkNode *pMinNode=pHead->pnext;LinkNode *pTmpNode=NULL;DataType TmpData;if(pHead->pnext==NULL){return 0;}while(pSwapNode->pnext!=NULL){
//每次先将pMinNode保存为待交换的节点pMinNode=pSwapNode;
//从待交换节点的下一个节点开始遍历pTmpNode=pSwapNode->pnext;
//找到后面最小的数据的节点,将每一个遍历的节点都与最小节点比较,让pMinNode总是指向更小的节点while(pTmpNode!=NULL){if(pMinNode->data >pTmpNode->data ){pMinNode=pTmpNode;}pTmpNode=pTmpNode->pnext;}
//如果最小的数据比带交换数据还小,就交换两个节点的数据,保证此轮最小的数据在最前面if(pMinNode->data < pSwapNode->data){TmpData=pMinNode->data;pMinNode->data=pSwapNode->data;pSwapNode->data=TmpData;}
//待交换数据向后依次遍历pSwapNode=pSwapNode->pnext;}return 0;
}

如何判断一个链表是否有环?环长?环的入口位置?

是否有环:

        快指针每次走2步,慢指针每次走1步,快慢指针相遇则说明有环
如何计算环长:

        标记相遇的位置,让指针继续向后走,没走一步计算器自加,走回到标记位置,则计算器值即为环长
如何计算环入口位置:

        将一个指针从第一个节点向后走,将一个指针从相遇点向后走,两个指针相遇的位置即为环入口的位置

LinkNode *IsHasCircle(LinkNode *pHead,int *len)
{int ret=0;*len=1;LinkNode *pFast=NULL;LinkNode *pSlow=NULL;LinkNode *pTmpNode=NULL;LinkNode *pNode1=NULL;LinkNode *pNode2=NULL;pFast=pSlow=pHead->pnext;
//判断是否有环while(1){pFast=pFast->pnext;if(pFast==NULL){ret=0;break;}pFast=pFast->pnext;if(pFast==NULL){ret=0;break;}pSlow=pSlow->pnext;if(pFast==pSlow){ret=1;break;}}if(ret==1){//获得环长
//从相遇节点的下一个节点触发,再次走到相遇节点刚好走路一圈pTmpNode=pSlow->pnext;while(pTmpNode!=pSlow){(*len)++;pTmpNode=pTmpNode->pnext;}获得环入口节点
//pNode1从第一个节点开始向后走pNode1=pHead->pnext;
//pNode2从快慢相遇位置开始走(在环内走)pNode2=pSlow;
//pNode1和pNode2节点相遇的位置即为环入口节点while(pNode1!=pNode2){pNode1=pNode1->pnext;pNode2=pNode2->pnext;}return pNode1;}return NULL;
}

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

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

相关文章

Stable Diffusion之提示词指南(三)

在上一篇的文章中&#xff0c;我们讲解了Stable Diffusion提示词的高级用法&#xff0c;对于一些高级属性有了了解。如果有不记得的&#xff0c;可以再去看看———Stable Diffusion之提示词指南(二)。今天我们讲解一下负提示词。 负提示词 负向提示词&#xff1a;简单说就是…

计算机网络803-(3)数据链路层

目录 一.数据链路两种类型 二.使用点对点信道的数据链路层 1. 数据链路和帧 2.数据链路层传送的是帧 三.三个基本问题 1.封装成帧 2.透明传输 ①字节填充法 ②其他方法&#xff1a;字符计数法&#xff0c;比特填充法&#xff0c;违规编码 3. 差错检测 &#xff08;1…

成为一名月薪 2 万的 web 安全工程师需要掌握哪些技能?

现在 web 安全工程师比较火&#xff0c;岗位比较稀缺&#xff0c;现在除了一些大公司对学历要求严格&#xff0c;其余公司看中的大部分是能力。 有个亲戚的儿子已经工作 2 年了……当初也是因为其他的行业要求比较高&#xff0c;所以才选择的 web 安全方向。 资料免费分享给你…

【在Linux世界中追寻伟大的One Piece】传输层协议UDP

目录 1 -> 传输层 2 -> 端口号 2.1 -> 端口号范围划分 2.2 -> 知名端口号 3 -> UDP协议 3.1 -> UDP协议端格式 3.2 -> UDP的特点 3.2.1 -> 面向数据报 3.3 -> UDP的缓冲区 3.4 -> UDP使用注意事项 3.5 -> 基于UDP的应用层协议 1 -…

【进程间通信】管道应用场景---简易进程池

#include<iostream> #include<vector> #include<string> #include<cstring> #include<cstdlib> #include<unistd.h> #include<sys/stat.h> #include<sys/wait.h>//把5个子进程要管理起来&#xff0c;要先描述再组织 const int…

【C++】list的使用和list的模拟实现和迭代器失效问题

目录 一、list 的简单介绍 二、list 的基本使用 &#x1f389;list的构造 &#x1f389;list iterator 的使用 &#x1f389;list capacity &#x1f389;list element access &#x1f389;list modifiers &#x1f389;list operator 三、list 的模拟实现 &#x…

Unity TreeView扩展

实现效果 这里原来是做的一个检测网络、事件回调耗时的工具。简单改了成了一个演示TreeView的demo。实现了TreeView的基本功能并且实现了对列的排序。TreeView还可以制作点击&#xff0c;双击&#xff0c;右键等事件&#xff0c;但这里暂时不需要用到。 思维导图 工程&#xf…

华为云征文|部署内容管理系统 Joomla

华为云征文&#xff5c;部署内容管理系统 Joomla 一、Flexus云服务器X实例介绍1.1 云服务器介绍1.2 应用场景1.3 核心竞争力 二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置 三、部署 Joomla3.1 Joomla 介绍3.2 Docker 环境搭建3.3 Joomla 部署3.4 Joom…

【MCAL】TC397+EB-tresos之SPI配置实战 - (同步/异步)

本篇文章首先从理论讲起&#xff0c;从AUTOSAR规范以及MCAL手册两个不同角度&#xff08;前者偏理论&#xff0c;后者偏实践&#xff09;介绍了SPI模块的背景概念与理论&#xff0c;帮助读者在实际配置之前能有个理论的框架。然后详细的介绍了在TC397平台使用EB tresos对SPI驱动…

简化理解:Tomcat 和 Servlet 规范

有时候&#xff0c;我们会把复杂的技术概念弄得很复杂&#xff0c;其实这些东西可以用更简单的语言来理解。我们来看看 Tomcat 和 Servlet 规范到底是怎么回事。 1. 什么是 Servlet 规范&#xff1f; 简单来说&#xff0c;Sun 公司&#xff08;现在是 Oracle&#xff09;定了…

Axure RP下载+详细安装步骤资源百度云盘分享

众所周知&#xff0c;Axure全称“axure rp”&#xff0c;是一款专业的快速原型设计工具。 它能帮助网站需求设计者&#xff0c;快捷而简便的创建基于网站构架图的带注释页面示意图、操作流程图、以及交互设计&#xff0c;并可自动生成用于演示的网页文件和规格文件&#xff0c…

单片机内存区域划分

目录 一、C 语言内存分区1、栈区2、堆区3、全局区&#xff08;静态区&#xff09;4、常量区5、代码区6、总结 二、单片机存储分配1、存储器1.1 RAM1.2 ROM1.3 Flash Memory1.4 不同数据的存放位置 2、程序占用内存大小 一、C 语言内存分区 C 语言在内存中一共分为如下几个区域…

AR 眼镜之-系统通知定制(通知弹窗)-实现方案

目录 &#x1f4c2; 前言 AR 眼镜系统版本 系统通知定制 1. &#x1f531; 技术方案 1.1 技术方案概述 1.2 实现方案 1&#xff09;实现系统通知的监听 2&#xff09;系统通知显示&#xff1a;通知弹窗 2. &#x1f4a0; 实现系统通知的监听 2.1 继承 NotificationLi…

【原型设计工具评测】Axure、Figma、Sketch三强争霸

在当今的数字化设计领域&#xff0c;选择合适的原型设计工具对于项目的成功至关重要。Axure、Figma 和 Sketch 是目前市场上最受欢迎的三款原型设计工具&#xff0c;它们各具特色&#xff0c;满足了不同用户的需求。本文将对这三款工具进行详细的对比评测&#xff0c;帮助设计师…

联蔚盘云亮相CDIE消费品行业峰会

8月28日&#xff0c;由华昂集团主办&#xff0c;专注于消费品行业的2024CDIE行业峰会在广州盛大开幕。联蔚数科携子品牌联蔚盘云亮相本次大会。本次峰会汇聚了众多企业高管&#xff0c;行业领域专家&#xff0c;围绕AI技术前沿、数智营销新策略、会员运营以及品牌增量路径等话题…

后台框架-统一异常管理

搭建后台框架全局异常管理是一个很重要的部分&#xff0c;好在SpringBoot提供了很好的处理方法 使用ControllerAdvice ControllerAdvice是Spring MVC中的一个全局异常处理注解&#xff0c;它允许在一个地方集中处理所有控制器抛出的异常。通过使用ControllerAdvice&#xff0…

Leetcode199二叉树的右视图(java实现)

今天我们分享的题目是199题&#xff0c;题目描述如下&#xff1a; 那么本道题的解题思路呢就是使用层序遍历&#xff0c;每次将每层中的最后一个元素加入到我们的集合中。 本道题目和之前的层序遍历二叉树的题目很像&#xff0c;但是需要注意的细节。那么我会在代码中指出。 代…

Flink CDC读取Mysql时,Decimal类型数据异常,变成了字符串(源码解析及解决方案)

1. 问题说明 使用Flink CDC 读取mysql数据时,当表字段为decimal时,读取的数据变成了字符串。 如下示例: 环境: Flink 1.18.0 Flink CDC 3.1.1 mysql 8 mysql的数据如下: 使用Flink CDC读取后的数据如下: 为了方便看,复制出来就是: {“id”:1,“price”:“AZA=”,…

ClickHousez中如何定时清理过期数据库?

一、脚本清理 要在ClickHouse中自动删除过期的数据库&#xff0c;你可以使用ClickHouse的SQL命令结合外部脚本&#xff08;如Shell脚本&#xff09;和计划任务&#xff08;如cron&#xff09;来实现。下面是一个示例&#xff0c;展示如何创建一个Shell脚本来检查数据库的创建时…

[引人深思]博彩用户真的赢了吗?——多维度揭示赌博危害

1.项目背景 博彩业&#xff0c;作为全球经济中一个庞大而复杂的行业&#xff0c;吸引了无数用户参与其中&#xff0c;然而&#xff0c;在巨大的利益诱惑背后&#xff0c;博彩业对个人和社会造成的潜在危害却不容忽视&#xff0c;尽管博彩活动常被包装为“娱乐”或“休闲活动”…