C++栈(stack)详解
一、引言
在编程和算法设计中,栈(Stack)是一种非常常见且重要的数据结构。栈遵循后进先出(LIFO, Last In First Out)的原则,即最后一个被添加到栈中的元素总是第一个被移除。本文将详细介绍栈的基本概念、操作以及在实际编程中的应用。
二、栈的基本概念
栈是一种线性数据结构。栈只允许在一端(称为栈顶)进行插入和删除操作。栈中没有元素时,称为空栈。栈的插入操作通常被称为“压栈”(push),而删除操作则被称为“弹栈”(pop)。
三、栈的基本操作
压栈(push):在栈顶添加一个新元素。如果栈已满,则无法进行压栈操作。
弹栈(pop):移除栈顶的元素,并返回该元素的值。如果栈为空,则无法进行弹栈操作。
查看栈顶(peek):返回栈顶元素的值,但不移除该元素。如果栈为空,则无法进行查看栈顶操作。
判断栈是否为空(isEmpty):检查栈中是否包含任何元素。
获取栈的大小(size):返回栈中元素的数量。
图片解释:
- 图1是一个初始的栈,含有元素 1 7 2 1\space7\space2 1 7 2,
- 图2在栈顶插入了元素 8 8 8,(注意是在栈顶插入,不能在栈尾插入)
- 图3在栈顶插入了元素 2 2 2,
- 图4(第二行最右边)在栈顶删除了元素 2 2 2,这时栈顶为 8 8 8,
- 图5在栈顶删除了元素 8 8 8,这时栈顶为 1 1 1,
- 图6在栈顶删除了元素 1 1 1,这时栈顶为 7 7 7
仔细观察,可以发现栈的结构类似于将要洗的衣服叠在一起,后放上衣服堆的衣服(相当于入栈)会被先洗(后进先出),洗完以后就拿走晾干(相当于出栈)。
四、栈的实现方式
栈可以用数组或链表来实现。使用数组实现的栈在性能上通常优于链表,因为数组在内存中是连续的,访问速度快。然而,数组实现的栈在大小上通常是固定的,如果栈的大小超过数组的容量,就需要进行扩容操作,这可能会带来一定的性能开销。
链表实现的栈则更加灵活,可以根据需要动态地分配和释放内存。但是,链表中的元素在内存中并不是连续的,因此访问速度可能会慢一些。
(1) 数组实现:
#include <iostream>
#include <stdexcept>
class Stack {
private:
int top; // 栈顶指针
unsigned capacity; // 栈的最大容量
int* array; // 指向数组的指针
// 辅助函数,用于检查栈是否已满
bool isFull() const {
return top == capacity - 1;
}
// 辅助函数,用于检查栈是否为空
bool isEmpty() const {
return top == -1;
}
public:
// 构造函数
Stack(unsigned capacity) {
this->capacity = capacity;
top = -1;
array = new int[capacity];
}
// 析构函数
~Stack() {
delete[] array;
}
// 入栈操作
void push(int value) {
if (isFull()) {
throw std::out_of_range("Stack is full")