一、什么是栈
栈是限定仅在表头进行插入和删除操作的线性表。要搞清楚这个概念,首先要明白”栈“原来的意思,如此才能把握本质。”栈“者,存储货物或供旅客住宿的地方,可引申为仓库、中转站,所以引入到计算机领域里,就是指数据暂时存储的地方,所以才有进栈、出栈的说法。

二、两种常用的栈
1、顺序栈
使用连续的内存空间模拟栈的空间,一般使用数组来实现,数组索引为0即为栈底,其次再定义一个变量储存栈顶位置即可,这种栈实现起来比较简单容易操作,适合初学者。

2、链式栈
使用零散的内存空间模拟栈的空间,一般使用链表1来实现,链表尾部即为栈底,链表头部即为栈顶。

三、栈的实现

代码节选自网络

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
//定义结点结构体
typedef struct Node
{
 int data;    //内容
 struct Node * pNext; //指向下一结点的指针
} NODE, * PNODE;   //NODE等价于struct Node, PNODE等价于struct Node *
//定义栈的结构体
typedef struct Stack
{
 PNODE pTop;    //栈顶结点
 PNODE pBottom;   //栈底结点
} STACK, * PSTACK;   //STACK等价于struct Stack, PSTACK等价于struct Stack *
//函数声明
void initStack(PSTACK pStack);    //对栈进行初始化的函数
void pushStack(PSTACK pStack, int val);  //入栈的函数
bool popStack(PSTACK pStack, int * pVal);//出栈的函数,*pVal用来保存出栈的元素内容
void traverseStack(PSTACK pStack);   //遍历栈的函数
bool isEmpty(PSTACK pStack);    //判断栈是否为空的函数
void clearStack(PSTACK pStack);   //清空栈的函数
int main(void)
{
 STACK stack;   //定义一个栈变量,STACK等价于struct Stack
 int val;    //用来保存出栈的内容
 initStack(&stack);  //调用栈的初始化函数
 pushStack(&stack, 10); //调用入栈的函数
 pushStack(&stack, 20);
 pushStack(&stack, 30);
 pushStack(&stack, 50);
 traverseStack(&stack); //调用遍历栈的函数
 //调用出栈的函数
 if(popStack(&stack, &val))
  printf("出栈成功,出栈的元素值为:%d\n", val);
 else
  printf(" 出栈失败!");
 //调用清空栈的函数
 clearStack(&stack);
 traverseStack(&stack); //调用遍历栈的函数
 system("pause");
 return 0;
}

void initStack(PSTACK pStack)
{
 //创建一个空结点,让pTop指向它
 pStack->pTop = (PNODE)malloc(sizeof(NODE));
 if(NULL != pStack->pTop)
 {
  //将pBottom也指向空节点
  pStack->pBottom = pStack->pTop;
  //清空空结点的指针域
  pStack->pTop->pNext = NULL;
 }
 else      //如果内存分配失败
 {
  printf("内存分配失败!程序退出!\n");
  exit(-1);
 }
 return;
}

void pushStack(PSTACK pStack, int val)
{
 //动态创建一个新结点
 PNODE pNew = (PNODE)malloc(sizeof(NODE));
 //设置新结点的数据域的值
 pNew->data = val;
 //将新结点的指针域指向之前建的空节点
 pNew->pNext = pStack->pTop;   //pStack->pTop不能换成pStack->pBottom
 //pTop指向新的结点
 pStack->pTop = pNew;
 return;
}

bool popStack(PSTACK pStack, int * pVal)
{
 if(isEmpty(pStack))
 {
  return false;
 }
 else
 {
  //先保存栈顶元素的地址,然后将pTop指向下一元素,最后释放之前栈顶元素的内存
  PNODE rNode = pStack->pTop;
  *pVal = rNode->data;
  pStack->pTop = rNode->pNext;
  free(rNode);
  rNode = NULL;
  return true;
 }
}

void traverseStack(PSTACK pStack)
{
 //将栈顶赋给一个临时结点,因为在遍历栈的时候不能销毁栈
 PNODE pNode = pStack->pTop;
 //循环遍历栈,直到栈底
 while(pStack->pBottom != pNode )
 {
  printf("%d  ", pNode->data);
  pNode = pNode->pNext;
 }
 printf("\n");
 return;
}

bool isEmpty(PSTACK pStack)
{
 if(pStack->pTop == pStack->pBottom)
  return true;
 else
  return false;
}

void clearStack(PSTACK pStack)
{ //栈为空,则退出该函数
 if(isEmpty(pStack))
 {
  return;
 }
 else
 { 
  //两个结点指针变量用来释放栈中元素的内存
  PNODE p = pStack->pTop;
  PNODE q = NULL;
  //循环释放内存
  while(p != pStack->pBottom)
  {
   q = p->pNext;
   free(p);
   p = q;
  }
  //将栈顶和栈底指向同一个指针域为空的结点
  pStack->pTop = pStack->pBottom;
  return;
 }
}

四、栈的存储
1、栈的顺序存储结构
  栈的顺序存储结构需要使用一个数组和一个整型变量来实现。利用数组来顺序存储栈中的所有元素,利用整型变量来存储栈顶元素的下标位置,可这个变量称为栈顶指针。

const int MaxSize = 50;
struct Stack
{
    ElemType stack[MaxSize];
    int top;
};

若要对存储栈的数组空间采用动态分配,则可定义如下:

struct Stack
{
    ElemType *stack;
    int top;
    int MaxSize;
};

 top的值为-1表示栈空。

2、栈的链式存储结构
  栈的链式存储结构是通过由结点构成的单链表实现的,此时表头指针被称为栈顶指针,由栈顶指针指向的表头结点被称为栈顶结点,整个单链表被称为链栈。对链栈的插入和删除操作是在单链表的表头进行的。
当向一个链栈插入元素时,是把该元素插入到栈顶,即,使该元素结点的指针域指向原来的栈顶结点,而栈顶指针则修改为指向该元素结点,使该结点成为新的栈顶结点。

五、两栈的空间共享
当程序中同时使用两个栈时,可以将两个栈的栈底设在向量空间的两端,让两个栈各自向中间延伸。
当一个栈的元素较多,超过向量空间的一半时,只要另一个栈的元素不多,那么前者就可以占用后者的部分存储空间。只有当整个向量空间被两个栈占满(即两个栈顶相遇)时,才会发生上溢,因此两个栈共享一个长度为m的向量空间

六、栈的抽象数据类型

ADT 栈(stack)  
    Data  
        同线性表。元素具有相同的类型,相邻元素具有前驱和后堆关系。  
    Operation  
        InitStack ( *S ):初始化操作.建立一个空栈S。  
        DestroyStack ( *S ):若栈存在,則销毁它。  
        ClearStack (*S):将栈清空。  
        StackEmpty ( S ):若栈为空,返回true,否則返回 false。  
        GetTop (S,*e):若栈存在且非空,用e返回S的栈顶元素。  
        Push (*S,e):若栈S存在,插入新元素e到栈S中并成为栈頂元素。  
        Pop (*S,*e):删除栈S中栈顶元素,并用e返回其值。  
        StackLength (S):返回回栈S的元素个数。  
    endADT  

七、栈的应用
裴波那契数列的计算
四则运算表达式
后缀表达式的定义
递归
中缀转后缀

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值