数据结构(一)链表

目录

链表

单向链表

单向链表结构与基本操作

插入节点

删除节点

搜索节点

遍历链表

反转链表

双向链表

双向链表结构与基本操作

节点定义和创建

插入节点

删除节点

搜索节点

遍历链表

转链表反


在开始讲线性表之前,先给各位读者重新回顾一下链表

链表

单向链表

单向链表是一种基本的数据结构,由一系列节点组成,每个节点包含两部分:数据域指针域数据域存储数据,而指针域存储指向列表中下一个节点的指针。单向链表的特点是数据元素的排列呈现单一方向,即每个节点仅指向下一个节点,直到最后一个节点的指针通常指向NULL,表示链表的结束。

单向链表结构与基本操作

在C语言中,单向链表的节点可以这样定义

typedef struct Node {int data;                 // 数据域,存储节点的数据struct Node* next;        // 指针域,指向下一个节点的指针
} Node;

 创建节点:初始化一个节点,通常需要提供数据,节点的next指针设置为NULL

Node* createNode(int data) {Node* newNode = (Node*)malloc(sizeof(Node));if (newNode != NULL) {newNode->data = data;newNode->next = NULL;}return newNode;
}
插入节点

插入节点的基本过程:首先找到正确位置p,然后申请新结点t并对t的结点信息赋值,最后讲t插在p之后

插入到头部

void insertAtHead(Node** head, int data) {Node* newNode = createNode(data);newNode->next = *head;*head = newNode;
}

插入到尾部
在链表尾部插入节点需要遍历整个链表,直到找到最后一个节点。

void insertAtTail(Node** head, int data) {Node* newNode = createNode(data);if (*head == NULL) {*head = newNode;} else {Node* temp = *head;while (temp->next != NULL) {temp = temp->next;}temp->next = newNode;}
}

插入到特定位置

在链表的特定位置插入节点需要遍历链表直到达到指定位置的前一个节点。

void insertAtPosition(Node** head, int data, int position) {Node* newNode = createNode(data);if (position == 1) {insertAtHead(head, data);} else {Node* temp = *head;for (int i = 1; temp != NULL && i < position - 1; i++) {temp = temp->next;}if (temp == NULL) {printf("Position exceeds the length of the list.\n");} else {newNode->next = temp->next;temp->next = newNode;}}
}
删除节点

注意:删除一个节点后必须释放该节点的空间

删除头部节点

void deleteFromHead(Node** head) {if (*head != NULL) {Node* temp = *head;*head = (*head)->next;free(temp);}
}

删除尾部节点

删除尾部节点需要遍历整个链表以找到倒数第二个节点。

void deleteFromTail(Node** head) {if (*head == NULL) return;if ((*head)->next == NULL) {free(*head);*head = NULL;} else {Node* temp = *head;while (temp->next->next != NULL) {temp = temp->next;}free(temp->next);temp->next = NULL;}
}

删除特定位置的节点

删除特定位置的节点需要遍历链表直到找到该位置的前一个节点。

void deleteAtPosition(Node** head, int position) {if (*head == NULL) return;if (position == 1) {deleteFromHead(head);} else {Node* temp = *head;for (int i = 1; temp != NULL && i < position - 1; i++) {temp = temp->next;}if (temp == NULL || temp->next == NULL) {printf("Position exceeds the length of the list.\n");} else {Node* next = temp->next->next;free(temp->next);temp->next = next;}}
}
搜索节点

搜索节点涉及遍历链表以查找具有特定值的节点。

Node* search(Node* head, int key) {Node* current = head;while (current != NULL) {if (current->data == key) {return current;}current = current->next;}return NULL;
}
遍历链表

遍历链表是访问链表中每个节点的基本操作。

void printList(Node* head) {Node* current = head;while (current != NULL) {printf("%d -> ", current->data);current = current->next;}printf("NULL\n");
}
反转链表

反转链表需要改变每个节点的指针方向。

Node* reverseList(Node* head) {Node* prev = NULL;Node* current = head;Node* next = NULL;while (current != NULL) {next = current->next;current->next = prev;prev = current;current = next;}return prev;
}

双向链表

双向链表(Doubly Linked List)是一种链式数据结构,其中每个节点包含数据部分以及两个指针,分别指向前一个节点和后一个节点。这种结构允许从两个方向遍历链表:向前和向后。双向链表在插入和删除操作中比单向链表更加灵活,因为可以直接访问前驱和后继节点。

双向链表结构与基本操作

节点定义和创建

创建一个双向链表节点,需要初始化数据和两个指针:

typedef struct Node {int data;                 // 数据域,存储节点的数据struct Node* prev;        // 指向前一个节点的指针struct Node* next;        // 指向下一个节点的指针
} Node;Node* createNode(int data) {Node* newNode = (Node*)malloc(sizeof(Node));if (newNode != NULL) {newNode->data = data;newNode->prev = NULL;newNode->next = NULL;}return newNode;
}
插入节点

插入到头部

在头部插入节点,需要更新头节点的prev指针和新节点的next指针。

void insertAtHead(Node** head, int data) {Node* newNode = createNode(data);newNode->next = *head;if (*head != NULL) {(*head)->prev = newNode;}*head = newNode;
}

插入到尾部

在尾部插入节点,需要遍历链表找到尾节点,然后更新尾节点的next指针和新节点的prev指针。

void insertAtTail(Node** head, int data) {Node* newNode = createNode(data);if (*head == NULL) {*head = newNode;} else {Node* temp = *head;while (temp->next != NULL) {temp = temp->next;}temp->next = newNode;newNode->prev = temp;}
}

插入到特定位置

在特定位置插入节点,需要更新前一个节点的next指针和新节点的prev指针,以及新节点的next指针和后一个节点的prev指针。

void insertAtPosition(Node** head, int data, int position) {Node* newNode = createNode(data);if (position == 1) {insertAtHead(head, data);} else {Node* temp = *head;for (int i = 1; temp != NULL && i < position - 1; i++) {temp = temp->next;}if (temp == NULL) {printf("Position exceeds the length of the list.\n");} else {newNode->next = temp->next;newNode->prev = temp;if (temp->next != NULL) {temp->next->prev = newNode;}temp->next = newNode;}}
}
删除节点

删除头部节点:删除头部节点,需要更新头节点的prev指针和新头节点的next指针。

void deleteFromHead(Node** head) {if (*head == NULL) return;Node* temp = *head;*head = (*head)->next;if (*head != NULL) {(*head)->prev = NULL;}free(temp);
}

删除尾部节点:删除尾部节点,需要遍历链表找到倒数第二个节点,然后更新其next指针

void deleteFromTail(Node** head) {if (*head == NULL) return;if ((*head)->next == NULL) {free(*head);*head = NULL;} else {Node* temp = *head;while (temp->next->next != NULL) {temp = temp->next;}free(temp->next);temp->next = NULL;}
}

删除特定位置的节点:删除特定位置的节点,需要更新前一个节点的next指针和后一个节点的prev指针

void deleteAtPosition(Node** head, int position) {if (*head == NULL) return;if (position == 1) {deleteFromHead(head);} else {Node* temp = *head;for (int i = 1; temp != NULL && i < position; i++) {temp = temp->next;}if (temp == NULL) {printf("Position exceeds the length of the list.\n");} else {if (temp->prev != NULL) {temp->prev->next = temp->next;}if (temp->next != NULL) {temp->next->prev = temp->prev;}free(temp);}}
}
搜索节点

搜索节点,需要遍历链表直到找到具有特定值的节点。

Node* search(Node* head, int key) {Node* current = head;while (current != NULL) {if (current->data == key) {return current;}current = current->next;}return NULL;
}
遍历链表

向前遍历

void printListForward(Node* head) {Node* current = head;while (current != NULL) {printf("%d -> ", current->data);current = current->next;}printf("NULL\n");
}

向后遍历

void printListBackward(Node* head) {Node* current = head;while (current != NULL) {printf("%d <- ", current->data);current = current->prev;}printf("NULL\n");
}
转链表反
void reverseList(Node** head) {Node* temp = NULL;Node* current = *head;while (current != NULL) {temp = current->prev;current->prev = current->next;current->next = temp;current = current->prev;}if (temp != NULL) {*head = temp->prev;}
}

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

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

相关文章

hhdb数据库介绍(9-21)

计算节点参数说明 checkClusterBeforeDnSwitch 参数说明&#xff1a; PropertyValue参数值checkClusterBeforeDnSwitch是否可见否参数说明集群模式下触发数据节点高可用切换时&#xff0c;是否先判断集群所有成员正常再进行数据节点切换默认值falseReload是否生效是 参数设…

每日一练:【动态规划算法】斐波那契数列模型之第 N 个泰波那契数(easy)

1. 第 N 个泰波那契数&#xff08;easy&#xff09; 1. 题目链接&#xff1a;1137. 第 N 个泰波那契数 2. 题目描述 3.题目分析 这题我们要求第n个泰波那契Tn的值&#xff0c;很明显的使用动态规划算法。 4.动态规划算法流程 1. 状态表示&#xff1a; 根据题目的要求及公…

网页抓取API,让数据获取更简单

网页抓取的过程通常分为以下步骤&#xff0c;尤其是在面对静态网页时&#xff1a; 获取页面 HTML&#xff1a;使用 HTTP 客户端下载目标页面的 HTML 内容。解析 HTML&#xff1a;将下载的 HTML 输入解析器&#xff0c;准备提取内容。提取数据&#xff1a;利用解析器功能&#…

D3中颜色的表示方法大全

d3-color 是 D3.js 库中的一个模块&#xff0c;用于处理颜色。它提供了多种方式来表示和操作颜色。下面是一些常见的颜色表示方法及示例代码&#xff1a; 1. CSS颜色关键字 CSS 颜色关键字是一种简单的方式来指定颜色。例如&#xff1a; const color d3.color("steelbl…

IDEA2023 创建SpringBoot项目(一)

一、Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。 二、快速开发 1.打开IDEA选择 File->New->Project 2、…

下一代以区域为导向的电子/电气架构

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所有人的看法和评价都是暂时的&#xff0c;只有自己的经历是伴随一生的&#xff0c;几乎所有的担忧和畏惧…

详细解析STM32 GPIO引脚的8种模式

目录 一、输入浮空&#xff08;Floating Input&#xff09;&#xff1a;GPIO引脚不连接任何上拉或下拉电阻&#xff0c;处于高阻态 1.浮空输入的定义 2.浮空输入的特点 3.浮空输入的应用场景 4.浮空输入的缺点 5.典型配置方式 6.注意事项 二、输入上拉&#xff08;Inpu…

第8章 硬件维护-8.6 产品变更管理(PCN)

8.6 产品变更管理&#xff08;PCN&#xff09; PCN是Product Change Notice&#xff08;产品变更管理&#xff09;的缩写。PCN是厂商为了提高质量、降低成本主动向客户发起的产品变更。一般涉及如下变更的&#xff0c;需要发布PCN公告。 &#xff08;1&#xff09;生产地址变更…

关于安卓模拟器或手机设置了BurpSuite代理和安装证书后仍然抓取不到APP数据包的解决办法

免责申明 本文仅是用于学习研究安卓系统设置代理后抓取不到App数据包实验,请勿用在非法途径上,若将其用于非法目的,所造成的一切后果由您自行承担,产生的一切风险和后果与笔者无关;本文开始前请认真详细学习《‌中华人民共和国网络安全法》【学法时习之丨网络安全在身边一…

【小程序】dialog组件

这个比较简单 我就直接上代码了 只需要传入title即可&#xff0c; 内容部分设置slot 代码 dialog.ttml <view class"dialog-wrapper" hidden"{{!visible}}"><view class"mask" /><view class"dialog"><view …

问:Spring MVC DispatcherServlet流程步骤梳理

DispatcherServlet是Spring MVC框架中的核心组件&#xff0c;负责接收客户端请求并将其分发到相应的控制器进行处理。作为前端控制器&#xff08;Front Controller&#xff09;的实现&#xff0c;DispatcherServlet在整个请求处理流程中扮演着至关重要的角色。本文将探讨Dispat…

uni-app快速入门(十)--常用内置组件(下)

本文介绍uni-app的textarea多行文本框组件、web-view组件、image图片组件、switch开关组件、audio音频组件、video视频组件。 一、textarea多行文本框组件 textarea组件在HTML 中相信大家非常熟悉&#xff0c;组件的官方介绍见&#xff1a; textarea | uni-app官网uni-app,un…

一些任务调度的概念杂谈

任务调度 1.什么是调度任务 依赖&#xff1a;依赖管理是整个DAG调度的核心。调度依赖包括依赖策略和依赖区间。 依赖分为任务依赖和作业依赖&#xff0c;任务依赖是DAG任务本身的依赖关系&#xff0c;作业依赖是根据任务依赖每天的作业产生的。两者在数据存储模型上有所不同…

[已解决]Tomcat 9.0.97控制台乱码

maven3.8.1 JDK11 Tomcat9.0.97 修改apache-tomcat-9.0.97\conf\logging.properties文件&#xff1a; WebServlet("/login") public class LoginServlet extends HttpServlet {Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) th…

语义通信论文略读(十六)多任务+中继通道

Two Birds with One Stone: Multi-Task Semantic Communications Systems over Relay Channel 一石二鸟&#xff1a;中继通道上的多任务语义通信系统 作者: Yujie Cao, Tong Wu, Zhiyong Chen, Yin Xu, Meixia Tao, Wenjun Zhang 所属机构: 上海交通大学 时间&#xff1a;…

【微软:多模态基础模型】(5)多模态大模型:通过LLM训练

欢迎关注[【youcans的AGI学习笔记】](https://blog.csdn.net/youcans/category_12244543.html&#xff09;原创作品 【微软&#xff1a;多模态基础模型】&#xff08;1&#xff09;从专家到通用助手 【微软&#xff1a;多模态基础模型】&#xff08;2&#xff09;视觉理解 【微…

蓝桥杯第22场小白入门赛2~5题

这场比赛开打第二题就理解错意思了&#xff0c;还以为只能用3个消除和5个消除其中一种呢&#xff0c;结果就是死活a不过去&#xff0c;第三题根本读不懂题意&#xff0c;这蓝桥杯的题面我只能说出的是一言难尽啊。。第四题写出来一点但是后来知道是错了&#xff0c;不会正解&am…

【初阶数据结构篇】队列的实现(赋源码)

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…

Java基础夯实——2.4 线程的生命周期

Java线程生命周期 Java线程的生命周期分为&#xff1a;新建&#xff08;New&#xff09;、就绪&#xff08;Runnable&#xff09;、阻塞&#xff08;Blocked&#xff09;、等待 (Waiting) 、计时等待&#xff08;Timed_Waiting&#xff09;、终止&#xff08;Terminated&#…

基于Java Springboot二手书籍交易系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…