基础数据结构(1):链表

news2024/11/15 23:35:06

    在学习算法时,发现用什么数据结构来存储数据是很重要的,所以学习数据结构也是必须的,先从基础数据结构:数组,字符串,链表,栈,队列,树,矩阵,邻接表,哈希表等,数组和字符串我们已经了解的很多了,所以我们从链表开始学习,了解什么是链表,链表存储数据的方式,以及如何对链表进行各种操作,如何用数组来模拟链表,如何用栈来做链表相关的题目。

1.何为链表

  由于顺序表的插入删除操作需要移动大量的元素,影响了运行效率,因此引入了线性表的链式存储——单链表。单链表通过一组任意的存储单元来存储线性表中的数据元素,不需要使用地址连续的存储单元,因此它不要求在逻辑上相邻的两个元素在物理位置上也相邻。同时因为单链表是非随机的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。

      我们再看链表是什么:

      链表其实是由一个个结点组成,每个结点之间通过链接更新串联起来,每个结点都有一个后继结点,最后一个结点的后继结点为空结点

     图中就是一个链表其中橙色结点被称为黄色结点的前驱结点,黄色结点被称为橙色结点的后继结点,链表其实有单向链表、双向链表、循环链表等,这里先只介绍单向链表。那既然结点存储数据,怎么找到后驱结点呢?下面一起来看看吧

2.链表结点的定义

typedef struct ListNode
{
   int data;
   struct ListNode* next;
}ListNode;

     这就是一个结点的定义,我们把一个结点看成一个结构体,其中data是数据域,可以是任意类型,而struct ListNode* next定义了一个指向ListNode结构体的指针,这个指针的地址是后继结点,将指向下一个结点,这就是指针域,如下图所示  

      下面看看具体怎么创建一个链表的结点

3.链表结点创建

ListNode* ListCreateNode(int data)
{
   ListNode* node=(List*)malloc(sizeof(ListNode));
   node->data=data;
   node->next=NULL;
   return node;
}

     我们先用malloc函数分配一块内存空间,用来存放ListNode即链表对象,将数据域置为函数传参data,将指针域置为NULL,代表这是一个孤立的链表结点,最后返回这个结点的指针。

4.虚拟头结点

     为了方便对链表进行操作,避免第一个结点无法操作的问题,我们往往会建立一个虚拟头结点,这个头结点上不存储数据,只是指向链表的第一个结点

ListNode* head=ListCreateNode(-1);

5.链表的创建及初始化

     单链表有两种:一种是带虚拟头结点的,一种不带虚拟头结点。总的来说,带头结点的单链表相对于不带头结点的单链表来说,更加方便对链表进行操作,所以很多时候我们都是用带头结点的单链表,这里我们也只用学习带头结点的即可

5.1初始化带头结点的单链表

void InitList(ListNode* head) {
	head=(ListNode*)malloc(sizeof(ListNode));
    head->next=NULL;
}

5.2创建带头结点的单链表

5.2.1头插法

         头插法顾名思义就是从链表开头插入,先插入的后输出,后插入的先输入,例如,我想创建一个链表(4,7,9),输出就是(9,7,4)。

ListNode* HeadInsert(ListNode* head) {
    initlist(head); //初始化
    int n;
    scanf_s("%d",&n);
    for(int i=0;i<n;i++) 
    {
        ListNode* node = (ListNode*)malloc(sizeof(ListNode));
        int data;
        scanf_s("%d", &data);
        node->data = data;
        node->next = head->next;
        head->next = node;
    }
    return head;
}

5.2尾插法

     尾插法顾名思义就是从链表末尾开始插入,先插入的先输出,后插入的后输出

ListNode* TailInsert(ListNode* head) {
    initlist(head); //初始化
    ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
    cur = head;
    int n,data;
    scanf_s("%d",&n);
    for(int i=0;i<n;i++) 
    {
        ListNode* node = (ListNode*)malloc(sizeof(ListNode));
        scanf_s("%d", &data)
        node->data = data;
        node->next =NULL;
        cur->next = node;
        cur = cur->next; 
    }
    return head;
}

6.链表基础操作 

     创建完链表之后,我们就要对链表进行操作了,常见的操作就是增删改查

6.1遍历操作

void PrintList(ListNode* head) {
    ListNode* cur = head->next;
    while (cur) {
        printf("%d ", cur->data);
        cur = cur->next;
    }
    printf("\n");
}

6.2求单链表的长度

int Length(ListNode* head) {
    ListNode* cur = head->next;
    int len = 0;
    while (cur) {
        len++;
        cur = cur->next;
    }
    return len;
}

6.3查找操作

6.3.1按值查找
ListNode* locateElem(ListNode* head, int data)
{
    ListNode* cur = head->next;
    while (cur && cur->data != data)
    {
        cur = cur->next;
    }
    return cur;
}
6.3.2按位查找
ListNode* getElem(ListNode* head, int i)
{
    int j = 1;
    ListNode* cur = head->next;
    if (i == 0)return head;
    if (i < 1)return NULL;
    while (cur && j < i)
    {
        cur = cur->next;
        j++;
    }
    return cur;
}

6.4插入操作

void Insert(ListNode* head, int i, int data)
{
    ListNode* pre = getElem(head, i - 1);
    ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
    cur->data = data;
    cur->next = pre->next;
    pre->next = cur;
}

6.5删除操作

     将链表的第i个结点删除

void Delete(ListNode* head, int i) {
    if (i<1 || i>Length(head))return;
    ListNode* pre = getElem(head, i - 1);
    ListNode* cur = pre->next;
    pre->next = cur->next;
    free(cur);
}

6.6判空操作

bool Empty(ListNode* head) {
    if (head->next == NULL) {
        printf("Head is null\n");
        return true;
    }
    else {
        printf("Head is not null\n");
        return false;
    }
}

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

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

相关文章

3D小球跑酷

目录 一、前言 二、开发环境 三、场景搭建 1. 创建项目 2. 创建场景内物体 2.1 创建跑道 2.2 创建玩家 2.3 创建障碍物 2.4 改变跑道和障碍物的颜色 2.4.1 创建材质 2.4.2 给跑道和障碍物更换材质 四、功能脚本实现 1. 创建玩家脚本 2. 相机跟随 3. 胜负的判定 3…

spring boot版本升级遇到的一些问题

背景&#xff1a;由于项目需求&#xff0c;需要将nacos 1.4.6版本升级到2.x版本&#xff0c;由此引发的springboot、springcloud、springcloud Alibaba一系列版本变更。 旧版本分别为&#xff1a; Spring Boot 2.3.5.RELEASE Spring Cloud Hoxton.SR9 Spring Cloud Alibaba 2.2…

基于RocketMQ实现分布式事务

前言 在上一篇文章Spring Boot自动装配原理以及实践我们完成了服务通用日志监控组件的开发&#xff0c;确保每个服务都可以基于一个注解实现业务功能的监控。 而本文我们尝试基于RocketMQ实现下单的分布式的事务。可能会有读者会有疑问&#xff0c;之前我们不是基于Seata完成了…

让AIGC成为你的智能外脑,助力你的工作和生活

人工智能成为智能外脑 在当前的科技浪潮中&#xff0c;人工智能技术正在以前所未有的速度改变着我们的生活和工作方式。其中&#xff0c;AIGC技术以其强大的潜力和广泛的应用前景&#xff0c;正在引领着这场革命。 AIGC技术是一种基于人工智能的生成式技术&#xff0c;它可以通…

SQL 的执行顺序,你搞清楚了吗?

这是一条标准的查询语句: 这是我们实际上SQL执行顺序&#xff1a; from 子句组装来自不同数据源的数据&#xff1b;where 子句基于指定的条件对记录行进行筛选&#xff1b;group by 子句将数据划分为多个分组&#xff1b;使用聚集函数进行计算&#xff1b;使用 having 子句筛选…

【Python必做100题】之第二十二题(复制列表)

题目&#xff1a;将一个列表的数据复制到另一个列表中 重点&#xff1a;确保复制到位要导入copy方法进行深度复制 代码如下&#xff1a; #将一个列表的数据复制到另一个列表中 import copy list [1,2,3,4] print(list) list1 copy.copy(list) list[0] 30 print(list) pri…

CentOS:Docker 创建及镜像删除

1、安装docker 远程连接服务器&#xff0c;可以直接下载netsarang比较好用 家庭/学校免费 - NetSarang Website 如果有残留docker未删除干净&#xff0c;请使用 sudo yum -y remove docker docker-common docker-selinux docker-engine Step1&#xff1a;安装必要的一些…

docker 安装及配置 nginx + tomcat(四):高可用

文章目录 1. 引言2. 高可用架构3. 实际步骤3.1 虚拟机新建系统3.2 安装 keepalived3.3 配置 keepalived3.4 启动 keepalived3.5 验证高可用3.5.1 查看当前效果3.5.2 模拟灾难 4 参考 1. 引言 前情提要&#xff1a; 《docker 安装及配置 nginx tomcat&#xff08;一&#xff0…

2.vue学习(8-13)

文章目录 8.数据绑定9.el与data的2种写法10.理解mvvm11.object.defineProperty12. 理解数据代理13 vue中的数据代理 8.数据绑定 单向数据绑定就是我们学的v-bind的方式&#xff0c;vue对象变了&#xff0c;页面才变。但是页面变了&#xff0c;vue对象不会变。 双向数据绑定需要…

项目经理和产品经理的区别,如何判断自己适合哪个,从事该岗位前期需做的准备(学习技能考、哪些证书)?

最近很多人咨询“项目经理跟产品经理该怎么选&#xff0c;我更适合哪个&#xff1f;”“项目经理跟产品经理哪个更有钱途 ”“项目经理转产品经理好转吗”等等&#xff0c;今天就一次性说清楚项目经理跟产品经理有什么区别&#xff0c;应该怎么选择。 不想看长篇大论的&#x…

[计网02] 数据链路层 笔记 总结 详解

目录 数据链路层概述 主要功能 封装成帧 透明传输 差错检测 冗余码 差错控制 检错编码 纠错编码 奇偶效验法 CRC循环冗余码 静态分配信道 频分多路复用FDM 时分多路复用TDM 波分多路复用WDM 码分多路复用CDM 随机访问介质的访问控制 ALOHA CSMA CSMA/CD CSMA/…

关于“Python”的核心知识点整理大全30

目录 12.2.3 在 OS X 系统中安装 Pygame 12.2.4 在 Windows 系统中安装 Pygame 12.3 开始游戏项目 12.3.1 创建 Pygame 窗口以及响应用户输入 首先&#xff0c;我们创建一个空的Pygame窗口。使用Pygame编写的游戏的基本结构如下&#xff1a; alien_invasion.py 12.3.2 设…

零刻EQ12 N100 双2.5G网口 All In One新手教程

零刻EQ12 N100 双2.5G网口 All In One新手教程 前言1.硬件配置2.准备工作2.1. ESXI8.0U2镜像2.2. Rufus磁盘工具下载2.3. ikuai镜像下载2.4. StarWindConverter虚拟磁盘格式转换工具下载2.5. OpenWrt镜像下载2.6. 黑群晖RR引导镜像下载(DSM7.2)2.7. 需要准备的硬件2.8. 格式化需…

【C语言(十五)】

动态内存管理 一、为什么要有动态内存分配? 我们已经掌握的内存开辟方式有&#xff1a; int val 20 ; // 在栈空间上开辟四个字节 char arr[ 10 ] { 0 }; // 在栈空间上开辟 10 个字节的连续空间 但是上述的开辟空间的方式有两个特点&#xff1a; • 空间开辟大小是固…

vCenter HA拆分和部署

原创作者&#xff1a;运维工程师 谢晋 vCenter HA拆分和部署 拆分vCenter HA部署vCenter HA 拆分vCenter HA 客户vCenter HA内一台虚拟机出现故障无法连接&#xff0c;报错如下&#xff1a; 点击移除集群报错如下&#xff1a; 查找官方KB&#xff0c;按照官方KB进行移除…

货仓选址

title: 货仓选址 date: 2023-12-19 15:06:02 tags: 排序 categories: 算法进阶指南 题目大意 解题思路 将数组排序后&#xff0c;将货仓建在 x x x 坐标处&#xff0c;其左侧和右侧的商家数量相同的时候最优 实现代码 #include<bits/stdc.h>using namespace std; type…

SQL进阶理论篇(十三):数据库的查询优化器是什么?

文章目录 简介什么是查询优化器查询优化器的两种优化方式总结参考文献 简介 事务可以让数据库在增删改查的过程中&#xff0c;保证数据的正确性和安全性&#xff0c;而索引可以帮数据库提升数据的查找效率。查询优化器&#xff0c;则是帮助我们获取更高的SQL查询性能。 本节我…

FreeRTOS的heap文件

在动态创建任务的时候, 只需要提供一个任务句柄, 内存的分配, TCB的分配, 都是系统来进行的, 也是这个文件做的工作. heap文件一共有5个, 都是内存管理文件, 工程只需要一个就行, 这五个的内存分配方法都不一样. heap1: 只实现了malloc功能, 没有实现free功能.(不用) heap2: 实…

小程序使用web-view无法打开该H5页面不支持打开的解决方法

我在正式上线版小程序使用 web-view 组件测试时提示&#xff1a;“无法打开该页面&#xff0c;不支持打开 https://xxxxxx&#xff0c;请在“小程序右上角更多->反馈与投诉”中和开发者反馈。” 奇怪的是&#xff0c;“真机调试”、“开发模式”都可以使用 web-view 组件访…

【Netty】NIO与Netty核心概念

目录 NIO编程NIO介绍NIO和BIO的比较缓冲区(Buffer)基本介绍常用API缓冲区对象创建添加数据读取数据 通道(Channel)基本介绍Channel常用类ServerSocketChannelSocketChannel Selector (选择器)基本介绍常用API介绍示例代码 NIO 三大核心原理 Netty核心概念Netty 介绍原生 NIO 存…