数据结构进阶:使用链表实现栈和队列详解与示例(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、…...
如何分析和改善网站的SEO效果
如何分析和改善网站的SEO效果 在当今互联网时代,一个优秀的网站不仅需要内容丰富,还需要有良好的搜索引擎优化(SEO)效果。SEO是提升网站在搜索引擎中排名的关键手段,本文将详细探讨如何分析和改善网站的SEO效果&#…...
保姆级教学:FLUX.1文生图+SDXL Prompt风格,从环境准备到图片生成的完整流程
保姆级教学:FLUX.1文生图SDXL Prompt风格,从环境准备到图片生成的完整流程 你是否曾经遇到过这样的困扰:明明输入了详细的描述词,但生成的图片却与预期相差甚远?或者尝试混合多种风格时,结果变得不伦不类&…...
第198章 万物编译(秀秀)
弦光研究院物质科学中心的环形实验室内,空气仿佛凝固成了某种可见的期待,每一立方厘米都承载着对技术突破的深切盼望。秀秀独自站立在主控制台前,目光穿透层层防护屏障,聚焦在那个被超导磁体环绕的圆柱形真空腔内。腔内࿰…...
TRAE SOLO模式实战:如何用AI上下文工程师5分钟搞定JWT登录接口开发
TRAE SOLO模式实战:5分钟构建JWT登录接口的AI开发革命 清晨的阳光透过百叶窗洒在键盘上,咖啡杯里升起最后一缕热气。作为一名全栈开发者,你刚收到产品经理的紧急需求:"今天下班前上线用户登录功能,支持邮箱密码验…...
Qwen3.5-2B轻量化部署案例:中小企业私有化AI助手落地全流程
Qwen3.5-2B轻量化部署案例:中小企业私有化AI助手落地全流程 1. 为什么选择Qwen3.5-2B 对于中小企业而言,部署AI助手常常面临两大难题:一是硬件成本高,二是技术门槛高。Qwen3.5-2B作为一款轻量化多模态基础模型,完美解…...
从安装到实战:在快马平台部署一个基于openclaw的新闻采集demo
今天想和大家分享一个完整的实战项目:在InsCode(快马)平台上从零开始部署一个基于openclaw的新闻采集demo。这个项目特别适合想快速验证爬虫框架能力的朋友,因为平台的一键部署功能让我们能跳过繁琐的环境配置,直接进入实战环节。 为什么选择…...
面向对象分析模型深入分析
面向对象分析模型深入分析 面向对象分析(Object-Oriented Analysis, OOA)是系统分析师在需求阶段的核心工作方法。它强调从问题域中的客观实体出发,以“对象”为基本单元建立业务模型,而不是从功能或数据流出发。下面从核心概念、三大模型、建模流程到实战案例进行全面解析…...
探索PLECS仿真下DAB变换器峰值电流前馈控制策略——IEEE顶刊复现之旅
PLECS仿真,IEEE顶刊复现,DAB变换器峰值电流前馈控制策略。最近在电力电子领域的研究中,我深入钻研了DAB(Dual - Active - Bridge)变换器的相关控制策略,并通过PLECS仿真实现了IEEE顶刊论文里一种峰值电流前…...
优化粒子群算法实现VMD分解参数优化
56_基于改进的粒子群算法实现vmd分解参数优化。 matlab环境,2018a及以上版本。 可用于学习粒子群算法的改进,以及粒子群算法的使用。 1.考虑到传统粒子群算法中固定的权值容易使算法陷入局部最优解,针对这一缺点,从惯性权重和学习…...
Open UI5 源代码解析之780:Label.js
源代码仓库: https://github.com/SAP/openui5 源代码位置:src\sap.m\src\sap\m\Label.js sap.m.Label 文件深度解析与项目作用说明 一、文件定位与整体职责 Label.js 位于 sap.m 组件库中,是一个非常基础却影响面极广的控件实现文件。它定义了 sap.m.Label 的完整行为,…...
