数据结构——栈


一、抽象数据类型栈的定义
  1. 定义:只能在表的一端( 栈顶 也就是表尾)进行插入和删除运算的线性表。表头称为栈底,不含元素的空表称为空栈
  2. 逻辑结构:与线性表相同,仍为一对一关系
  3. 存储结构:用顺序栈或链栈存储均可
  4. 运算规则:只能在栈顶运算,且访问结点时依照 后进先出(LIFO)或先进后出(FILO)的原则
  5. 实现方式:关键是编写入栈和出栈函数,具体实现依顺序栈或链栈的不同而不同
二、栈的表示和实现
顺序表和顺序栈的对比:
顺序栈的栈底指针(base)始终指向栈底位置,若base的值为Null表明栈结构不存在。栈顶指针(top)初值指向栈底,top=base可作为空栈的标记,每当插入新的栈顶元素是,指针top增1;删除栈顶元素时,top减1。
顺序栈的存储表示:
#define  MAXSIZE  100//最大存储空间的分配
typedef struct
{
  SElemType   *base;
  SElemType   *top;
  int stacksize;  //当前已分配的存储空间,以元素为单位
}SqStack;
顺序栈的基本操作:
存储分配:
Status InitStack (SqStack &S){
//构造一个空栈
SqStack *S
S.base =  new SElemType[MAXSIZE];  //存储分配
if(!S.base)exit (OVERFLOW);
S.top=S.base;  //初始化栈顶指针,现在这是一个空栈
S.stacksize = MAXSIZE;  //设置栈的大小
return OK;
}//InitStack
判断栈是否为空:
bool StackEmpty( SqStack S )
{
  if(S.top == S.base)
        return true;
   else
        return false;
}
求顺序栈的长度:
int StackLength( SqStack S ){
  return S.top – S.base;
}
清空顺序栈:
Status ClearStack( SqStack S ){
  if( S.base )
          S.top = S.base;
  return OK;
}
销毁顺序栈:
Status DestroyStack( SqStack &S ){
  if( S.base ){
  delete S.base ;
  S.stacksize = 0;
  S.base = S.top = NULL;
  }
    return OK;
}
顺序栈进栈:
Status Push( SqStack &S, SElemType e)
{
  if( S.top - S.base== S.stacksize ) // 栈满
        return ERROR;  
  *S.top=“D”;
    S.top++;
  return OK;
}
顺序栈出栈:
Status Pop( SqStack &S, SElemType &e) {
  if( S.top == S.base ) // 栈空
        return ERROR;  
  S.top--;
   e=*S.top;
  return OK;
}
选取栈顶元素:
Status GetTop( SqStack S, SElemType &e)
{
  if( S.top == S.base )  // 栈空
        return ERROR;  
  e = *( S.top – 1 );
  return OK;
}
链栈:受限的单链表,只能在链表头部进行操作,故没有必要附加头结点。栈顶指针就是链表的头指针。
存储分布:
typedef  struct StackNode {
      SElemType  data;
      struct StackNode *next; //栈顶指针也就是头指针
} StackNode,  *LinkStack;
LinkStack S;  
  • 栈的应用举例
1.数制转换
【算法步骤】
① 初始化一个空栈S。
② 当十进制数N非零时,循环执行以下操作:
* 把N与8求余得到的八进制数压入栈S;
* N更新为N与8的商。
③ 当栈S非空时,循环执行以下操作:
* 弹出栈顶元素e;
* 输出e。
代码实现:
【算法描述】
void conversion(int N)
{//对于任意一个非负十进制数,打印输出与其等值的八进制数
   InitStack(S);  //初始化空栈S
   while(N)  //当N非零时,循环
   {
      Push(S,N%8);  //把N与8求余得到的八进制数压入栈S
      N=N/8;  //N更新为N与8的商
   }
   while(!StackEmpty(S))//当栈S非空时,循环
   {
      Pop(S,e);  //弹出栈顶元素e
      cout<<e;  //输出e
   }
}
2.行编辑程序:
设立一个输入缓冲区,用以接收用户输入的一行字符。当输入的字符既不是退格符(@)也不是退行符(#)时,将这个字符压入栈顶;如果是一个退格符则从栈顶删去一个元素;如果是一个退行符则将字符栈清为空栈。
代码实现:
void LineEdit(){
//利用字符栈S,从终端接收一行并传送至调用过程的数据区
    InitStack(S);   //构造一个空栈S
ch=getchar();   //从终端接收第一个字符
while(ch!=EOF){
    while(ch!=EOF&&ch!='/n'){
            switch(ch){
                 case'#':Pop(S,ch);       break;   //仅当栈非空时退栈,弹出ch
                 case'@':ClearStack(S);       break;   //设置S为空栈
                 default:Push(S,ch);             break;//有效字符进栈
              }
             ch=getchar();//从终端接收下一个字符
    }//将从栈底到栈顶的栈内字符传送至调用过程的数据区;
    ClearStack(S);   //重置S为空栈
    if(ch!=EOF)   ch=getchar();
}
DestroyStack(S);
}//LineEdit
  • 栈与递归的实现
递归函数:直接调用自己或者通过一列的调用语句间接地调用自己的函数
double Fact ( double n ) {
    if ( n == 0) return 1;
    else return n * Fact (n-1);
}
在运行被调用函数之前,系统需先完成三件事:
(1)将实参,返回地址等传递给被调用函数
(2)为被调用函数的局部变量分配存储区
(3)将控制转移到被调用函数的入口
从被调用函数返回调用函数之前,系统需要完成的三件事:
(1)保存被调用函数的计算结果
(2)释放被调用函数的数据区
(3)依照被调用函数保存的返回地址将控制转移到调用函数
三阶Hanoi塔问题:
将X上的圆盘移至Z上并仍然按相同顺序叠排
代码实现:
#include<iostream.h>
int c=0;
void move(char x,int n,char z)
{
  cout<<++c<<","<<n<<","<<x<<",“<<z<<endl;
}
void Hanoi(int n,char A,char B,char C)
{
  if(n==1)
  move(A,1,C);
  else
  {
  Hanoi(n-1,A,C,B);
  move(A,n,C);
  Hanoi(n-1,B,A,C);
  }
}
void main(){
  Hanoi(3,'a','b','c');
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值