数据结构 - 栈

是限定仅在表尾进行插入和删除操作的线性表(函数调用过程,列车进入车站)

 

一、栈的定义(先进后出,后进先出)

栈顶(top): 允许插入和删除

栈底(bottom):最先进来的元素将会留在栈底

 

栈的ADT

数据对象:D = {ai | ai 属于 ElemSet, i = 1, 2, 3, 4... n , n >= 0}

数据关系:同线性表,元素具有相同的类型,相邻元素具有前驱与后继关系。

操作:

  • InitStack(*S):初始化操作,建立一个空栈S.
  • DestoryStack(*S): 若栈存在,则销毁它。
  • ClearStack(*S): 将栈清空
  • StackEmpty(S): 若栈为空,返回true, 否则返回false.
  • StackLength(S): 返回栈S的元素个数。
  • GetTop(S, *e): 若栈存在且非空,用e返回S的栈顶元素
  • Push(*S, e): 若栈S存在,插入新元素e到栈S中并成为栈顶元素
  • Pop(*S, *e): 删除栈S中栈顶元素,并用e返回其值。
  • StackTraverse(S, visit()): 从栈底到栈顶依次对S的每个数据元素调用函数visit()。

 

二、栈的顺序存储结构及实现

栈的结构定义

/* stack.h栈的顺序存储表示 */
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACKINCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
{
  SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
  SElemType *top; /* 栈顶指针 */
  int stacksize; /* 当前已分配的存储空间,以元素为单位 */
}SqStack; /* 顺序栈 */

/*
 * 操作结果: 构造一个空栈S
 */
Status InitStack(SqStack *S);

/*
 * 初始条件:栈S已存在
 * 操作结果:栈S被销毁
 */
Status DestroyStack(SqStack *S);

/*
 * 初始条件: 栈S已存在
 * 操作结果: 将S清为空栈
 */
Status ClearStack(SqStack *S);

/*
 * 初始条件:栈S已存在
 * 操作结果:若栈S为空栈,则返回true, 否则返回false
 */
Status StackEmpty(SqStack S);

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

/*
 * 初始条件: 栈S已存在且非空
 * 操作结果: 用e返回S的栈顶元素
 */
Status GetTop(SqStack S,SElemType *e);

/*
 * 初始条件: 栈S已存在
 * 操作结果: 返回S的元素的个数,即栈的长度
 */
Status Push(SqStack *S,SElemType e);

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

/*
 * 初始条件: 栈S已存在且非空
 * 操作结果: 从栈底到栈顶依次对s的每个数据元素调用函数visit()
 */
Status StackTraverse(SqStack S,Status(*visit)(SElemType));

 

 

顺序栈操作的实现

/* stack.c 顺序栈(存储结构由stack.h定义)的基本操作(9个) */

Status InitStack(SqStack *S)
{ /* 构造一个空栈S */
  (*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
  if(!(*S).base)
    exit(OVERFLOW); /* 存储分配失败 */
  (*S).top=(*S).base;
  (*S).stacksize=STACK_INIT_SIZE;
  return OK;
}

Status DestroyStack(SqStack *S)
{ /* 销毁栈S,S不再存在 */
  free((*S).base);
  (*S).base=NULL;
  (*S).top=NULL;
  (*S).stacksize=0;
  return OK;
}

Status ClearStack(SqStack *S)
{ /* 把S置为空栈 */
  (*S).top=(*S).base;
  return OK;
}

Status StackEmpty(SqStack S)
{ /* 若栈S为空栈,则返回TRUE,否则返回FALSE */
  if(S.top==S.base)
    return TRUE;
  else
    return FALSE;
}

int StackLength(SqStack S)
{ /* 返回S的元素个数,即栈的长度 */
  return S.top-S.base;
}

Status GetTop(SqStack S,SElemType *e)
{ /* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
  if(S.top>S.base)
  {
    *e=*(S.top-1);
    return OK;
  }
  else
    return ERROR;
}

Status Push(SqStack *S,SElemType e)
{ /* 插入元素e为新的栈顶元素 */
  if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */
  {
    (*S).base=(SElemType *)realloc((*S).base,((*S).stacksize+STACKINCREMENT)*sizeof(SElemType));
    if(!(*S).base)
      exit(OVERFLOW); /* 存储分配失败 */
    (*S).top=(*S).base+(*S).stacksize;
    (*S).stacksize+=STACKINCREMENT;
  }
  *((*S).top)++=e;
  return OK;
}

Status Pop(SqStack *S,SElemType *e)
{ /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
  if((*S).top==(*S).base)
    return ERROR;
  *e=*--(*S).top;
  return OK;
}

Status StackTraverse(SqStack S,Status(*visit)(SElemType))
{ /* 从栈底到栈顶依次对栈中每个元素调用函数visit()。 */
  /* 一旦visit()失败,则操作失败 */
  while(S.top>S.base)
    visit(*S.base++);
  printf("\n");
  return OK;
}

 

三、栈的链式存储结构

/* 链栈的定义 */
typedef struct StackNode
{
    SElemType data;
    struct StackNode * next;
} StackNode, *LinkStackPtr;

typedef struct LinkStack
{
    LinkStackPtr top;
    int count;
} LinkStack;

 

 

栈的插入与删除

/* 栈的链式存储结构 - 入栈操作 */
/* 插入元素e为新的栈顶元素 */
Status Push(LinkStack *S, SElemType e)
{
    LinkStackPtr s = (LinkStackPtr)malloc(sizeof(StackNode));
    s->data = e;
    s->next = S->top;    //把当前有栈顶指针赋值给新结点直接后继
    S->top = s;            //将新结点s赋值给栈顶指针
    S->count++;            //计数
    return OK;    
}

/* 栈的链式存储结构 - 出栈操作 */
/* 插入元素e为新的栈顶元素 */
Status Pop(LinkStack *S, SElemType *e)
{
    LinkStackPtr p;
    if(StackEmpty(*S))
        return ERROR;
    *e = S->top->data;            //将栈顶元素值赋值给e
    p = S->top;                    //将栈顶点赋值给p
    S->top = S->top->next;        //将指针下移一位
    free(p);                    //释放内存p
    S->count--;
    return OK;
}

 

四、栈的应用

编写一个简单的计算器程序,用来计算按照逆波兰符号(Reverse Polish Notation, PRN)录入的整数表达式。

逆波兰符号指运算符在操作数的后边。

 

例如: 用户输入如下表达式

30 5 - 7 *

结果为175。

 

程序执行步骤:

第一步:将30压入栈

第二步:将5压入栈

第三步:将5与30取出,计算30-5的值得25

第四步:将25压入栈

第五步:将7压入栈

第六步:将7与25取出,相乘得175

第七步:将175入栈

无输入,返回结果。

 

/*
*RPN:Reverse Polish Notation
*逆波兰表达式:将数据存储在栈中进行计算时,入栈时将按照以下顺序
*如:(1-2)*(4+5) RPN是: 1 2 - 4 5 + *
*如: 5 -(6+7)* 8 + 9 / 4  RPN是:  5 6 7 + 8 * - 9 4 / 
*/

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#define STACK_INIT_SIZE 20
#define STACKINCREMENT  10
#define MAXBUFFER       10

/* 定义栈结构 */
typedef double ElemType;
typedef struct
{
    ElemType *base;
    ElemType *top;
    int stacksize;
}sqStack;

//初始化栈
InitStack(sqStack  *s)
{
    s->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
    if (!s->base) exit(0);
    s->top = s->base;
    s->stacksize = STACK_INIT_SIZE;
}

//入栈操作
Push(sqStack  *s, ElemType e)
{
    if (s->top - s->base >= s->stacksize)
    {
        s->base = (ElemType *)malloc((STACK_INIT_SIZE + STACKINCREMENT) * sizeof(ElemType));
        if (!s->base) exit(0);
        s->top = s->base + s->stacksize;
    }

    *(s->top) = e;
    s->top++;
}

//出栈操作
Pop(sqStack  *s, ElemType *e)
{
    if (s->top == s->base) return;
    *e = *--(s->top);
}

//获取栈长度
int StackLen(sqStack s)
{
    return (s.top - s.base);
}

int main()
{
    sqStack s;
    char c;
    double d, e;
    char str[MAXBUFFER];
    int i = 0;
    
    InitStack(&s);   /* 初始化栈 */

    printf("Input datas with Reverse Polish Notation,Ending with '#' \n");
    scanf("%c", &c);

    while (c != '#')
    {
        while (isdigit(c))  //数字与空格的处理
        {
            str[i++] = c;
            str[i] = '\0';
            if (i >= 10)
            {
                printf("ERROR:Data is out of range \n");
                return -1;
            }
            scanf("%c", &c);
            if (c == ' ')
            {
                d = atof(str);
                Push(&s, d);     // 入栈
                i = 0;
                break; 
            }
        }
        switch (c)        //四则运算符号处理
        {
        case '+':
            Pop(&s, &e);
            Pop(&s, &d);
            Push(&s, d + e);
            break;
        case '-':
            Pop(&s, &e);
            Pop(&s, &d);
            Push(&s, d - e);
            break;
        case '*':
            Pop(&s, &e);
            Pop(&s, &d);
            Push(&s, d * e);
            break;
        case '/':
            Pop(&s, &e);
            Pop(&s, &d);
            if (e != 0)
            {
                Push(&s, d / e);
            }
            else
            {
                printf("ERROR:Input Wrong");
                return -1;
            }
            break;
        }
        scanf("%c", &c);
    }
    Pop(&s, &d);
    printf("Result is: %f\n", d);

    return 0;
}

 

 

问题:用两个栈实现队列

思路:定义s1,s2, 两个栈

当入队时,将数据压入s1

当出队时,将数据倒入s2, 取出第栈底元素,再将s2倒入s1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2016-10-28 11:12  elewei  阅读(333)  评论(0)    收藏  举报