编程基础 - 栈(Stack)
本文意指简明扼要的描述栈,并用C++从零到有的实现栈。
需要一定的数据结构与程序语言的基础,尤其是要了解什么是顺序表。
文章目录
1 栈的简介(Introduction of Stack)
栈(Stack)又名堆栈。
-
定义:栈作为一种数据结构,它是一种只能在一端进行插入和删除操作的特殊线性表
- 允许插入和删除的一端称为栈顶(TOP)
- 不允许插入和删除的一端称为栈底(BOTTOM)
- 插入操作称为进栈或入栈(PUSH)
- 删除操作称为退栈或出栈(POP)
-
限制:只能在栈顶插入和删除
-
存储结构:顺序结构或链式结构
-
运算规则(特点):后进先出(Last-In/First-Out,LIFO)或先进后出(First-In/Last-Out,FILO)
-
与一般线性表的区别:仅运算规则不同
2 栈的主要方法(Main Methods of Stack)
栈的主要操作包括:
-
初始化(Initialize)
-
进栈(Push):插入元素
-
退栈(Pop):如果栈中有元素,删除栈顶元素;
-
获取栈顶元素(GetTop):如果栈不为空,获取栈顶元素;
-
清空栈(Clear):如果栈不为空,则删除所有元素;
-
判断栈空(IsEmpty):栈空返回
true
,否则返回false
; -
判断栈满(IsFull):栈满返回
true
,否则返回false
;
3 栈的实现(C++ Code)
虽然在各种高级语言中,栈已经都被实现了:
-
在C++中,使用栈需要加入
#include <stack>
。 -
在C#中,使用栈需要加入
using System.Collection.Generic;
。
但在这里为了更好的理解它,我们将用C++自己实现栈。
提示:以下代码编译器为VC++,属性__declspec(property…)代码在其它编译器可能不通用,如果用其它编译器可删除这一行,直接使用方法代替。
3.1 栈的抽象类(Abstract Class)
首先,我们新建一个头文件起名为Stacks.h
。它将包含如下内容:
-
一些需要的常量(主要是顺序结构需要):
- 栈的默认最大长度
- 栈的默认长度增长率
-
一个栈的模板抽象类:包含了栈的主要方法的虚函数。
-
一些需要的包含库(
#include
)
我们同时为这些内容放入 命名空间Stacks
(之后所有代码都在它之中) 中:
#pragma once
#include <stdexcept> // Build-in exceptions
namespace Stacks
{
constexpr int DEFAULT_MAX_COUNT = 255; // Max Count of Sequential Structure
constexpr int DEFAULT_INCREAMENT = 16; // Increament of Sequential Structure
template<typename T>
class AbstractStack
{
public: // Constructor
virtual ~AbstractStack()
{
};
public: // public Properties
inline virtual int GetCount() = 0;
__declspec(property(get = GetCount)) int count;
public: // public Methods
virtual void Push(T item) = 0;
virtual T Pop() = 0;
virtual T Top() = 0;
virtual T Peek(); // in C#, `Top()` Method is called `Peek()`
virtual void Clear() = 0;
virtual bool Empty() = 0;
};
template<typename T>
T AbstractStack<T>::Peek()
{
return Top();
}
}
-
#include <stdexcept>
:程序异常库,里面有许多常用的异常错误信息 -
DEFAULT_MAX_COUNT
:顺序结构的默认长度; -
DEFAULT_INCREAMENT
:顺序结构的默认增长长度; -
template<typename T> class AbstractStack
:栈的模板抽象类(T
为元素的类型)int GetCount()
与int count
:是一个属性方法,获取栈内元素个数void Push(T item)
:入栈T Pop()
:出栈T Top()
与T Peek()
:获取栈顶元素()void Clear()
:清空栈bool Empty()
:栈是否为空
Tips
constexpr int
可以替换成#define
:
#define DEFAULT_MAX_COUNT 255
#define DEFAULT_INCREAMENT 16
有了基类之后,我们将按照栈的结构来分别写代码。
3.2 顺序结构(Sequential Structure)
在顺序结构中,数组是存储数据的主要类型。而我们在进行栈操作时,需要一个变量指向栈顶元素,从而顺序结构需要的变量:
-
元素数组:存储元素
- 数组初始化的长度
- 当数组满时,需要增长的长度
-
栈顶元素下标:标识当前栈顶元素的位置
而在方法上,除了继承下来的方法,我们需要增加一些顺序结构的必要方法:
-
扩充栈:当栈满时,扩充栈的大小
-
栈是否满
所以,我们建立一个新的头文件SequentialStack.h
来写顺序结构,并将顺序栈命名为SequentialStack
,
即,我们的最终结构为:
#pragma once
#include "Stacks.h"
namespace Stacks
{
template<typename T>
class SequentialStack : virtual public AbstractStack<T>
{
public: // Constructor
SequentialStack();
virtual ~SequentialStack() override;
protected: // protected Fields
T* m_Items; // 元素数组
int m_TopIndex; // 栈顶下标
int m_MaxCount; // 元素数组长度
int m_Increament; // 元素数组增长长度
public: // public Properties
inline virtual int GetCount() override;
inline int GetMaxCount();
inline int GetIncreament();
inline void PutIncreament(int value);
__declspec(property(get = GetCount)) int count;
__declspec(property(get = GetMaxCount)) int maxCount;
__declspec(property(get = GetIncreament, put