栈与队列的实现

简介: 栈与队列的实现

栈与队列的实现

使用数组或链表实现栈和队列,并讨论它们的应用场景和性能特点。

 

 

栈(Stack)

实现

数组实现:

栈顶指针(top):用于指向栈顶元素的位置。

初始化时,栈顶指针通常设置为-1(如果栈为空)或0(如果栈可以包含空元素)。

入栈(push):在栈顶添加元素,栈顶指针加1。

出栈(pop):移除栈顶元素,栈顶指针减1。

访问栈顶元素(peek/top):返回栈顶元素的值,但不移除它。

链表实现:

使用链表的头部作为栈顶。

入栈:在链表头部添加新节点。

出栈:移除链表头部节点。

访问栈顶元素:访问链表头部节点的值。

应用场景

后缀表达式求值

深度优先搜索(DFS)

浏览器的前进后退功能

撤销操作(如文本编辑器的撤销)

性能特点

数组实现:

时间复杂度:入栈、出栈、访问栈顶元素均为O(1)。

空间复杂度:O(n),n为栈中元素数量。

缺点:栈大小受限,可能需要动态扩容。

链表实现:

时间复杂度:入栈、出栈、访问栈顶元素均为O(1)(不考虑链表节点分配的时间)。

空间复杂度:O(n),n为栈中元素数量。

优点:动态大小,不需要预先分配空间。

队列(Queue)

实现

数组实现:

队首指针(front):指向队列第一个元素。

队尾指针(rear):指向队列最后一个元素的下一个位置(或最后一个元素,取决于实现方式)。

入队(enqueue):在队尾添加元素,队尾指针加1。

出队(dequeue):移除队首元素,队首指针加1(可能需要考虑队列头部的元素移动到尾部以维持连续性,即循环队列)。

链表实现:

使用链表的头部作为队首,尾部作为队尾。

入队:在链表尾部添加新节点。

出队:移除链表头部节点。

应用场景

广度优先搜索(BFS)

操作系统中的任务调度

打印机任务队列

消息队列(如RabbitMQ、Kafka等)

性能特点

数组实现:

时间复杂度:入队、出队平均情况下为O(1),但在最坏情况下(如频繁入队出队导致大量元素移动)可能退化到O(n)。

空间复杂度:O(n),n为队列中元素数量。

优点:随机访问队列中元素速度快。

缺点:可能需要动态扩容,且队列大小受限。

链表实现:

时间复杂度:入队、出队均为O(1)(不考虑链表节点分配的时间)。

空间复杂度:O(n),n为队列中元素数量。

优点:动态大小,不需要预先分配空间。

缺点:无法像数组那样快速随机访问队列中的元素。

总结

栈和队列是两种非常基础且重要的数据结构,它们在算法设计和系统设计中有着广泛的应用。选择数组还是链表实现取决于具体的应用场景和对性能的需求。数组实现通常具有较好的缓存局部性,但大小受限;链表实现则更加灵活,但随机访问性能较差。

 

栈与队列的实现扩展

在数据结构的设计与实现中,数组和链表作为基础但极其重要的元素,广泛应用于各种算法与系统设计中。本文将从栈(Stack)与队列(Queue)的实现出发,深入探讨它们在不同场景下的应用及性能特点,并通过具体的代码示例进行说明。

栈(Stack)的实现

数组实现

数组实现的栈通过维护一个栈顶指针(top)来追踪栈顶元素的位置。初始化时,栈顶指针可以设置为-1(表示空栈)或根据具体情况而定。以下是基于数组的栈的基本操作代码示例(C++):

#include <iostream>

#include <vector>

 

template<typename T>

class StackArray {

private:

std::vector<T> data;

int top = -1;

 

public:

void push(const T& value) {

data.push_back(value);

top++;

}

 

T pop() {

if (isEmpty()) throw std::out_of_range("pop from empty stack");

T value = data[top];

data.pop_back();

top--;

return value;

}

 

T peek() const {

if (isEmpty()) throw std::out_of_range("peek from empty stack");

return data[top];

}

 

bool isEmpty() const {

return top == -1;

}

};

 

// 使用示例

StackArray<int> stack;

stack.push(1);

std::cout << stack.pop() << std::endl; // 输出: 1

链表实现

链表实现的栈通常将链表的头部作为栈顶。这允许我们在O(1)时间复杂度内完成入栈(push)和出栈(pop)操作。以下是基于链表的栈的实现代码(C++):

#include <iostream>

 

template<typename T>

class StackNode {

public:

T value;

StackNode* next;

 

StackNode(T val) : value(val), next(nullptr) {}

};

 

template<typename T>

class StackLinkedList {

private:

StackNode<T>* top = nullptr;

 

public:

void push(const T& value) {

StackNode<T>* newNode = new StackNode<T>(value);

newNode->next = top;

top = newNode;

}

 

T pop() {

if (!top) throw std::out_of_range("pop from empty stack");

T value = top->value;

StackNode<T>* temp = top;

top = top->next;

delete temp;

return value;

}

 

T peek() const {

if (!top) throw std::out_of_range("peek from empty stack");

return top->value;

}

 

bool isEmpty() const {

return top == nullptr;

}

};

 

// 使用示例

StackLinkedList<int> stack;

stack.push(1);

std::cout << stack.pop() << std::endl; // 输出: 1

队列(Queue)的实现

数组实现

数组实现的队列需要维护队首指针(front)和队尾指针(rear)。队列的入队(enqueue)操作在队尾添加元素,出队(dequeue)操作移除队首元素。以下是基于数组的队列实现代码(C++):

// 省略部分代码,因篇幅限制,仅展示关键思路

// 注意:数组实现队列时,需处理队列满和队列空的情况,以及可能的动态扩容

链表实现

链表实现的队列将链表的头部作为队首,尾部作为队尾。这种实现方式允许在O(1)时间复杂度内完成入队和出队操作。以下是基于链表的队列实现代码(C++):

#include <iostream>

 

template<typename T>

class QueueNode {

public:

T value;

QueueNode* next;

 

QueueNode(T val) : value(val), next(nullptr) {}

};

 

template<typename T>

class QueueLinkedList {

private:

QueueNode<T>* front = nullptr;

QueueNode<T>* rear = nullptr;

 

public:

void enqueue(const T& value) {

QueueNode<T>* newNode = new QueueNode<T>(value);

if

 

目录
相关文章
|
1月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
137 9
|
25天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
24 1
|
12天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
30 5
|
28天前
|
存储 算法 Java
数据结构的栈
栈作为一种简单而高效的数据结构,在计算机科学和软件开发中有着广泛的应用。通过合理地使用栈,可以有效地解决许多与数据存储和操作相关的问题。
|
1月前
|
存储 JavaScript 前端开发
执行上下文和执行栈
执行上下文是JavaScript运行代码时的环境,每个执行上下文都有自己的变量对象、作用域链和this值。执行栈用于管理函数调用,每当调用一个函数,就会在栈中添加一个新的执行上下文。
|
1月前
|
存储
系统调用处理程序在内核栈中保存了哪些上下文信息?
【10月更文挑战第29天】系统调用处理程序在内核栈中保存的这些上下文信息对于保证系统调用的正确执行和用户程序的正常恢复至关重要。通过准确地保存和恢复这些信息,操作系统能够实现用户模式和内核模式之间的无缝切换,为用户程序提供稳定、可靠的系统服务。
50 4
|
1月前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
2月前
数据结构(栈与列队)
数据结构(栈与列队)
22 1
|
2月前
【数据结构】-- 栈和队列
【数据结构】-- 栈和队列
18 0
|
2月前
|
算法 程序员 索引
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器
栈的基本概念、应用场景以及如何使用数组和单链表模拟栈,并展示了如何利用栈和中缀表达式实现一个综合计算器。
39 1
数据结构与算法学习七:栈、数组模拟栈、单链表模拟栈、栈应用实例 实现 综合计算器