数据结构进阶:使用链表实现栈和队列详解与示例(C, C#, C++)
文章目录
- 1、 栈与队列简介
- 栈(Stack)
- 队列(Queue)
- 2、使用链表实现栈
- C语言实现
- C#语言实现
- C++语言实现
- 3、使用链表实现队列
- C语言实现
- C#语言实现
- C++语言实现
- 4、链表实现栈和队列的性能分析
- 时间复杂度
- 空间复杂度
- 性能特点
- 与其他实现的比较
- 总结
在软件开发中,数据结构是不可或缺的一部分。本文将详细介绍如何使用链表来实现栈和队列这两种基本的数据结构,并提供C、C#和C++三种语言的示例代码。
1、 栈与队列简介
栈(Stack)
栈是一种后进先出(Last In First Out, LIFO)的数据结构。栈的基本操作包括:
- push:将元素压入栈顶。
- pop:移除栈顶元素。
- peek:查看栈顶元素。
队列(Queue)
队列是一种先进先出(First In First Out, FIFO)的数据结构。队列的基本操作包括:
- enqueue:在队列尾部添加元素。
- dequeue:移除队列头部元素。
- peek:查看队列头部元素。
2、使用链表实现栈
链表是一种灵活的数据结构,非常适合实现栈。
C语言实现
#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node* next;
} Node;typedef struct Stack {Node* top;
} Stack;void initStack(Stack* stack) {stack->top = NULL;
}void push(Stack* stack, int data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = stack->top;stack->top = newNode;
}int pop(Stack* stack) {if (stack->top == NULL) {printf("栈为空\n");return -1;}Node* temp = stack->top;int data = temp->data;stack->top = stack->top->next;free(temp);return data;
}int peek(Stack* stack) {if (stack->top == NULL) {printf("栈为空\n");return -1;}return stack->top->data;
}void destroyStack(Stack* stack) {while (stack->top != NULL) {Node* temp = stack->top;stack->top = stack->top->next;free(temp);}
}int main() {Stack stack;initStack(&stack);push(&stack, 1);push(&stack, 2);push(&stack, 3);printf("栈顶元素:%d\n", peek(&stack));printf("出栈元素:%d\n", pop(&stack));printf("出栈元素:%d\n", pop(&stack));destroyStack(&stack);return 0;
}
C#语言实现
using System;public class Node {public int Data { get; set; }public Node Next { get; set; }
}public class Stack {private Node top;public void Push(int data) {Node newNode = new Node { Data = data, Next = top };top = newNode;}public int Pop() {if (top == null) {throw new InvalidOperationException("栈为空");}int data = top.Data;top = top.Next;return data;}public int Peek() {if (top == null) {throw new InvalidOperationException("栈为空");}return top.Data;}
}class Program {static void Main() {Stack stack = new Stack();stack.Push(1);stack.Push(2);stack.Push(3);Console.WriteLine("栈顶元素:" + stack.Peek());Console.WriteLine("出栈元素:" + stack.Pop());Console.WriteLine("出栈元素:" + stack.Pop());}
}
C++语言实现
#include <iostream>struct Node {int data;Node* next;
};class Stack {
public:Stack() : top(nullptr) {}~Stack() {while (top != nullptr) {Node* temp = top;top = top->next;delete temp;}}void push(int data) {Node* newNode = new Node{data, top};top = newNode;}int pop() {if (top == nullptr) {throw std::runtime_error("栈为空");}Node* temp = top;int data = temp->data;top = top->next;delete temp;return data;}int peek() const {if (top == nullptr) {throw std::runtime_error("栈为空");}return top->data;}private:Node* top;
};int main() {Stack stack;stack.push(1);stack.push(2);stack.push(3);std::cout << "栈顶元素:" << stack.peek() << std::endl;std::cout << "出栈元素:" << stack.pop() << std::endl;std::cout << "出栈元素:" << stack.pop() << std::endl;return 0;
}
3、使用链表实现队列
队列是另一种常见的数据结构,同样可以通过链表来实现。
C语言实现
#include <stdio.h>
#include <stdlib.h>typedef struct Node {int data;struct Node* next;
} Node;typedef struct Queue {Node* front;Node* rear;
} Queue;void initQueue(Queue* queue) {queue->front = queue->rear = NULL;
}void enqueue(Queue* queue, int data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;if (queue->rear == NULL) {queue->front = queue->rear = newNode;} else {queue->rear->next = newNode;queue->rear = newNode;}
}int dequeue(Queue* queue) {if (queue->front == NULL) {printf("队列为空\n");return -1;}Node* temp = queue->front;int data = temp->data;queue->front = queue->front->next;if (queue->front == NULL) {queue->rear = NULL;}free(temp);return data;
}int peekQueue(Queue* queue) {if (queue->front == NULL) {printf("队列为空\n");return -1;}return queue->front->data;
}void destroyQueue(Queue* queue) {while (queue->front != NULL) {Node* temp = queue->front;queue->front = queue->front->next;free(temp);}queue->rear = NULL;
}int main() {Queue queue;initQueue(&queue);enqueue(&queue, 1);enqueue(&queue, 2);enqueue(&queue, 3);printf("队首元素:%d\n", peekQueue(&queue));printf("出队元素:%d\n", dequeue(&queue));printf("出队元素:%d\n", dequeue(&queue));destroyQueue(&queue);return 0;
}
C#语言实现
using System;public class Node {public int Data { get; set; }public Node Next { get; set; }
}public class Queue {private Node front;private Node rear;public void Enqueue(int data) {Node newNode = new Node { Data = data };if (rear == null) {front = rear = newNode;} else {rear.Next = newNode;rear = newNode;}}public int Dequeue() {if (front == null) {throw new InvalidOperationException("队列为空");}int data = front.Data;front = front.Next;if (front == null) {rear = null;}return data;}public int Peek() {if (front == null) {throw new InvalidOperationException("队列为空");}return front.Data;}
}class Program {static void Main() {Queue queue = new Queue();queue.Enqueue(1);queue.Enqueue(2);queue.Enqueue(3);Console.WriteLine("队首元素:" + queue.Peek());Console.WriteLine("出队元素:" + queue.Dequeue());Console.WriteLine("出队元素:" + queue.Dequeue());}
}
C++语言实现
#include <iostream>struct Node {int data;Node* next;
};class Queue {
public:Queue() : front(nullptr), rear(nullptr) {}~Queue() {while (front != nullptr) {Node* temp = front;front = front->next;delete temp;}}void enqueue(int data) {Node* newNode = new Node{data, nullptr};if (rear == nullptr) {front = rear = newNode;} else {rear->next = newNode;rear = newNode;}}int dequeue() {if (front == nullptr) {throw std::runtime_error("队列为空");}Node* temp = front;int data = temp->data;front = front->next;if (front == nullptr) {rear = nullptr;}delete temp;return data;}int peek() const {if (front == nullptr) {throw std::runtime_error("队列为空");}return front->data;}private:Node* front;Node* rear;
};int main() {Queue queue;queue.enqueue(1);queue.enqueue(2);queue.enqueue(3);std::cout << "队首元素:" << queue.peek() << std::endl;std::cout << "出队元素:" << queue.dequeue() << std::endl;std::cout << "出队元素:" << queue.dequeue() << std::endl;return 0;
}
4、链表实现栈和队列的性能分析
时间复杂度
栈(Stack)
- push(入栈)操作:O(1)
在链表实现的栈中,每次入栈操作只需要在链表头部插入一个新节点,这是一个常数时间操作。
- pop(出栈)操作:O(1)
出栈操作涉及移除链表头部的节点,这同样是一个常数时间操作。
- peek(查看栈顶元素)操作:O(1)
查看栈顶元素只需要返回链表头部的节点值,不需要遍历链表。
队列(Queue)
- enqueue(入队)操作:O(1)
在链表实现的队列中,每次入队操作通常在链表尾部插入一个新节点,这也是一个常数时间操作。
- dequeue(出队)操作:O(1)
出队操作涉及移除链表头部的节点,在链表实现的队列中,通常需要保持一个指向链表尾部的指针,以便于在尾部进行插入操作。为了使出队操作达到O(1),我们可以使用双端链表(或两个指针分别指向头部和尾部),这样出队时只需要更新头部指针。
- peek(查看队首元素)操作:O(1)
与栈类似,查看队首元素只需要返回链表头部的节点值。
空间复杂度
- 栈和队列:O(n)
链表实现栈和队列的空间复杂度是线性的,其中n是栈或队列中元素的数量。每个元素都需要一个节点来存储。
性能特点
- 动态大小:链表实现的栈和队列可以根据需要动态地增长和收缩,不需要预先分配固定大小的存储空间。
- 无内存碎片:与数组实现相比,链表实现不会产生内存碎片,因为它们通过指针连接,不需要连续的内存空间。
- 插入和删除效率:链表的插入和删除操作不需要移动其他元素,只需改变指针,因此效率较高。
- 内存开销:链表实现需要额外的内存来存储节点间的指针,这可能比数组实现需要更多的内存。
与其他实现的比较
与数组实现的栈和队列比较:
- 数组实现的栈和队列在内存使用上可能更高效,因为它们不需要额外的指针字段。
- 数组实现的栈和队列可能需要预先分配固定大小的空间,这可能导致空间浪费或需要动态扩容,而链表实现则可以更加灵活地处理大小变化。
与平衡二叉搜索树(如AVL树、红黑树)实现的栈和队列比较:
- 使用平衡二叉搜索树实现的栈和队列在理论上可以达到O(log n)的时间复杂度,但是这在实际中很少见,因为这种实现过于复杂且在实践中不太必要。
总的来说,链表实现的栈和队列在大多数情况下提供了良好的性能,尤其是在元素数量变化较大或者内存使用需要优化时。然而,具体选择哪种实现方式还需要根据实际应用场景和性能需求来决定。
总结
本文通过C、C#和C++三种不同的编程语言,详细介绍了如何使用链表来实现栈和队列这两种基本的数据结构。每种实现都包括了初始化、添加元素、移除元素、查看顶部元素和销毁数据结构的完整操作。
链表由于其灵活性和动态性,是实现栈和队列的理想选择。通过本文的示例,我们可以看到,虽然不同的语言在语法和细节上有所不同,但核心概念和实现逻辑是相似的。
在实际应用中,理解这些数据结构的实现对于编写高效和可靠的应用程序至关重要。无论是进行算法设计、数据处理还是系统开发,掌握栈和队列的实现都是每个程序员的基本技能。
相关文章:
数据结构进阶:使用链表实现栈和队列详解与示例(C, C#, C++)
文章目录 1、 栈与队列简介栈(Stack)队列(Queue) 2、使用链表实现栈C语言实现C#语言实现C语言实现 3、使用链表实现队列C语言实现C#语言实现C语言实现 4、链表实现栈和队列的性能分析时间复杂度空间复杂度性能特点与其他实现的比较…...
【线程系列之五】线程池介绍C语言
一、基本概念 1.1 概念 线程池(Thread Pool)是一种基于池化技术管理线程的机制,旨在减少线程创建和销毁的开销,提高系统资源的利用率,以及更好地控制系统中同时运行的线程数量。线程池通过预先创建一定数量的线程&am…...
【学习css3】使用flex和grid实现等高元素布局
过往的实现方法是使用浮动加计算布局来实现,当flex和grid问世时,这一切将变得简单起来 一、简单的两列实现 1、先看页面效果 2、css代码 .container {padding: 10px;width: 100ch;margin: 0 auto;box-shadow: inset 0 0 0 2px #ccc;}.column {margin: 2…...
如何防止Eclipse格式化程序在行注释开头插入空格
格式化前: //foo bar 格式化后: // foo bar 这种看着不是很舒服。如果不让格式化时自动在注释符后面插入空格呢? 要在Eclipse中进行代码格式化时防止在行注释(//)后面自动增加空格,可以通过调整…...
Nextjs 调用组件内的方法
在 Next.js 中,如果你想从一个组件外部调用组件内部的方法,可以使用 React 的 useRef 钩子来引用组件实例并调用其方法。这种方法主要适用于类组件,但也可以用于函数组件,通过将方法暴露在 ref 对象上。 以下是一个示例ÿ…...
ip地址是电脑还是网线决定的
在数字化时代的浪潮中,网络已经成为了我们日常生活和工作不可或缺的一部分。当我们谈论网络时,IP地址无疑是一个核心的概念。然而,关于IP地址的分配和决定因素,很多人可能存在误解。有些人认为IP地址是由电脑决定的,而…...
Hadoop中HDFS、Hive 和 HBase三者之间的关系
HDFS(Hadoop Distributed File System)、Hive 和 HBase 是 Hadoop 生态系统中三个重要的组件,它们各自解决了大数据存储和处理的不同层面的问题。我们用大白话来解释这三个组件之间的关系: HDFS - 数据的仓库: HDFS 是…...
opencv—常用函数学习_“干货“_10
目录 二七、离散余弦变换 执行离散余弦变换 (dct) 和逆变换 (idct) 解释 实际应用 JPEG压缩示例(简化版) 二八、图像几何变换 仿射变换 (warpAffine 和 getAffineTransform) 透视变换 (warpPerspective 和 getPerspectiveTransform) 旋转变换 (g…...
Jmeter二次开发Demo
Jmeter二次开发Demo 前言 在上一集,我们已经完成了JMX脚本的分析,大致了解了JMX脚本的基本元素。 那么在这一集,我们将会介绍一下Jmeter二次开发的Demo。 Demo代码 那么话不多说,我们就直接上代码。 public class TestStress…...
MongoDB综合实战篇(超容易)
一、题目引入 在MongoDB的gk集合里插入以下数据: 用语句完成如下功能: (1)查询张三同学的成绩信息 (2)查询李四同学的语文成绩 (3)查询没有选化学的同学 (4…...
框架设计MVVM
重点: 1.viewmodel 包含model 2.view包含viewmodel,通过驱动viewmodel去控制model的数据和业务逻辑 // Test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> #include <vector>using namespace std;#p…...
RK3399基础部分
1.RK3399介绍 基础特性: 高达1.8GHz的双核Cortex-A72 四核Cortex-A53高达1.4GHz NPU高达3.0TOPS Mali-T860MP4 GPU 双通道DDR3/DDR3L/LPDDR3/LPDDR4 4K超高清H265/H264/VP9 HDR10/HLG H264编码器 双MIPI CSI和ISP USB Type-CGPU: 图形处理器(英语&…...
linux高级编程(广播与组播)
广播与组播: 广播: 局域网,一个人发所有人都能收(服务器找客户端),(发给路由器的广播地址后后路由器自动给所有人发,可用于服务器找客户端) 只能udp来做 setsocketopt…...
Andriod Stdio新建Kotlin的Jetpack Compose简单项目
1.选择 No Activity 2.选择kotlin 4.右键选择 在目录MyApplication下 New->Compose->Empty Project 出现下面的画面 Finish 完成...
Linux多线程编程-哲学家就餐问题详解与实现(C语言)
在哲学家就餐问题中,假设有五位哲学家围坐在圆桌前,每位哲学家需要进行思考和进餐两种活动。他们的思考不需要任何资源,但进餐需要使用两根筷子(左右两侧各一根)。筷子是共享资源,哲学家们在进行进餐时需要…...
从C向C++18——演讲比赛流程管理系统
一.项目需求 1.比赛规则 学校举行一场演讲比赛,共有12个人参加。比赛共两轮,第一轮为淘汰赛,第二轮为决赛。每名选手都有对应的编号,如 10001~ 10012比赛方式:分组比赛,每组6个人;第一轮分为两…...
QThread和std::thread
在 Qt 中, 我们经常会用到多线程,这时候就需要纠结是使用 Qt 的 QThread 还是使用 C 标准库的 std::thread。 这里记录一下我自己的理解,先介绍一下 QThread 和 std::thread 的使用方法,对比一下他们的不同,最后说一下…...
LeetCode 算法:组合总和 c++
原题链接🔗:组合总和 难度:中等⭐️⭐️ 题目 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 …...
【两大3D转换SDK对比】HOOPS Exchange VS. CAD Exchanger
在现代工业和工程设计领域,CAD数据转换工具是确保不同软件系统间数据互通的关键环节。HOOPS Exchange和CAD Exchanger是两款备受关注的工具,它们在功能、支持格式、性能和应用场景等方面有着显著差异。 本文将从背景、支持格式、功能和性能、应用场景等…...
Openerstry + lua + redis根据请求参数实现动态路由转发
文章目录 一、需求分析二、准备1、软件安装2、redis-lua封装优化 三、实现1、nginx.conf2、dynamic.lua注意 3、准备两个应用4、访问nginx 四、参数直接传要代理的地址端口 一、需求分析 根据用户访问url的参数,将请求转发到对应指定IP的服务器上。 二、准备 1、…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
