基本操作:
入栈、出栈相当于插入、删除
实现方式:
链表、数组。
链表:可以通过继承链表来实现。本文略
数组实现:避免了指针,更流行,唯一的潜在危害是需要提前声明一个数组的大小,但是在典型的应用中,任一时刻栈元素的个数不会太大,所以此危害可忽略。
#include <iostream>
using namespace std;
/**********************************************************************
栈基本操作
用链表实现的栈结构的缺点是总是需要动态的分配资源,如果想解决这个问题可以
用另一个栈结构存储被删除的数据,而使用数组实现则效率更高一些,唯一的不足
就是就是需要提前的申请空间大小,这里只是实现了一些栈简答操作。
增加了find_min操作。
**********************************************************************/
typedef struct StackRecord
{
int m_capcity;//栈容量
int m_topIndex;//栈顶索引,空栈为-1
int* m_pArray;//存放栈元素的数组
} *Stack;
Stack CreatStack(int capacity);//创建空栈
void push(Stack s, int x);
void pop(Stack s);
int top(Stack s);
void MakeEmpty(Stack s);
bool IsDisposeStack(Stack s);//释放栈
bool IsFull(Stack s);
bool IsEmpty(Stack s);
void Traverse(Stack s);//从栈顶到栈低遍历
int main()
{
Stack s = CreatStack(5);
push(s, 5);
push(s, 19);
push(s, 10);
Traverse(s);
cout << "一次出栈" << endl;
pop(s);
Traverse(s);
int sTop = top(s);
cout << "栈顶元素:" << top << endl;
cout << "置空栈:";
MakeEmpty(s);
Traverse(s);
if (IsDisposeStack(s))
cout << "释放成功" << endl;
else
cout << "释放不成功" << endl;
system("pause");
return 0;
}
Stack CreatStack(int capacity)
{
if (capacity < 0)
cout << "栈太小" << endl;
Stack stack = new StackRecord;
stack->m_capcity = capacity;
stack->m_pArray = new int[capacity];
MakeEmpty(stack);
return stack;
}
void push(Stack s, int x)
{
if (!IsFull(s))
{
s->m_topIndex += 1;
s->m_pArray[s->m_topIndex] = x;
}
else
cout << "栈已满,入栈失败" << endl;
}
void pop(Stack s)
{
if (!IsEmpty(s))
{
s->m_topIndex -= 1;
}
else
cout << "空栈,弹出失败" << endl;
}
int top(Stack s)
{
if (!IsEmpty(s))
return s->m_pArray[s->m_topIndex];
else
cout << "空栈,栈顶元素不存在" << endl;
}
void MakeEmpty(Stack s)
{
s->m_topIndex = -1;
}
bool IsDisposeStack(Stack s)
{
if (s->m_pArray != nullptr)
{
delete[] s->m_pArray;
s->m_pArray = nullptr;
}
delete s;
s = nullptr;
if (s == nullptr)
return true;
}
bool IsFull(Stack s)
{
if (s->m_topIndex == s->m_capcity - 1)
return true;
return false;
}
bool IsEmpty(Stack s)
{
if (s->m_topIndex == -1)
return true;
return false;
}
void Traverse(Stack s)
{
cout << "从栈顶到栈低遍历:";
if (!IsEmpty(s))
{
int tmp = s->m_topIndex;
while (tmp != -1)
{
cout << s->m_pArray[tmp] << " ";
tmp--;
}
cout << endl;
}
else
cout << "栈为空" << endl;
}
应用:
1.平衡符号:例如检验符号是否成对出现
读入字符直到文件尾,遇到左半边字符入栈,右半边字符出栈。如果到最后栈为空,则封闭,否则报错。复杂度为线性。
2.后缀表达式(逆波兰表达式):优点,当一个表达式以后缀形式给出时,无需知道任何优先规则。
3.将中缀表达式(标准)转化为后缀表达式:利用一个放操作符的栈,一个放输出的栈。
4.函数调用:
注意:
栈为了速度,一般不检查栈溢出,所以使用栈,当栈过大时(失控递归),会发生一些奇怪的事。
尾递归:
尾递归完全合法且看起来无害,但也会使你越出栈空间,eg:
//利用尾递归遍历(使用极端不当):尾递归设计在最后一行进行递归调用
//如果链表含有20000个元素,嵌套调用20000个活动记录的一个栈
//活动记录由于包含的全部信息特别庞大,可能会越过栈空间
void PrintList(List L)
{
L = L->m_pNextNode;
if (L != nullptr)
{
cout << L->m_element << "";
PrintList(L->m_pNextNode);
}
}
//使用goto语句消除尾递归
void PrintListGoto(List L)
{
top:
if (L != nullptr)
{
cout << L->m_element << "";
L = L->m_pNextNode;
goto top;
}
}