Linked List

文章目录

  • 链表
    • 定义
    • 专业术语
    • 代码
    • 链表分类
    • 常见算法
    • 链表创建和常用算法
  • 链表总结

链表

补充知识
typedef
给类型换名字,比如

typedef struct Student
{int sid;char name[100];char sex;
}ST;//ST就代表了struct Student
//即这上方一大坨都可以用ST表示
//原先结构体定义对象是通过下面这种方式实现的
struct Student st;
//现在使用typedef后,即可用下方方式定义
ST st;

或者来一个结构体指针定义。

typedef struct Student
{int sid;char name[100];char sex;
}*PST;
//这样PST等价于struct Student *
//这样初始化后就可以直接初始化一个结构体指针
PST ps = &st;
//之后ps进行指针的调用就行,例如下所示
ps->sid = 99;

离散存储

离散的含义,任何一个点到其他点之间是有间距的。

定义

n个节点离散分配,彼此通过指针相连接,每个节点只有一个前驱节点,每个节点只有一个后继节点,首节点没有前驱节点,尾节点没有后继节点。

专业术语

  • 首节点:第一个有效的节点。
  • 尾节点:最后一个有效节点。
  • 头结点:在首节点的前面加上这个结点,即第一个有效节点前的节点叫做头结点。头结点里面没有存放有效数据,也没有存放链表有效节点的个数,其真正含义是可以方便我们对链表进行操作(增删改查)。
  • 头指针:指向头结点的指针变量(存放了头结点的地址)。
  • 尾指针:指向尾节点的指针变量。

确定一个链表需要几个参数?
首节点可以通过头结点推出来,所以不是必须的,尾指针是0,因为没有后继节点,所以尾指针也不是必须的。尾节点也不是必须的,找到最后空的就知道尾节点,所以也不是必须的。头指针包含了指向头结点的地址,所以头结点也不是必须的,记下头指针就行。首节点可以由头结点推出来,所以首节点也不是必须的。所以综上,只要知道头结点的地址,就可以把整个链表的所有信息都找到。所以说确定一个链表只需要一个参数,即为头指针。
头结点的数据类型和首节点的数据类型是一样的。

代码

通过代码来模拟链表。
每一个节点的数据类型都是一模一样的,一个节点可以分成两部分,一部分是存放有效的数据,另有一部分是存放指针,指向后面的一个节点。这样就造成了每一个节点的数据类型是一样的。这里面的指针指向的是第二个节点的整体。
在这里插入图片描述
所以现在是包含了一个数据域一个指针域,

typedef struct Node{int data;//数据域struct Node *pNext;//指针域 //这里的指针域指向的是与其数据类型一致,但是另外一个节点。(下一节点的地址)(本节点的指针指向了下一节点)
}NODE, *PNODE;
//NODE是struct Node类型,*PNODE是struct Node *类型,记住struct Node是包含了整个整体的,要带上花括号{},即struct Node{}

链表分类

  • 单向链表
  • 双向链表:这下相比单链表,每个节点分成了三个部分,分别有指向自己的前驱和后继的指针,以及存放有效值。
  • 循环链表:能通过任何一个节点找到其他所有的节点,就是首尾节点连接了。
  • 非循环链表

常见算法

  1. 遍历
  2. 查找
  3. 清空
  4. 销毁
  5. 求长度
  6. 排序
  7. 删除节点
  8. 插入节点

狭义的算法是与数据的存储方式密切相关的,广义的算法是与数据的存储方式无关。泛型是利用某种技术达到的效果就是,不同的存存储方式,执行的操作时是一样的。(泛型是一种假象)

插入节点伪代码:

r = p->next;
p->next = q;
q->next = r;
//
q->next = p->next;
p->next = q;
//以上两种方法都能实现q节点插入到p和p.next中间

删除节点的伪代码:

r = p->next;
p->next = p-next->next;
free(r);
//C当中不会自动释放内存,所以得手动释放内存,free
//C++当中是delete

链表创建和常用算法

#include <iostream>
#include <cmalloc>using namespace std;typedef struct Node{int data;//数据域struct Node *pNext;//指针域
}Node, *PNODE;
//现在就是定义了这么一个数据类型,叫做struct Node。//函数声明
PNODE create_list(void);
void traverse_list(PNODE pHead);//遍历
bool is_empty(PNODE pHead);//判断是否为空,就看pHead->pNext == nullptr的结果
int length_list(PNODE);//链表长度
bool insert_list(PNODE, int, int);
bool delete_list(PNODE, int, int*);
//可以把删除的结点放到第三个参数当中去,也就是delete删除的元素可以暂存到第三个参数当中去。delete_list(pHead, 3, &val);
void sort_list(PNODE);//排序int main(void){PNODE pHead = nullptr;//等价于struct Node *pHead = nullptr;pHead = create_list();//create_list()函数的功能就是创建一个非循环单向链表,然后把单向链表的首地址赋给pHead。//创建一个非循环单向链表,并将该链表的头结点地址,赋给pHead。sort_list(pHead);traverse_list(pHead);//insert_list(pHead, 4, 33);int len = length_list(pHead);cout << "链表长度是: " << endl;//这是代表遍历的意思,之前也说了,推出链表的所有参数只需要一个头结点指针(头指针)就行。if (is_empty(pHead))cout << "链表为空" << "\n" << endl;elsecout << "链表非空" << "\n" << endl;return 0;
}
//因为动态内存管理,在一个函数当中申请的内存可以在另外一个函数当中调用。//创建函数
PNODE create_list(void)//最后只要分配好的内存地址就行
{int len;//存放有效节点的个数int val;//临时存放用户输入的结点的值//分配了一个不存放数据的头结点PNODE pHead = (PNODE)malloc(sizeof(NODE));if (pHead == nullptr){cout << "分配失败,程序终止" << endl;return -1;}PNODE pTail = pHead;pTail->pNext = nullptr;//这样永远指向尾节点cout << "请输入您需要生产的链表节点的个数:len = " << endl;cin >> len;for(int i = 0; i < len; ++i){cout << "请输入第 " << i+1 << " 个节点的值: " << endl;//i+1是因为链表从1开始的,这里的i是从0开始的cin >> val;//每循环一次,就用pNew造出一个新的节点PNODE pNew = (PNODE)malloc(sizeof(NODE));//临时节点if (pNew == nullptr){cout << "分配失败,程序终止" << endl;return -1;}//总而言之就是利用pHead生成一个临时节点,然后把数值放到临时节点的数据域当中去,再把临时节点挂到之前一个节点的后面,最后再把临时节点清空。但是这样有问题,每次新生成的结点都会挂到之前一个节点的后面,造成“一对多”的现象,所以解决方法就是,每次新生成的结点都要挂到整个链表的尾节点的后面。所以定义一个pTail永远指向尾节点。pNew->data = val;pTail->pNext = pNew;pNew->pNext = nullptr;pTail = pNew;}return pHead;//返回头结点地址
}//遍历函数
//主要思路,先定义一个指针p,指向第一个有效的结点,如果此时指向的结点不为空,就把数据域给输出就行,再往后移一个。
void travese_list(PNODE pHead)
{PNONDE p = pHead->pNext;while(p != nullptr){cout << p_data << endl;p = p->pNext;//一定要往后移,往后移才能指向下一个}cout << "\n" << "输出完毕" << endl;return;
}//判断是否为空的函数
bool is_empty(PNODE pHead)
{if(pHead->pNext == nullptr)return true;elsereturn false;
}//长度函数
int length_list(PNODE pHead)
{PNODE p = pHead->pNext;int cnt = 0;while(p->pNext != nullptr){++cnt;p = p->pNext;}return cnt;
}//排序函数
//依次把数每次和后面的数进行比较,这下就是升序排序的
void sort_list(PNODE pHead)
{int i, j, t;int len = length_list(pHead);PNODE p, q;for (i = 0 ,p = pHead->pNext; i<len-1; ++i, p = p->pNext){for (j = j+1, q = p->pNext; j<len; ++j, q = q->pNext){if (p->data > q->data) //类似于数组中的a[i]>a[j]{t = p->data;//t = a[i];p->data = q->data;//a[i] = a[j];q->data = t;//a[j] = t;}}}return;
}
//听完郝老师讲的这里,我才真正知道在C++当中函数重载的具体意思,operator之类的醍醐灌顶。//插入函数
//在pHead所指向的链表的第pos个节点的前面插入一个新的节点,该节点的值是val,并且pos的值是从1开始。记住pos不包含头结点,而是从首节点(有效节点)开始。
bool insert_list(PNODE pHead, int pos, int val)
{int i = 0;PNODE p = pHead;while(p != nullptr && i < pos-1)//这里的p是代表不是最后一个,i<pos-1表示找到插入位置之前的结点。//while函数的作用是将p移动到pos-1的位置,画图就好理解。{p = p->pNext;++i;}if (i > pos-1 || p == nullptr)//这里的if是判断要插入的位置是否超出了链表多一个位置//i>pos-1是判断pos是否为小于1的数,若是则直接false//p = nullptr是为了处理插入的位置,例如有5个节点,现在在第7个节点位置插入。因为这是接着while循环的,所以多一层if判断经过while循环后的p的变化,同时还能判断是否为空链表的存在。return false;PNODE pNew = (PNODE)malloc(sizeof(NODE));if (pNew == nullptr){cout << "动态内存分配失败" << "\n" << endl;return -1;}//以上pos等于1的时候,不执行前面两个表达式,即while和if,直接执行后面的,此时将新元素插入到头结点和第一个有效节点之间。pNew->data = val;PNODE q = p->pNext;p->pNext = pNew;pNew->pNext = q;return true;
}//删除函数
bool delete_list(PNODE p, int pos, int*pVal)
{int i = 0;PNODE p = pHead;while(p->pNext != nullptr && i < pos-1){p = p->pNext;++i;}if (i > pos-1 || p->pNext == nullptr)return false;PNODE q = p->pNext;*pVal = q->data;//删除p节点后面的结点p->pNext = p->pNext->pNext;free(q);q = nullptr;return true;
}

链表总结

狭义的讲:数据结构是专门研究数据存储的问题,数据的存储包含两方面,个体的存储,以及个体关系的存储。算法是对存储数据的操作。
广义的讲:数据结构既包含数据的存储也包含数据的操作,对存储数据的操作就是算法。

算法:
狭义的讲:算法是和数据的存储方式密切相关。
广义的讲:算法和数据的存储方式无关。
这就是泛型的思想。

数据的存储结构有几种:
线性:连续存储【数组】,离散存储【链表】,线性结构的应用—栈,队列。

链表的优缺点:

  1. 插入和删除快
  2. 存取元素速度慢
  3. 存储容量无限

数组的优缺点:

  1. 存取速度很快
  2. 但事先必须知道数组的长度
  3. 插入删除元素很慢
  4. 空间通常是有限制的
  5. 需要大块连续的内存块

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

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

相关文章

Springer独立出版 | 2023年触觉与虚拟现实国际会议(ICHVR 2023)

会议简介 Brief Introduction 2023年触觉与虚拟现实国际会议(ICHVR 2023) 会议时间&#xff1a;2023年12月15日-17日 召开地点&#xff1a;中国北海 大会官网&#xff1a;www.ichvr.org 2023年触觉与虚拟现实国际会议(ICHVR 2023)由东南大学、上海交通大学联合主办&#xff1b;…

PHP使用Redis实战实录4:单例模式和面向过程操作redis的语法

PHP使用Redis实战实录系列 PHP使用Redis实战实录1&#xff1a;宝塔环境搭建、6379端口配置、Redis服务启动失败解决方案PHP使用Redis实战实录2&#xff1a;Redis扩展方法和PHP连接Redis的多种方案PHP使用Redis实战实录3&#xff1a;数据类型比较、大小限制和性能扩展PHP使用Re…

ajax概述

目录 1.什么是ajax 2.ja原生ajax 3.jQuery框架的ajax 4.综合案例 1.什么是ajax Ajax 即"Asynchronous Javascript And XML"&#xff08;异步 JavaScript 和 XML&#xff09;&#xff0c;是指一种创建交互式网页应用的网页开发技术。Ajax 异步 JavaScript 和 XML&…

多线程(JavaEE初阶系列5)

目录 前言&#xff1a; 1.什么是定时器 2.标准库中的定时器及使用 3.实现定时器 结束语&#xff1a; 前言&#xff1a; 在上一节中小编给大家介绍了多线程中的两个设计模式&#xff0c;单例模式和阻塞式队列模式&#xff0c;在单例模式中又有两种实现方式一种是懒汉模式&a…

初识TDMQ

目录 一&#xff1a;需求背景二&#xff1a;相关文档三&#xff1a;验证TDMQ广播消息 一&#xff1a;需求背景 目前公司需要将决策引擎处理的结果&#xff0c; 一部分数据交给下游分析/入黑/通知等功能。因此就需要决策引擎生产结果让多方下游去消费。 而我需要实现下游的一部…

STM32使用HAL库BH1750光照度传感器

开发环境 单片机&#xff1a;STM32F103C8T6 光照度传感器&#xff1a;BH1750 IDE&#xff1a;KEILSTM32CUBEMX 单片机配置 1、STM32CUBEMX BH1750代码 1、头文件 /* ************************************************* BH1750光照数据计算&#xff08;LUX&#xff09; …

Shell脚本实现分库分表操作

目录 一&#xff0c;分库备份 二&#xff0c;分库操作 三&#xff0c;分库分表备份 四&#xff0c;备份还原 一&#xff0c;分库备份 #!/bin/bash mysql_cmd-uroot -pzly666666 bak_path/backup/db [ -d ${bak_path} ] || mkdir -p ${bak_path}mysql ${mysql_cmd} -e show…

解决Django报错 : No module named ‘MySQLdb‘

Django的版本是2.0&#xff0c;Python的版本号是3.6.4 在models.py创建好了模型类之后使用命令&#xff1a;python manage.py makemigrations 进行迁移&#xff0c;但是突然报错&#xff1a;ImportError:No module named MySQLdb 查询了相关资料发现python2.x版本是支持mysql…

Linux - PostgreSQL 适用于9.x 以上的 tar.gz 源码安装与理解 - 报错集锦

这里写目录标题 序言主要内容bash 配置文件个人理解关于初始化 PostgreSQL 数据库的理解 启动方法检查服务器是否在PostgreSQL中运行关闭 postgresql 数据库方法参考链接 序言 PostgreSQL 9.x 以下版本笔者没用过&#xff0c;具体操作看参考链接&#xff0c;笔者就不记录重复操…

回答网友 修改一个exe

网友说&#xff1a;他有个很多年前的没有源码的exe&#xff0c;在win10上没法用&#xff0c;让俺看一下。 俺看了一下&#xff0c;发现是窗体设计的背景色的问题。这个程序的背景色用的是clInactiveCaptionText。clInactiveCaptionText 在win10之前的系统上是灰色&#xff0c;但…

幅度调制与角度调制

文章目录 前言一、调制简介1、调制定义2、调制目的3、调制的分类 二、幅度调制&#xff08;线性调制&#xff09;1、幅度调制的一般模型2、常规双边带调幅 AM①、AM 信号的产生②、AM 调制器的模型③、AM 波形和频谱④、AM 信号的特点⑤、AM 包络检波⑥、调幅系数 3、抑制载波双…

Java中对Redis的常用操作

目录 数据类型五种常用数据类型介绍各种数据类型特点 常用命令字符串操作命令哈希操作命令列表操作命令集合操作命令有序集合操作命令通用命令 在Java中操作RedisRedis的Java客户端Spring Data Redis使用方式介绍环境搭建配置Redis数据源编写配置类&#xff0c;创建RedisTempla…

推荐带500创作模型的付费创作V2.1.0独立版系统源码

ChatGPT 付费创作系统 V2.1.0 提供最新的对应版本小程序端&#xff0c;上一版本增加了 PC 端绘画功能&#xff0c; 绘画功能采用其他绘画接口 – 意间 AI&#xff0c;本版新增了百度文心一言接口。 后台一些小细节的优化及一些小 BUG 的处理&#xff0c;前端进行了些小细节优…

Spring依赖注入和ioc在spring中的实现方式

目录 一、依赖注入 1.IOC思想 2.什么是依赖注入&#xff1f; 3.实例化对象中有pojo类型属性 二、IOC在Spring中的实现方式 1.获取bean的三种方式 1.1根据bean的id获取 1.2根据bean的类型获取&#xff08;最常用&#xff0c;因为在IOC容器中&#xff0c;一个类型的bean只…

<MySQL> Centos 7环境安装MySQL

Centos 7环境安装MySQL 1.卸载不要的环境 停止MySQL服务 systemctl stop mariadb.service systemctl stop mysqld禁止MySQL服务开机自启 systemctl disable mysqld卸载MySQL软件包 yum remove mysql-server mysql-client删除MySQL数据目录 rm -rf /var/lib/mysql清理MySQ…

[golang gin框架] 42.Gin商城项目-微服务实战之后台Rbac微服务角色增删改查微服务

一.重构后台Rbac用户登录微服务功能 上一节讲解了后台Rbac微服务用户登录功能以及Gorm数据库配置单独抽离&#xff0c;Consul配置单独抽离&#xff0c;这一节讲解后台Rbac微服务角色增删改查微服务功能&#xff0c;Rbac微服务角色增删改查微服务和后台Rbac用户登录微服务是属于…

SpringBoot入门

目录 一、创建项目 二、项目结构 三、起步依赖 四、简单请求接口 控制类 1、无参数 2、简单参数 3、实体参数 4、数组集合参数 5、json参数 五、统一响应结果 result.java HelloResponse.java 测试结果 一、创建项目 Spring官方骨架&#xff0c;可以理解为Sprin…

提升开发效率,Lombok的链式编程和构建模式

目录 链式编程 定义 代码示例 ​编辑 Accessors(chaintrue) 开启链式编程 ​编辑 Accessors(chain true,fluent true) 去除set和get 构建模式 定义 代码示例 ​编辑 踩坑 Singular 定义 代码示例 踩坑默认值情况 ​编辑 With 定义 代码示例 链式编程 定义 链…

ChatGPT的应用与发展趋势:解析人工智能的新风口

目录 优势 应用领域 发展趋势 总结 在人工智能技术迅猛发展的时代&#xff0c;自然语言处理系统的提升一直是研究者们追求的目标。作为人工智能领域的重要突破之一&#xff0c;ChatGPT以其出色的语言模型和交互能力&#xff0c;在智能对话领域取得了重要的进展。 ChatGPT是…

一文教会你单向链表

目录 一、什么是链表&#xff1f; 1.链表的定义 2.链表的实现 2.1链表的定义 2.2创建一个链表 二、链表的各个接口 1.创建节点 2.头插(将新创建的节点作为头插入到链表中) 3.打印链表 4.尾插(将新创建的节点插入到链表的末端) 5.头删 6.尾删 7.查找 8.删除指定节点位…