数据结构| 栈

栈的定义

栈也称为堆栈,它是限定仅在表尾进行插入和删除操作的线性表。对于栈来说,表尾称为栈顶,表头称为栈尾。栈顶是动态变化的,它由一个栈指针的变量指示的。当表中没有元素时,称为空栈。栈的插入操作称为入栈或进栈,而删除操作称为出栈或退栈。

栈是一种后进先出的数据结构,也就是说最先进栈的一定是栈底元素,最后进栈的一定是栈顶元素,而每次删除的元素也一定是栈顶元素。

栈的抽象数据类型的定义:

ADT Stack{
    数据对象;
    数据关系;

    基本操作:
      InitStack(&S)
    操作结果:构造一个空栈S
      
      DestroyStack(&S)
    初始条件:存在栈S
    操作结果:栈S被销毁

      ClaerStack(&S)
    初始条件:存在栈S
    操作结果:将S清为空栈

      StackEmpty(S)
    初始条件:存在栈S
    操作结果:若栈S为空栈,则返回TRUE,否则返回FALSE

      StackLength(S)
    初始条件:存在栈S
    操作结果:返回S的元素个数,即栈的长度

      GetTop(S,&e)
    初始条件:存在栈S
    操作结果:用e返回S的栈顶元素

      Push(&S,&e)
    初始条件:存在栈S
    操作结果:插入元素e为新的栈顶元素

      Pop(&S,&e)
    初始条件:存在栈S且非空
    操作结果:删除S的栈顶元素,并用e返回其值

      StackTraver(S,visit())
    初始条件:存在栈S且非空
    操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit()。一旦调用失
    败,则操作失效
}ADT Stack

栈的表示与实现

1.宏定义解释

#define STACK_INIT_SIZE  100    //存储空间初始分配量
#define STACKINCREMENT   10   //存储空间分配增量

2.结构类型

typedef struct{
    SElemType *base;  //栈底的指针
    SElemType *top;  //栈顶的指针
    int stacksize;  //当前分配的存储空间
}SqStack;

3.基本操作的实现

(1)初始化栈InitStack

Status InitStack(SqStack &S){
    S.base=(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType))  //为栈底申请空间
    if(!S.base){
      exit(OVERFLOW);  //分配失败
    }
    S.top = S.base;  //初始化时栈顶指向栈底
    S.stcaksize = STACK_INIT_SIZE;
    return OK;
}

(2)销毁栈DestroyStack

Status DestroyStack(SqStack &S)
{
    S.top = NULL;   //栈顶指针指向空
    S.stacksize = 0;  //栈的内存置为0
    free(S.base);  //释放栈底的指针
    return OK;
}

(3)清空栈ClearStack

Status ClearStack(SqStack &S)
{
    S.top = S.base;  //当栈顶=栈底时为空栈
    return OK;
}

(4)判断栈是否为空StackEmpty

Status StackEmpty(SqStack S)
{
    if (S.top == S.base)  //当栈顶=栈底时为空栈
        return TRUE;  //空栈则返回TRUE
    else
        return FALSE;
}

(5)求栈的长度StackLength

Status StackLength(SqStack S)
{
    if (S.top == S.base)
        return FALSE;
    else
        return (S.top - S.base);//直接相减就是栈的长度
}

(6)求栈顶元素GetTop

Status GetTop(SqStack S, SElemType &e)
{
    if (S.top == S.base)
        return FALSE;
    else
        e = *(S.top - 1);  //返回栈顶的值
    return e;
}

(7)栈顶插入元素Push

Status Push(Sqstack &S,SElemType e){
  if(S.top-S.base>=S.stacksize){  //如果超出初始的容量则要申请内存
  S.base = (ElemType *)realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(ElemType)); 
  if(!S.base){
    exit(OVERFLOW);
  }
  S.stop = S.base + S.stacksize;  //栈顶的指向
  S.stacksize += STACKINCREMENT;  //容量增加
  }
  *S.stop=e;  
  S.top++;  
  return OK;
  }

(8)删除栈顶元素Pop

Status Pop(SqStack &S,SElemType &e){
  if(S.top==S.base){
    return ERROR;
  }
  else{
    S.top--;  //top指向栈顶的元素
    e=*S.top;  //给e赋值为栈顶元素的值
    return e;
  }
}

(9)遍历栈StackTraverse

Status StackTraverse(SqStack S){
  if(S.base==NULL||S.top==S.base){
    return ERROR;
  }
  ElemType *p;
  p=S.top;
    while (p > S.base)
    {
        p--;
        printf("%d ",*p);
    }
    return OK;
}

栈与递归

递归是指在函数的定义中,在定义自己的同时又出现了对自身的调用。而栈的后进先出的思想可以很好地应用于递归当中。

在递归中最经典的问题就是n阶汉诺塔问题,即假设有三个塔X,Y,Z,在塔X上放置n个大小直径各不相同且从小到大为1、2……n的圆盘,要求将塔X上的n个圆盘移动到塔Z上并要求按照同样的叠放顺序排列,同时必须满足:1)每次只能移动一个圆盘。2)圆盘可以放置X,Y,Z中任何一个塔上。3)小盘必须放在大盘的上面。

算法实现:

void Hanoi(int n,char x,char y,char z){
//将塔X上排列好的由上到下编号为1~n的圆盘移动到塔Z上,Y作为辅助塔
    if(n==1){
        Move(x,1,z);  //函数功能:将编号为1的圆盘从X移到Z上
    }
    else{
        Hanoi(n-1,x,z,y);  //调用自己
        Move(x,n,z);
        Hanoi(n-1,y,x,z);
    }
}
    原文作者:yzbkaka
    原文地址: https://www.jianshu.com/p/ac43cdbe1782
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞