数据结构基础内容(第三篇:堆栈)
# 堆栈 Stack
具有一定操作约束的线性表,只在一端(栈顶,Top)做 插入、删除
操作集:长度为MaxSize的堆栈S 属于 Stack,堆栈元素item 属于 ElementType
1. Stack CreateStack( int MaxSize ): 生成空堆栈,其最大长度为MaxSize;
2. int IsFull( Stack S, int MaxSize ):判断堆栈S是否已满;
3. void Push( Stack S, ElementType item ):将元素item压入堆栈;
4. int IsEmpty ( Stack S ):判断堆栈S是否为空;
5. ElementType Pop( Stack S ):删除并返回栈顶元素;
## 栈的顺序存储实现
栈的顺序存储结构通常由一个一维数组和一个记录.栈顶元素位置的变量组成。
```c
#define MaxSize <储存数据元素的最大个数>
typedef struct SNode *Stack; //结构指针
struct SNode{
ElementType Data[MaxSize]; //数组
int Top; // 栈顶位置的数组下标
};
```
* 入栈 Push
```c
void Push( Stack PtrS, ElementType item ) // stack这个类型的指针
{
if ( PtrS->Top == MaxSize-1 ) // 判断满不满。从 0 到 MaxSize-1
{
printf(“堆栈满”);
return;
}else
{
PtrS->Data[++(PtrS->Top)] = item;
/* 相当于:
(PtrS->Top)++;
PtrS->Data[PtrS->Top] = item;
*/
return;
}
}
```
* 出栈 Top
```c
ElementType Pop( Stack PtrS )
{
if ( PtrS->Top == -1 )
{
printf(“堆栈空”);
return ERROR; //ERROR是ElementType的特殊值,标志错误
} else
{
return ( PtrS->Data[(PtrS->Top)--] ); // return 出下标为top的这个值,同时Top-1
}
}
```
[例] 请用一个数组实现两个堆栈,要求最大地利用数组空间,使 数组只要有空间入栈操作就可以成功。
【分析】 一种比较聪明的方法是使这两个栈分别从数组的两头开始 向中间生长;当两个栈的栈顶指针相遇时,表示两个栈都满了。
```c
#define MaxSize <存储数据元素的最大个数>
struct DStack {
ElementType Data[MaxSize];
int Top1; /* 堆栈1的栈顶指针 */
int Top2; /* 堆栈2的栈顶指针 */
} S;
S.Top1 = -1; // 左边这个设为空
S.Top2 = MaxSize; // 右边设为空(已经超出了MaxSize -1)
```
入栈
```c
void Push( struct DStack *PtrS, ElementType item, int Tag )
{ /* Tag作为区分两个堆栈的标志,取值为1和2 */
if ( PtrS->Top2 – PtrS->Top1 == 1) /* 堆栈满, 两个指针相邻啦 */
{
printf(“堆栈满”);
return ;
}
if ( Tag == 1 ) /* 对第一个堆栈操作 */
PtrS->Data[++(PtrS->Top1)] = item; // 放在第一个元素后面一位
else /* 对第二个堆栈操作 */
PtrS->Data[--(PtrS->Top2)] = item; // 放在最后一个元素的前面一位
}
```
出栈
```c
ElementType Pop( struct DStack *PtrS, int Tag )
{ /* Tag区分两个堆栈*/
if(Tag==1) /*对第一个堆栈操作 */
{
if ( PtrS->Top1 == -1 ) /*堆栈1空 */
{
printf(“堆栈1空”);
return NULL;
} else
return PtrS->Data[(PtrS->Top1)--]; // 先抛出再对top-1
} else /* 对第二个堆栈操作 */
{
if ( PtrS->Top2 == MaxSize ) /*堆栈2空 */
{
printf(“堆栈2空”);
return NULL;
}
else
return PtrS->Data[(PtrS->Top2)++]; // 先抛出再对top+1
}
}
```
## 堆栈的链式存储实
栈的链式存储结构实际上就是一个单链表,叫做链栈。插入和删 除操作只能在链栈的栈顶进行。
```c
typedef struct SNode *Stack; struct SNode{
ElementType Data;
struct SNode *Next;
};
```
初始化(建立空栈)
```c
Stack CreateStack()
{ /* 构建一个堆栈的头结点,返回指针 */
Stack S;
S =(Stack)malloc(sizeof(struct SNode));
S->Next = NULL;
return S;
}
```
判断堆栈S是否为空
```c
int IsEmpty(Stack S) /*判断堆栈S是否为空,若为空函数返回1,否则返回0 */
{
return ( S->Next == NULL );
}
```
* 入栈 Push
```c
void Push( ElementType item, Stack S) /* 将元素item压入堆栈S */
{
struct SNode *TmpCell;
TmpCell=(struct SNode *)malloc(sizeof(struct SNode))
TmpCell->Element = item;
TmpCell->Next = S->Next; // 插到头结点的后面
S->Next = TmpCell;
}
```
* 出栈 Top
```c
ElementType Pop(Stack S) /* 删除并返回堆栈S的栈顶元素 */
{
struct SNode *FirstCell;
ElementType TopElem;
if( IsEmpty( S ) )
{
printf(“堆栈空”);
return NULL;
}
else
{
FirstCell = S->Next;
S->Next = FirstCell->Next;
TopElem = FirstCell ->Element; // 获得被删除的这个值,return出去
free(FirstCell);
return TopElem;
}
}
```
## 应用:表达式求值
* 运算数相对顺序不变
* 运算符号顺序发生改变: 需要存储“等待中”的运算符号,要将当前运算符号与“等待中”的最后一个运算符号比较
* 如果最后一个符号的优先级比较高,则出栈
* 如果最后一个符号的优先级更低,则等待
括号怎么办?
左括号(优先级比乘号*高.但左括号(在堆栈中优先级就降到最低, 左括号(优先级比加号+低.
碰到右括号)后,括号内的计算结束,把堆栈内的抛出来,直到遇到左括号(.