C/C++数据结构之深入了解线性表:顺序表、单链表、循环链表和双向链表

线性表是一种基本的数据结构,它在计算机科学中起着至关重要的作用。线性表用于存储一系列具有相同数据类型的元素,这些元素之间存在顺序关系。在C/C++中,我们可以使用各种方式来实现线性表,其中包括顺序表、单链表、循环链表和双向链表。本篇博客将深入探讨这些数据结构的概念,并通过示例代码进行详细分析。

什么是线性表?

线性表是一种抽象数据类型,它表示具有相同数据类型的元素的有序集合。线性表中的元素之间存在明确的线性顺序,通常由一个首元素和一个尾元素界定。线性表的常见操作包括插入、删除、查找和遍历。在C/C++中,线性表可以通过数组或链表来实现。

顺序表(Array)

顺序表是一种使用数组来实现的线性表,其中元素在内存中是连续存储的。这使得顺序表具有O(1)时间复杂度的随机访问特性,但在插入和删除操作时可能需要移动大量元素。顺序表的大小通常是固定的,除非重新分配内存。

顺序表的定义

在C/C++中,顺序表可以定义如下:

#include <stdio.h>#define MAX_SIZE 100  // 顺序表的最大容量typedef struct {int data[MAX_SIZE];  // 数据存储数组int length;          // 当前长度
} SeqList;

顺序表的示例

以下是一个简单的C程序,用于初始化、插入和遍历顺序表:

#include <stdio.h>#define MAX_SIZE 100typedef struct {int data[MAX_SIZE];int length;
} SeqList;// 初始化顺序表
void init(SeqList *list) {list->length = 0;
}// 在指定位置插入元素
int insert(SeqList *list, int position, int element) {if (position < 0 || position > list->length || list->length >= MAX_SIZE) {return 0;  // 插入失败}for (int i = list->length; i > position; i--) {list->data[i] = list->data[i - 1];}list->data[position] = element;list->length++;return 1;  // 插入成功
}// 遍历顺序表
void traverse(SeqList *list) {for (int i = 0; i < list->length; i++) {printf("%d ", list->data[i]);}printf("\n");
}int main() {SeqList list;init(&list);insert(&list, 0, 1);insert(&list, 1, 2);insert(&list, 2, 3);traverse(&list);return 0;
}

这段代码演示了如何初始化顺序表、在指定位置插入元素以及遍历顺序表。输出将是 1 2 3

单链表(Singly Linked List)

单链表是一种通过节点之间的指针链接来实现的线性表。每个节点包含数据元素和一个指向下一个节点的指针。单链表不要求内存中的节点是连续的,因此插入和删除操作比顺序表更高效。

单链表的定义

在C/C++中,单链表可以定义如下:

#include <stdio.h>typedef struct Node {int data;           // 数据元素struct Node *next;  // 指向下一个节点的指针
} ListNode;

单链表的示例

以下是一个简单的C程序,用于初始化、插入和遍历单链表:

#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node *next;
} ListNode;// 初始化单链表
ListNode *init() {return NULL;
}// 在链表末尾插入元素
ListNode *insert(ListNode *head, int element) {ListNode *newNode = (ListNode *)malloc(sizeof(ListNode));if (newNode == NULL) {perror("Memory allocation failed");exit(1);}newNode->data = element;newNode->next = NULL;if (head == NULL) {return newNode;}ListNode *current = head;while (current->next != NULL) {current = current->next;}current->next = newNode;return head;
}// 遍历单链表
void traverse(ListNode *head) {ListNode *current = head;while (current != NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}// 释放单链表的内存
void destroy(ListNode *head) {while (head != NULL) {ListNode *temp = head;head = head->next;free(temp);}
}int main() {ListNode *head = init();head = insert(head, 1);head = insert(head, 2);head = insert(head, 3);traverse(head);destroy(head);return 0;
}

这段代码演示了如何初始化单链表、在链表末尾插入元素以及遍历单链表。输出将是 1 2 3

循环链表(Circular Linked List)

循环链表是一种单链表的变体,其中最后一个节点的指针指向第一个节点,形成一个循环。循环链表可以用于解决环形问题,如约瑟夫问题(Josephus Problem)。

循环链表的定义

循环链表的定义与单链表类似,唯一不同之处在于最后一个节点的指针指向第一个节点。

#include <stdio.h>typedef struct Node {int data;struct Node *next;
} CircularListNode;

循环链表的示例

以下是一个简单的C程序,用于初始化、插入和遍历循环链表:

#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node *next;
} CircularListNode;// 初始化循环链表
CircularListNode *init() {return NULL;
}// 在链表末尾插入元素
CircularListNode *insert(CircularListNode *head, int element) {CircularListNode *newNode = (CircularListNode *)malloc(sizeof(CircularListNode));if (newNode == NULL) {perror("Memory allocation failed");exit(1);}newNode->data = element;newNode->next = NULL;if (head == NULL) {newNode->next = newNode; // 指向自己形成循环return newNode;}CircularListNode *current = head;while (current->next != head) {current = current->next;}current->next = newNode;newNode->next = head; // 最后一个节点指向头节点形成循环return head;
}// 遍历循环链表
void traverse(CircularListNode *head) {if (head == NULL) {return;}CircularListNode *current = head;do {printf("%d ", current->data);current = current->next;} while (current != head);printf("\n");
}// 释放循环链表的内存
void destroy(CircularListNode *head) {if (head == NULL) {return;}CircularListNode *current = head;CircularListNode *temp;do {temp = current;current = current->next;free(temp);} while (current != head);
}int main() {CircularListNode *head = init();head = insert(head, 1);head = insert(head, 2);head = insert(head, 3);traverse(head);destroy(head);return 0;
}

这段代码演示了如何初始化循环链表、在链表末尾插入元素以及遍历循环链表。输出将是 1 2 3,并形成循环。

双向链表(Doubly Linked List)

双向链表是一种链表,每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。这种结构使得在双向链表中可以轻松地进行双向遍历,但相对于单链表,它需要更多的内存空间来存储额外的指针。

双向链表的定义

在C/C++中,双向链表可以定义如下:

#include <stdio.h>typedef struct Node {int data;struct Node *prev;  // 指向前一个节点的指针struct Node *next;  // 指向后一个节点的指针
} DoublyListNode;

双向链表的示例

以下是一个简单的C程序,用于初始化、插入和遍历双向链表:

#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node *prev;struct Node *next;
} DoublyListNode;// 初始化双向链表
DoublyListNode *init() {return NULL;
}// 在链表末尾插入元素
DoublyListNode *insert(DoublyListNode *head, int element) {DoublyListNode *newNode = (DoublyListNode *)malloc(sizeof(DoublyListNode));if (newNode == NULL) {perror("Memory allocation failed");exit(1);}newNode->data = element;newNode->prev = NULL;newNode->next = NULL;if (head == NULL) {return newNode;}DoublyListNode *current = head;while (current->next != NULL) {current = current->next;}newNode->prev = current;current->next = newNode;return head;
}// 遍历双向链表(正向)
void traverseForward(DoublyListNode *head) {DoublyListNode *current = head;while (current != NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}// 遍历双向链表(反向)
void traverseBackward(DoublyListNode *head) {DoublyListNode *current = head;while (current->next != NULL) {current = current->next;}while (current != NULL) {printf("%d ", current->data);current = current->prev;}printf("\n");
}// 释放双向链表的内存
void destroy(DoublyListNode *head) {DoublyListNode *current = head;DoublyListNode *temp;while (current != NULL) {temp = current;current = current->next;free(temp);}
}int main() {DoublyListNode *head = init();head = insert(head, 1);head = insert(head, 2);head = insert(head, 3);traverseForward(head);traverseBackward(head);destroy(head);return 0;
}

这段代码演示了如何初始化双向链表、在链表末尾插入元素以及正向和反向遍历双向链表。输出将是 1 2 33 2 1


了解更多内容获取更多相关资源前往公众号:每日推荐系列


总结

线性表是计算机科学中常见的数据结构,用于存储一系列具有相同数据类型的元素。在C/C++中,我们可以使用不同的数据结构来实现线性表,包括顺序表、单链表、循环链表和双向链表。每种数据结构都有其独特的特点和适用场景,根据具体需求选择合适的数据结构是非常重要的。

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

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

相关文章

【golang】Windows环境下Gin框架安装和配置

Windows环境下Gin框架安装和配置 我终于搞定了Gin框架的安装&#xff0c;花了两三个小时&#xff0c;只能说道阻且长&#xff0c;所以写下这篇记录文章 先需要修改一些变量&#xff0c;这就需要打开终端&#xff0c;为了一次奏效&#xff0c;我们直接设置全局的&#xff1a; …

大厂面试题-JVM中的三色标记法是什么?

目录 问题分析 问题答案 问题分析 三色标记法是Java虚拟机(JVM)中垃圾回收算法的一种&#xff0c;主要用来标记内存中存活和需要回收的对象。 它的好处是&#xff0c;可以让JVM不发生或仅短时间发生STW(Stop The World)&#xff0c;从而达到清除JVM内存垃圾的目的&#xff…

代码随想录Day31 贪心06 T738 单调递增的数字 T968监控二叉树

LeetCode T738 单调递增的数字 题目链接:738. 单调递增的数字 - 力扣&#xff08;LeetCode&#xff09; 题目思路: 我们以332举例,题目要我们获得的是小于等于332的最大递增数字,我们知道这个数字要递增只能取299了,332 -- 329 --299 我们从后向前遍历,只要前一位大于后一位,我…

系统架构设计师之使用McCabe方法可以计算程序流程图的环形复杂度

系统架构设计师之使用McCabe方法可以计算程序流程图的环形复杂度

conda虚拟环境配置

命令行输入&#xff0c;conda -V 确定conda版本 创建自己的conda虚拟环境 activate 回车 conda create -n 名字 python版本号 执行命令 确认执行命令 输入y 创建完成 激活环境 conda activate 名字 进入python环境 python 退出 exit() conda deactive

Text Classification via Large Language Models

Abstract 表达大模型在文本分类上做的不好。 原因&#xff1a; 1、处理复杂语境时缺少推理能力。(e.g… 类比、讽刺) 2、限制学习的上下文的token数。 提出了自己的策略&#xff1a; ** Clue And Reasoning Prompting (CARP).线索与推理提示** 1、能用prompt找到clue(语境线索…

前端实现打印功能Print.js

前端实现打印的方式有很多种&#xff0c;本人恰好经历了几个项目都涉及到了前端打印&#xff0c;目前较为推荐Print.js来实现前端打印 话不多说&#xff0c;直接上教程 官方链接: Print.js官网 在项目中如何下载Print.js 使用npm下载&#xff1a;npm install print-js --sav…

抓取网页的含义和URL基本构成

抓取网页是指通过爬虫程序从互联网上获取网页的内容和数据。抓取网页是爬虫的核心功能之一&#xff0c;通过抓取网页&#xff0c;可以获取到网页中的文本、图片、链接等信息&#xff0c;用于后续的数据分析、挖掘和应用。 URL&#xff08;Uniform Resource Locator&#xff09…

muduo源码剖析之Buffer缓冲区类

简介 Buffer封装了一个可变长的buffer&#xff0c;支持廉价的前插操作&#xff0c;以及内部挪腾操作避免额外申请空间 使用vector作为缓冲区(可自动调整扩容) 设计图 源码剖析 已经编写好注释 buffer.h // Copyright 2010, Shuo Chen. All rights reserved. // http://c…

城市群(Megalopolis)/城际(inter-city)OD相关研究即Open Access数据集调研

文章目录 1 城市群/城际OD定义2 理论模型与分析方法2.1 重力模型 Gravity Model2.2 干预机会模型 Intervening Opportunities Model2.3 辐射模型 Radiation Model 3 Issues related to OD flows3.1 OD Prediction3.2 OD Forecasting3.3 OD Construction3.4 OD Estimation 4 OD …

PHP简单实现预定义钩子和自定义钩子

在PHP中&#xff0c;钩子&#xff08;Hooks&#xff09;是一种机制&#xff0c;允许开发人员在特定的时机插入自定义代码。通过使用钩子&#xff0c;开发人员可以在应用程序的特定事件发生时执行自定义的功能或逻辑 钩子有两种类型&#xff1a;预定义钩子和自定义钩子。 预定…

Ubuntu安装docker,并换镜像源详细教程,建议收藏

文章目录 添加docker官方的GPG密钥将docker仓库添加到apt源安装docker检查docker换源 添加docker官方的GPG密钥 sudo apt-get updatesudo apt-get install ca-certificates curl gnupgsudo install -m 0755 -d /etc/apt/keyringscurl -fsSL https://download.docker.com/linux…

【axios】axios的基本使用

一、 Axios简介 1、 Axios是什么&#xff1f; Axios是一个基于promise的HTTP库&#xff0c;类似于jQuery的ajax&#xff0c;用于http请求。可以应用于浏览器端和node.js&#xff0c;既可以用于客户端&#xff0c;也可以用于node.js编写的服务端。 2.、Axios特性 支持Promis…

Groovy安装开发环境

准备下载GDK并安装环境变量,跟安装JDK一模一样 https://groovy.apache.org/download.html

安装使用vcpkg的简易教程

目录 1. 首先安装vcpkg2. 在vcpkg目录下运行bootstrap-vcpkg.bat 命令3. 接着vs进行集成4. 使用vcpkg搜索可用的包5.下载安装所需包6.下载安装完成 1. 首先安装vcpkg 使用git命令下载 git clone https://github.com/Microsoft/vcpkg.git如果下载失败可直接下载文件 (vcpkg-ma…

基于Pytest+Requests+Allure实现接口自动化测试!

一、整体结构 框架组成&#xff1a;pytestrequestsallure设计模式&#xff1a; 关键字驱动项目结构&#xff1a; 工具层&#xff1a;api_keyword/参数层&#xff1a;params/用例层&#xff1a;case/数据驱动&#xff1a;data_driver/数据层&#xff1a;data/逻辑层&#xff1a…

C++基础:函数模板

为了代码重用&#xff0c;代码必须是通用的&#xff1b;通用的代码就必须不受数据类型的限制。那么我们可以把数据类型改为一个设计参数&#xff0c;这种类型的程序设计称为参数化程序设计&#xff0c;软件模板有模板构造&#xff0c;包括函数模板和类模板。 函数模板可以用来…

设计模式(19)命令模式

一、介绍&#xff1a; 1、定义&#xff1a;命令模式&#xff08;Command Pattern&#xff09;是一种行为设计模式&#xff0c;它将请求封装为一个对象&#xff0c;从而使你可以使用不同的请求对客户端进行参数化。命令模式还支持请求的排队、记录日志、撤销操作等功能。 2、组…

在spring boot+vue项目中@CrossOrigin 配置了允许跨域但是依然报错跨域,解决跨域请求的一次残酷经历

首先&#xff0c;说一下我们的项目情况&#xff0c;我们项目中后端有一个过滤器&#xff0c;如果必须要登录的接口路径会被拦下来检查&#xff0c;前端要传一个token&#xff0c;然后后端根据这个token来判断redis中这个用户是否已经登录。 if (request.getMethod().equals(&qu…

Azure云工作站上做Machine Learning模型开发 - 全流程演示

目录 本文内容先决条件从“笔记本”开始设置用于原型制作的新环境&#xff08;可选&#xff09;创建笔记本开发训练脚本迭代检查结果 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0…