栈(stack)是限制插入和删除只能在一个位置上进行的表,该位置是表的末端,叫做栈的顶。对栈的基本操作有Push(进栈)和 Pop(出栈),前者相当于插入,后者则是删除最后插入的元素。所以栈有时叫做LIFO(后进先出)表。
PART 1 栈的基本了解
对栈的第一次接触也是在C语言的学习中。不同的数据存放的方式不同,使用的机制也相应不同。普通函数的调用,递归等都要用到栈。
对栈的实现有两种方法,一种方法使用指针,而另一种方法则是使用数组。
用指针实现,则是使用链表。通过之前的学习知道,链表有头部和尾部,那么如果要用链表,显然应该用头部来作为栈表的顶。因为我们使用的是单向链表,如果要用尾部作为栈的顶,就必须知道倒数第二个结点和尾部结点的指针,操作起来是相对麻烦而且费时的。因为链表的头部将会一直存在,否则整个链表将不复存在,所以用头部来作为顶,更加简单。
代码实现:
1.构建结构体
struct Node
{
ElementType Element; //数据域
struct Node *Next; //建立指针
}
2.创建一个空栈的例程
Stack
CreatStack( void )
{
Stack S;
S = malloc( sizeof( struct Node)); //新建动态结构体
if( S == NULL )
FatalError( "Out of space !!!");
S->Next == NULL;
MakeEmpty(S);
return S;
}
void
MakeEmpty( Stack S )
{
if( S == NULL )
Error( "Must use CreateStack first" );
else
while( !IsEmpty( S )) //如果非空,就将数据Pop出
Pop(S);
}
3.检测栈是否是空栈
int
IsEmpty( Stack S )
{
return S->Next == NULL; //返回 判断S->是否指向NULL的bool值
}
4.Push进栈的例程
void
Push( ElementType X, Stack S)
{
PtrToNode TmpCell;
TmpCell = malloc( sizeof( struct Node) ); //创建动态结构体
if( TmpCell == NULL )
FatalError(" Out of space !!!");
else
{
TmpCell->Element = X; //进行Push操作
TmpCell->Next = S->Next;
S->Next = TmpCell;
}
}
5.从栈弹出元素的例程
void
Pop( Stack S )
{
PtrToNode FirstCell;
if( IsEmpty( S ) ) //判断其是否为空栈
Error( "Empty stack");
else
{
FirstCell = S->Next; //进行Pop操作
S->Next = S->Next->Next;
free( FirstCell);
}
}
第二个方法就是通过数组来实现。
如果要使用数组,我认为有以下几个需要注意的地方。
1.必须声明数组的大小,在一直最大数量的情况下进行操作。
2.只能通过数组创建同类型数据的栈表,最好使用结构体来实现。
3.在数据庞大的情况下可能会造成数值溢出。
通过数组实现的思想大概与链表相同。但是数组的存储方式是连续的,通常情况下我们可以直接通过访问下表的方式来访问数组中的成员。但是此例中我们必须判断此表是否为空表。所以还是必须在结构体中用到指针。
下面列出部分与链表差异较大的代码。
1.结构体的建立
struct StackRecord
{
int Capacity;
int TopOfStack; //栈表的顶
ElementType *Array;
}
2.栈的创建
Stack
CreateStack(int MaxElemnts) //定义一个变量记录最大成员个数
{
stack S;
if(MaxElemnts < MinStackSize) //将最大成员个数和数组大小比较
Error("Stack is too small");
S = malloc( sizeof( struct StackRecord)); //申请动态内存内存
if(s == NULL)
FatalError("Out of space!!!");
S->Array = malloc (sizeof(ElementType) * MaxElements); //将指针指向数组末尾
if(S->Array == NULL)
FatalError("Out of space!!!");
S->Capacity = MaxElements;
MakeEmpty(S);
return S; //返回建立好的数组
}
数组实现,源代码
#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct StackRecord
{
int Capacity;
int TopOfStack;
char *Array;
}Stack;
Stack CreateStack(void);
void DisposeStack(Stack S);
Stack Push(char X, Stack S);
Stack Pop(Stack S);
char TopandPop(Stack S);
//定义全局变量
int MaxElements = 20;
int MinStackSize = 25;
int count = 0;
int IsEmpty(Stack S) //判断栈是否为空
{
return S.TopOfStack == -1;
}
int IsFull(Stack S) //判断栈是否为满
{
return count == MaxElements;
}
int main()
{ Stack S;
S = CreateStack();
int i = 1;
char X;
while(i)
{
cout << "Please enter 1 to push, 2 to pop, 0 to end:" << endl;
cin >> i;
if(i == 1)
{
cout << "Please Input the Element:" << endl;
cin >> X;
S = Push(X, S);
}
if(i == 2)
{
S = Pop(S);
}
}
return 0;
}
Stack CreateStack(void) //创建栈
{
if(MaxElements >= MinStackSize)
{
cout << "This Stack is too small" << endl;
exit(1);
}
Stack S;
S.Array = (char*)malloc(sizeof(char)*MaxElements); //创建动态数组
if(S.Array == NULL)
{
cout << "out of space!!" << endl;
exit(1);
}
S.Capacity = MaxElements;
S.TopOfStack = -1; //MakeEmpty
return S;
}
void DisposeStack(Stack S) //释放动态内存
{
if(S.Array != NULL)
{
free(S.Array); //先释放动态数组
}
}
Stack Push(char X, Stack S)
{
if(!IsFull(S))
{
S.Array[++(S.TopOfStack)] = X; //随着push操作,TopOfStack往后移
count++;
return S;
}
else
{
cout << "out of space !!" << endl;
DisposeStack(S);
exit(1);
}
}
Stack Pop(Stack S)
{
if(!IsEmpty(S))
{
cout << S.Array[S.TopOfStack--] << endl;
return S;
}
else
{
cout << "This Strack is Empty!" <<endl;
DisposeStack(S);
exit(1);
}
}
PART2 栈的应用
1.平衡符合
用栈的方法编代码查找源代码中符号错误匹配
2.后缀表达式
在之前的计算中我们常用形式一般是4.99+5.99+6.99*1.06
但是利用栈可以将其转化成后缀表达式或逆波兰记法。
形如 4.99 1.06 * 5.99+6.99 1.06 * +
3.函数调用
总结
理解…继续理解…