数据结构与算法教程,数据结构C语言版教程!(第二部分、线性表详解:数据结构线性表10分钟入门)九

news2024/11/17 19:33:30

 第二部分、线性表详解:数据结构线性表10分钟入门

线性表,数据结构中最简单的一种存储结构,专门用于存储逻辑关系为"一对一"的数据。

线性表,基于数据在实际物理空间中的存储状态,又可细分为顺序表(顺序存储结构)和链表(链式存储结构)。

本章还会讲解顺序表和链表的结合体——静态链表,不仅如此,还会涉及循环链表、双向链表、双向循环链表等链式存储结构。

十七、如何判断单链表为有环链表?

循环链表一节,给大家详细地介绍了循环链表。在此基础上,本节带领大家讨论一个问题:如何判断一个单链表中有环?

注意,有环链表并不一定就是循环链表。循环链表指的是“首尾相连”的单链表,而有环链表则指的是单链表中存在一个循环子链表,如图 1 所示。

图 1 有环链表示意图

图 1 所示就是一个有环链表,但并不是循环链表。

那么,如果给定一个单链表,如何判断其是否为有环链表呢?常用的判断方法有如下 2 种。

1) 最直接的实现思想就是:从给定链表的第一个节点开始遍历,每遍历至一个节点,都将其和所有的前驱节点进行比对,如果为同一个节点,则表明当前链表中有环;反之,如果遍历至链表最后一个节点,仍未找到相同的节点,则证明该链表中无环。

注意,如果一个单链表为有环链表,基于单链表中各节点有且仅有 1 个指针域的特性,则势必该链表是没有尾结点的(如图 1 所示)。换句话说,有环链表的遍历过程是无法自行结束的,需要使用 break 语句手动结束遍历。

基于上面的实现思想,下面设计了一个相应的实现函数:

//自定义 bool 类型

typedef enum bool

{

        False=0,

        True=1

}bool;

// H 为链表的表头

bool HaveRing(link * H) {

        link * Htemp = H; /

        /存储所遍历节点所有前驱节点的存储地址,64位环境下地址占 8 个字节,所以这里用         long long 类型

        long long addr[20] = { 0 };

        int length = 0, i = 0;

        //逐个遍历链表中各个节点

        while (Htemp) {

                //依次将 Htemp 和 addr 数组中记录的已遍历的地址进行比对

                for (i = 0; i < length; i++) {

                        //如果比对成功,则证明有环

                        if (Htemp == addr[i]) {

                                return True;

                        }

                }

                //比对不成功,则记录 Htemp 节点的存储地址

                addr[length] = Htemp;

                length++;

                Htemp = Htemp->next;

        }

        return False;

}

如上所示,当函数的返回值为 True,表示该链表有环;反之若函数返回值为 False,表明链表中无环。显然,此实现方案的时间复杂度为O(n^{2})

2) 相比上一种实现方案,这里介绍一种时间复杂度为 O(n) 的算法。

该算法的实现思想需要借助一个论点,即在一个链表中,如果 2 个指针(假设为 H1 和 H2)都从表头开始遍历链表,其中 H1 每次移动 2 个节点的长度(H1 = H1->next->next),而 H2 每次移动 1 个节点的长度(H2 = H2->next),如果该链表为有环链表,则 H1、H2 最终必定会相等;反之,如果该链表中无环,则 H1、H2 永远不会相遇。

有关在有环链表中 H1 和 H2 必定会相遇的结论,假设有环链表中的环包含 n 个节点,则第一次遍历,H1 和 H2 相差 1 个节点;第二次遍历,H1 和 H2 相差 2 个节点;第三次遍历,H1 和 H2 相差 3 个节点...,最终经过多次遍历,H1 和 H2 会相差 n-1 个节点,此时就会在环中重合,此时 H1 和 H2 相等。

基于以上这个结论,我们可以轻松编写出对应的实现代码:

//H为链表的表头,该函数会返回一个枚举的 bool 类型数据

bool HaveRing(link * H) {

        link * H1 = H->next;

        link * H2 = H;

        while (H1) {

                if (H1 == H2) {

                        //链表中有环

                        return True;

                } else {

                        H1 = H1->next;

                        if (!H1) {

                                //链表中无环

                                return False;

                        }

                         else

                         {

                                H1 = H1->next;

                                H2 = H2->next;

                        }

                }

        }

        //链表中无环

        return False;

}

和上一种实现代码一样,当函数返回 False 时,表明当前链表中无环;反之若返回 True,则表明该链表为有环链表。和第一种算法相比,本算法的时间复杂度为 O(n)。


 十八、双向循环链表(C语言)详解

我们知道,单链表通过首尾连接可以构成单向循环链表,如图 1 所示:

单向循环链表示意图

图 1 单向循环链表示意图

同样,双向链表也可以进行首尾连接,构成双向循环链表。如图 2 所示:

双向循环链表示意图

图 2 双向循环链表示意图

当问题中涉及到需要 "循环往复" 地遍历表中数据时,就需要使用双向循环链表。例如,前面章节我们对约瑟夫环问题进行了研究,其实约瑟夫环问题有多种玩法,每次顺时针报数后,下一轮可以逆时针报数,然后再顺时针......一直到剩下最后一个人。解决这个问题就需要使用双向循环链表结构。

双向循环链表的创建

创建双向循环链表,只需在创建完成双向链表的基础上,将其首尾节点进行双向连接即可

C 语言实现代码如下:

//创建双向循环链表

line* initLine(line * head){

        head=(line*)malloc(sizeof(line));

        head->prior=NULL;

        head->next=NULL;

        head->data=1;

        line * list=head;

        for (int i=2; i<=3; i++) {

                line * body=(line*)malloc(sizeof(line));

                body->prior=NULL;

                body->next=NULL;

                body->data=i;

                list->next=body;

                body->prior=list;

                list=list->next;

        }

        //通过以上代码,已经创建好双线链表,接下来将链表的首尾节点进行双向连接

        list->next=head;

        head->prior=list;

        return head;

}

通过向 main 函数中调用 initLine 函数,就可以成功创建一个存储有 {1,2,3} 数据的双向循环链表,其完整的 C 语言实现代码为:

#include <stdio.h>

#include <stdlib.h>

typedef struct line{

        struct line * prior;

        int data;

        struct line * next;

}line;

line* initLine(line * head);

void display(line * head);

int main() {

        line * head=NULL;

        head=initLine(head);

        display(head);

        return 0;

}

//创建双向循环链表

line* initLine(line * head){

        head=(line*)malloc(sizeof(line));

        head->prior=NULL;

        head->next=NULL;

        head->data=1;

        line * list=head;

        for (int i=2; i<=3; i++) {

                line * body=(line*)malloc(sizeof(line));

                body->prior=NULL;

                body->next=NULL;

                body->data=i;

                list->next=body;

                body->prior=list;

                 list=list->next;

        }

         //通过以上代码,已经创建好双线链表,接下来将链表的首尾节点进行双向连接

         list->next=head;

         head->prior=list;

         return head;

}

//输出链表的功能函数

void display(line * head){ l

        ine * temp=head;

        //由于是循环链表,所以当遍历指针temp指向的下一个节点是head时,证明此时已经循环至链表的最后一个节点

        while (temp->next!=head) {

                 if (temp->next==NULL) {

                         printf("%d\n",temp->data);

                 }else{

                         printf("%d->",temp->data);

                 }

                 temp=temp->next;

         }

         //输出循环链表中最后一个节点的值

         printf("%d",temp->data);

}

程序输出结果如下:

1->2->3

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

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

相关文章

Java 基础知识点1 (含面试题)

本次Java 知识点主要是关于SE的相关基础&#xff0c;同时也包含了数据结构中的一些API&#xff0c;例如Set,List,Map等&#xff0c;最后也附上了相关重要的面试题&#xff0c;可供大家学习与参考&#xff01; 目录 重要知识点数据结构API面试题 重要知识点 Java 是一门面向对象…

linux下超级程序!在linux界面实现类图像化界面的操作体验!

linux下超级程序&#xff01;在linux界面实现类图像化界面的操作体验&#xff01; 本期带来一个超级程序&#xff01;在linux界面实现类图像化界面的操作体验。具体功能代码如下: 1500行完整代码想要完成部署&#xff0c;只需在本地创建一个LinuxGJ.sh的文件&#xff0c;然后…

传感数据分析——高通滤波与低通滤波

传感数据分析——高通滤波与低通滤波 文章目录 传感数据分析——高通滤波与低通滤波前言一、运行环境二、Python实现总结 前言 对于传感信号而言&#xff0c;我们可以提取其中的高频信息和低频信息&#xff0c;低频信息往往是信号的趋势&#xff0c;高频信息往往是一些突变或异…

构建自己的私人GPT

创作不易&#xff0c;请大家多鼓励支持。 在现实生活中&#xff0c;很多人的资料是不愿意公布在互联网上的&#xff0c;但是我们又要使用人工智能的能力帮我们处理文件、做决策、执行命令那怎么办呢&#xff1f;于是我们构建自己或公司的私人GPT变得非常重要。 一、本地部署…

win10下vscode+cmake编译C代码操作详解

0 工具准备 1.Visual Studio Code 1.85.1 2.cmake 3.24.01 前言 当我们只有一个.c文件时直接使用vscodeCode Runner插件即可完成编译&#xff0c;如果我们的工程很复杂包含多个.c文件时建议使用cmake来生成对应的make&#xff0c;指导编译器完成编译&#xff0c;否则会提示各…

数字图像处理(图像灰度变换、图像直方图及均衡、图像中值滤波、图像空域锐化增强、图像频域滤波)

数字图像处理&#xff08;图像灰度变换、图像直方图及均衡、图像中值滤波、图像空域锐化增强、图像频域滤波&#xff09; 目录 1 图像灰度变换 1.1 灰度线性变换 1.2 图像二值化 1.3 负象变换 1.4 灰度非线性变换 1.5 程序设计流程图 2 图像直方图及均衡 2.1 直方图 2…

无心剑七绝《高斯黎曼》

七绝高斯黎曼 高耸云端四海惊 斯人伟绩震豪英 黎霞璀璨通灵处 曼妙方程万世名 2024年1月6日 平水韵八庚平韵 《七绝高斯黎曼》是无心剑所作的一首以数学家为主题的七言绝句。全诗巧妙地将两位杰出的数学家——高斯&#xff08;Carl Friedrich Gauss&#xff09;与黎曼&#…

大模型机器人原理解析:如何从RT/RT2、Berkeley Gello到发展到斯坦福Mobile ALOHA、Google家务机器人

前言 23年7月&#xff0c;我在朋友圈评估Google的RT2说道&#xff1a; “大模型正在革新一切领域啊&#xff0c;超帅&#xff0c;通过大模型不仅能理解“人话”&#xff0c;还能对“人话”进行推理&#xff0c;并转变为机器人能理解的指令&#xff0c;从而分阶段完成任务。回…

express框架

目录 一、express介绍二、express 使用2.1 express下载2.2 express初体验 三、express 路由3.1 路由的使用3.2 获取参数3.3 获取路由参数 四、express响应设置五、express中间件5.1 什么是中间件5.2 中间件的作用5.3 中间件的类型5.3.1 定义全局中间件5.3.2 多个全局中间件5.3.…

协程池与新脚本语言

今天的主人公名为——Melang。 这是一款使用C语言开发的“新”的脚本语言&#xff0c;然而其已经默默问世了6年之久。 下面笔者就带你走进Melang world。 What is Melang Melang是一款协程并发脚本语言。它是一款解释型&#xff0c;而非编译型语言。 在Melang中&#xff…

html中的form表单以及相关控件input、文本域、下拉select等等的详细解释 ,点赞加关注持续更新~

文章目录 表单创建表单forminput 标签input标签的value属性设置input标签格式单选框多选框上传文件下拉菜单文本域设置文本域格式label 标签按钮 表单 作用&#xff1a;收集用户信息。 使用场景&#xff1a; 登录页面注册页面搜索区域 创建表单form <form action".…

实战环境搭建-linux下安装jdk1.8

查看安装jdk版本信息,主要是怕之前有遗漏的,或者安装失败的java rpm -qa | grep java 显示如下信息: 卸载: rpm -e --nodeps java-1.7.0-openjdk-1.7.0.261-2.6.22.2.el7_8.x86_64 rpm -e --nodeps java-1.8.0-openjdk-1.8.0.262.b10-1.el7.x86_64 还有一些其他的命令…

MATLAB插值函数

一、MATLAB插值函数概览 1&#xff09;本节重点介绍的插值函数 MATLAB插值函数适用情况基础句式interp1 函数interp1 主要用于一维数据的插值interp1(x, y, x_interp, ‘linear’); 其中 x 和 y 是已知数据点&#xff0c;x_interp 是要插值的目标点。interp2 函数interp2 用于…

【STM32】PWR电源控制

1 PWR简介 PWR&#xff08;Power Control&#xff09;电源控制 PWR负责管理STM32内部的电源供电部分&#xff0c;可以实现可编程电压监测器和低功耗模式的功能 可编程电压监测器&#xff08;PVD&#xff09;可以监控VDD电源电压&#xff0c;当VDD下降到PVD阀值以下或上升到P…

回首2023,期待2024!

2023&#xff0c;在改变中到来 2023年1月1日&#xff0c;我从成都冷清的学校回到了哈尔滨的老家&#xff0c;开始了保研之前的最后一个寒假 当时的目标是将之前的科研理论转化为实际&#xff0c;生产出一篇sci&#xff0c;助力保研加分 星移斗转&#xff0c;事与愿违&#x…

从零实现CLIP模型

1. 引言 CLIP代表语言图像对比预训练模型&#xff0c;是OpenAI于2021年开发的一个深度学习模型。CLIP模型中图像和文本嵌入共享相同的潜在特征空间&#xff0c;从而能够在两种模式之间直接进行对比学习。这是通过训练模型使相关的图像和文本更紧密地结合在一起&#xff0c;同时…

MySQL高级DBA的理论与实践,MySQL数据库管理员从入门到精通

一、教程描述 数据库管理员&#xff08;Database Administrator&#xff09;&#xff0c;简称DBA&#xff0c;想要成为高级的MySQL DBA&#xff0c;就要耐得住寂寞&#xff0c;持续不断地学习&#xff0c;除了数据库专业知识外&#xff0c;还需要了解主机、系统、网络、存储、…

SSD固态硬盘的黄金原则:抱最高的希望,做最坏的打算-1

随着SSD固态硬盘日益普及&#xff0c;在个人电脑中已成为基本的配置选项。在体验SSD固态硬盘带来的性能优势的同时&#xff0c;你有没有想过一个问题&#xff0c;SSD的数据如果误删除或发生故障丢失&#xff0c;还有没有可能找回来呢&#xff1f;这也许是固态硬盘飞入寻常百姓家…

C++_命令行操作

命令行操作 介绍第一步编译 源码第二部 找到exe 可执行文件第三步看图操作代码测试源码测试结果 介绍 本文介绍命令行操作 1.argc 表示当前输入 参数个数 2.argv 表示当前输入 字符串内容 第一步编译 源码 #include<iostream> #include<string>using namespace st…

构建网络信息安全的中国方案 - 国密SSL协议介绍以及国密Nginx服务器部署

国密SSL协议 国密SSL协议指的是采用国密算法&#xff0c;符合国密标准的安全传输协议。简而言之&#xff0c;国密SSL就是SSL/TLS协议的国密版本。TLS协议定义有三个版本号&#xff0c;为0x0301、0x0302、0x0303&#xff0c;分别对应TLS 1.0、1.1、1.2。国密SSL为了避免冲突&am…