栈
栈是一种特殊的线性表,其插入(又称入栈或压栈)和删除(又称出栈或弹栈)操作都在表的一端进行。表的两头称为栈顶和栈底
例如:栈的删除操作中,删除D元素
递归工作栈
我们常常会用到递归函数,而计算机执行递归就是使用递归工作栈。
当一个函数被调用时,一个返回地址和被调函数的局部变量和形参的值都要存储在递归工作栈中。因此随着递归的不断调用,最先被执行的操作存储在栈的最底部,最后的操作存储在栈的顶部。当执行到递归结束点(递归出口)的时候,开始从顶部自上往下返回存储的数据。
注:递归次数过多容易造成栈溢出,所以一般不提倡用递归算法设计程序
栈的简单操作
因为栈是一种特殊的线性表,所以它同线性表一样具有数组描述形式和链表描述形式
数组描述
创建arrayStack类
#ifndef ARRAYSTACK_H
#define ARRAYSTACK_H
template <typename T>
class stack
{
public:
virtual ~stack() {};
virtual bool empty() const = 0;
// 返回true, 当且仅当栈为空
virtual int size() const = 0;
// 返回栈中的元素
virtual T& top() = 0;
// 返回栈顶元素的索引
virtual void pop() = 0;
// 删除栈顶元素
virtual void push(const T& theElement) = 0;
// 将元素theElement压入栈
};
template <typename T>
class arrayStack : public stack<T>
{
public:
arrayStack(int InitialCapacity = 10);
~arrayStack() { delete [] stack; }
// 实现stack
bool empty() const
{
return stackTop == -1;
}
int size() const
{
return stackTop + 1;
}
T& top()
{
if(stackTop == -1)
throw "The stack is empty";
return stack[stackTop];
}
void pop()
{
if(stackTop == -1)
throw "The stack is emtpy";
stack[stackTop--].~T(); // T的析构函数
}
void push(const T& theElement);
// 改变容器大小(翻倍)
void changeLengthlD(T* &a, int oldLength, int newLength);
// 输出全部元素
void output();
private:
int stackTop; // 当前栈顶
int arrayLength; // 数组长度(栈容量)
T* stack; // 元素数组
};
template <typename T>
arrayStack<T>::arrayStack(int InitialCapacity)
{
if(InitialCapacity < 1)
InitialCapacity = 10;
arrayLength = InitialCapacity;
stack = new T[InitialCapacity];
stackTop = -1;
}
template <typename T>
void arrayStack<T>::push(const T& theElement)
{
if(stackTop == arrayLength -1)
{
changeLengthlD(stack, arrayLength, 2 * arrayLength);
arrayLength *= 2;
}
stack[++stackTop] = theElement;
}
template <typename T>
void arrayStack<T>::changeLengthlD(T* &a, int oldLength, int newLength)
{
T* temp = new T[oldLength];
for(int i = 0; i < oldLength; i++)
temp[i] = a[i];
delete[] a;
a = new T[newLength];
for(int i = 0; i < oldLength; i++)
a[i] = temp[i];
delete[] temp;
}
template <typename T>
void arrayStack<T>::output()
{
if(stackTop == -1)
throw "The array is emtpy";
int a = stackTop;
for(;a >= 0; a--)
std::cout << stack[a] << " ";
std::cout << std::endl;
}
#endif // !ARRAYSTACK_H
链表描述
用节点存储元素可能会有点麻烦,如果你直接存储的是一个链表的头结点(栈底),那么你要得到链表的尾节点(栈顶),都要循环遍历一次。如果你存储的是一个链表的尾节点,那么会方便许多。当然也有人会问当删除操作的时候,怎么将指针指向前一个呢?
#ifndef LINKEDSTACK_H
#define LINKEDSTACK_H
#include <iostream>
// 节点结构
template <typename T>
struct chainNode
{
T element;
chainNode<T> *next;
chainNode() {}
chainNode(const T& element)
{
this->element = element;
}
chainNode(const T& element, chainNode<T>* next)
{
this->element = element;
this->next = next;
}
};
template <typename T>
class stack
{
public:
virtual ~stack() {};
virtual bool empty() const = 0;
// 返回true, 当且仅当栈为空
virtual int size() const = 0;
// 返回栈中的元素
virtual T& top() = 0;
// 返回栈顶元素的索引
virtual void pop() = 0;
// 删除栈顶元素
virtual void push(const T& theElement) = 0;
// 将元素theElement压入栈
};
template <typename T>
class linkedStack : public stack<T>
{
public:
linkedStack(int InitialCapacity = 10)
{
stackSize = 0;
stackTop = NULL;
}
~linkedStack();
// 实现操作
bool empty() const
{
return stackSize == 0;
}
int size() const
{
return stackSize;
}
T& top()
{
if(stackSize == 0)
throw "The stack is empty";
return stackTop->element;
}
void pop();
void push(const T& theElement)
{
stackTop = new chainNode<T>(theElement, stackTop);
stackSize++;
}
private:
chainNode<T>* stackTop;
int stackSize; // 栈中的元素
};
template <typename T>
linkedStack<T>::~linkedStack()
{
while(stackTop != NULL)
{
chainNode<T>* nextNode = stackTop->next;
delete stackTop;
stackTop = nextNode;
}
}
template <typename T>
void linkedStack<T>::pop()
{
if(stackSize == 0)
throw "the stack is empty";
chainNode<T>* nextNode = stackTop->next;
delete stackTop;
stackTop = nextNode;
stackSize--;
}
#endif // !LINKEDSTACK_H