当前位置: 首页 > news >正文

【数据结构】链表补充——静态链表、循环链表、双向链表与双向循环链表

链表是数据结构中非常重要的一种线性结构,相比顺序表(数组),链表具有灵活的内存分配动态大小的优点。链表的常见变种包括:静态链表、循环链表、双向链表,以及它们的组合——双向循环链表。在本篇博客中,我们将一步步深入探索这些链表结构的实现原理、优缺点与应用场景。


一、什么是链表?

链表(Linked List)是一种线性存储结构,它由若干个节点组成。
每个节点包含两个部分:

  • 数据域(存储数据元素);
  • 指针域(存储下一个节点的地址)。

相比顺序表,链表的元素不需要在内存中连续存储,这使得链表在插入和删除元素时表现得更加高效。链表的节点通过指针连接,形成一个“链条”。


二、静态链表

📦 静态链表的定义

静态链表是一种使用数组模拟链表结构的方式。
它不同于传统的链表(使用指针),静态链表采用了数组的方式来存储节点,并通过数组中的索引来模拟指针的作用。每个元素不仅存储数据,还存储指向下一个元素的数组下标。

🌿 静态链表的结构

#include <iostream>
using namespace std;#define MAX_SIZE 100  // 假设链表最多有100个元素typedef int ElemType;struct StaticList {ElemType data;        // 存储数据元素int next;             // 存储下一个元素在数组中的下标
};class StaticLinkedList {
private:StaticList arr[MAX_SIZE]; // 数组模拟链表int head;  // 头指针,指向链表的第一个元素int size;   // 当前链表的长度public:StaticLinkedList() {head = -1;  // 初始为空链表size = 0;}// 插入元素void insert(int pos, ElemType value) {if (size == MAX_SIZE) {cout << "链表已满!" << endl;return;}int newNode = size++;  // 使用size作为新的节点下标arr[newNode].data = value;  // 存储数据// 找到插入位置if (pos == 0) {arr[newNode].next = head;head = newNode;} else {int prev = head;for (int i = 0; i < pos - 1; i++) {prev = arr[prev].next;}arr[newNode].next = arr[prev].next;arr[prev].next = newNode;}}// 打印链表void print() {int curr = head;while (curr != -1) {cout << arr[curr].data << " ";curr = arr[curr].next;}cout << endl;}
};

🔍 静态链表分析

  • 优点:使用数组模拟链表,可以避免动态内存分配带来的开销。每个节点之间通过数组下标来连接,比较节省内存。
  • 缺点:一旦数组满了,无法动态扩展,且对内存的利用不如动态链表灵活。

三、循环链表

📦 循环链表的定义

循环链表是一种特殊的链表,它的最后一个节点的next指针指向头节点,形成一个环形结构。循环链表可以是单向循环链表(只包含一个方向的指针)或者双向循环链表(包含两个方向的指针)。

🌿 单向循环链表的实现

#include <iostream>
using namespace std;struct Node {int data;Node* next;
};class CircularLinkedList {
private:Node* head;  // 头节点指针public:CircularLinkedList() {head = nullptr;}// 插入元素void insert(int value) {Node* newNode = new Node();newNode->data = value;if (!head) {head = newNode;newNode->next = head;  // 自己指向自己} else {Node* temp = head;while (temp->next != head) {temp = temp->next;  // 遍历到链表的最后一个节点}temp->next = newNode;  // 将新节点接到链表末尾newNode->next = head;  // 新节点指向头节点,形成环}}// 打印链表void print() {if (!head) return;Node* temp = head;do {cout << temp->data << " ";temp = temp->next;} while (temp != head);  // 循环直到回到头节点cout << endl;}
};

🔍 循环链表分析

  • 优点:通过将尾节点指向头节点,实现了循环结构,能够更加方便地从尾部回到头部,适用于循环调度等应用场景。
  • 缺点:结构上比普通链表复杂,且循环链表无法轻易地插入或删除某个元素的前一个节点。

四、双向链表

📦 双向链表的定义

双向链表是指每个节点除了有指向下一个节点的指针外,还有一个指向前一个节点的指针。这样可以使得链表的操作更加灵活,支持双向遍历。

🌿 双向链表的实现

#include <iostream>
using namespace std;struct Node {int data;Node* next;Node* prev;
};class DoublyLinkedList {
private:Node* head;  // 头节点Node* tail;  // 尾节点public:DoublyLinkedList() {head = nullptr;tail = nullptr;}// 插入元素void insert(int value) {Node* newNode = new Node();newNode->data = value;newNode->next = nullptr;newNode->prev = tail;if (tail) {tail->next = newNode;} else {head = newNode;  // 第一个节点}tail = newNode;}// 打印链表(从头到尾)void print() {Node* temp = head;while (temp) {cout << temp->data << " ";temp = temp->next;}cout << endl;}// 打印链表(从尾到头)void printReverse() {Node* temp = tail;while (temp) {cout << temp->data << " ";temp = temp->prev;}cout << endl;}
};

🔍 双向链表分析

  • 优点:支持双向遍历,删除、插入操作非常方便,尤其是在已知某个节点的情况下,可以快速地进行前向或后向操作。
  • 缺点:比单向链表占用更多的内存空间,因为每个节点需要额外存储一个指向前节点的指针。

五、双向循环链表

📦 双向循环链表的定义

双向循环链表结合了双向链表和循环链表的特点:既有指向前后节点的指针,又形成了一个循环结构。这样,既可以双向遍历链表,又可以在尾部和头部之间无缝切换。

🌿 双向循环链表的实现

#include <iostream>
using namespace std;struct Node {int data;Node* next;Node* prev;
};class DoublyCircularLinkedList {
private:Node* head;  // 头节点public:DoublyCircularLinkedList() {head = nullptr;}// 插入元素void insert(int value) {Node* newNode = new Node();newNode->data = value;if (!head) {head = newNode;newNode->next = head;newNode->prev = head;} else {Node* tail = head->prev;tail->next = newNode;newNode->prev = tail;newNode->next = head;head->prev = newNode;}
}// 打印链表(从头到尾)void print() {if (!head) return;Node* temp = head;do {cout << temp->data << " ";temp = temp->next;} while (temp != head);  // 循环直到回到头节点cout << endl;}
};

🔍 双向循环链表分析

  • 优点:支持双向遍历,且头尾连接成循环结构,适用于需要从任意位置循环访问的场景。
  • 缺点:需要存储两个指针(前后节点指针),因此内存开销较大,且比普通循环链表或双向链表更复杂。

六、小结

链表类型特点优点缺点
静态链表使用数组模拟链表结构内存利用相对较高,操作简单不能动态扩展,灵活性差
单向循环链表最后一个节点指向头节点,形成循环结构支持循环遍历,适合循环调度等应用插入删除操作较麻烦
双向链表每个节点有两个指针,分别指向前后节点支持双向遍历,插入删除操作方便每个节点需要额外的空间来存储前指针
双向循环链表双向链表和循环链表结合,头尾连接支持双向遍历,适用于循环访问的场景存储空间开销较大,操作复杂
http://www.dtcms.com/a/536590.html

相关文章:

  • Python测试题1
  • 解锁仓颉语言:探索全场景智能编程新范式
  • 大模型-模型压缩:量化、剪枝、蒸馏、二值化 (3)
  • C++进阶:(二)多态的深度解析
  • 天汇大厦网站建设公司佳木斯做网站公司
  • Java 大视界 -- 基于 Java 的大数据可视化在城市交通拥堵溯源与治理策略展示中的应用
  • 从零实现一个完整的vector类:深入理解C++动态数组
  • JVM从操作系统层面的总体启动流程
  • C++list类的模拟实现
  • 深圳三站合一网站建设网站建设推广怎样找客户
  • 【多所高校主办】第七届机器人、智能控制与人工智能国际学术会议(RICAI 2025)
  • 做网站有虚拟服务器什么是网络营销产生的基础
  • 高配款浮标五参数—可以及时掌握水体的生态状况
  • 《Java 实用技巧:均匀取元素算法(支持不足补齐)》
  • 【Linux】nohup命令
  • 泰州网站建设案例昆明网站seo外包
  • 【成长纪实】星光不负 码向未来|我的 HarmonyOS 学习之路与社区成长故事
  • 网站服务器租用4t多少钱一年啊提供网站建设公司有哪些
  • 如何处理系统环境变量的字符长度超过了 Windows 对话框的限制(2047 个字符)
  • 快速上手大模型:深度学习1(初识、神经网络基础)
  • Java---StringBuffer类
  • 【从零开始构建性能测试体系-10】人工智能与性能测试:如何借助AI提升测试效率
  • 网站建设人员要与客户谈什么一篇关于大学网站建设与管理的论文
  • 子洲网站建设制作网站上做网页怎么改图片
  • kafka使用-Producer
  • CUDA实现的点云MLS滤波
  • Spring Framework源码解析——TaskScheduler
  • 【从零开始开发远程桌面连接控制工具】02-服务端实现详解
  • 湖州网站设计公司WordPress博客Vieu主题
  • 国外好看的网站设计国外网站需要备案