数据结构进阶:使用链表实现栈和队列详解与示例(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、…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
