zoukankan      html  css  js  c++  java
  • 数据结构学习笔记02堆栈

    栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。是一种后进先出(LIFO)的数据结构。

    一.栈的顺序存储

    如图,左图为空栈,右图为已存放数据的栈。不难发现,栈只有一个口子,数据只能从一端进行入栈(push)和出栈(pop)操作。数据data的入栈顺序为 0, 1, 2.因此,出栈顺序只能为2,  1,0,从栈顶向栈底依次取出。

      1 //顺序栈
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 
      5 typedef int Status;
      6 typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
      7 
      8 #define STACK_INTI_SIZE 100        //存储空间初始分配量 
      9 #define STACKINCREMENT 10        //存储空间分配增量
     10 
     11 #define OK 1
     12 #define ERROR 0
     13 #define INFEASIBLE -1
     14 #define OVERFLOW -2
     15 
     16 typedef struct {
     17     SElemType *base;    
     18     SElemType *top;        //栈顶指针
     19     int stacksize;        //当前已分配的存储空间
     20 }SqStack;
     21 
     22 Status InitStack(SqStack &S);    
     23 Status DestroyStack(SqStack &S);
     24 Status ClearStack(SqStack &S);
     25 bool StackEmpty(SqStack S);        
     26 int StackLength(SqStack S);            
     27 Status GetTop(SqStack S, SElemType &e);    
     28 Status Push(SqStack &S, SElemType e);    
     29 Status Pop(SqStack &S, SElemType &e);    
     30 Status StackTraverse(SqStack S, Status(*visit)(SElemType e));
     31 
     32 Status visit(SElemType c)
     33 {
     34     printf("%d ", c);
     35     return OK;
     36 }
     37 /*操作结果:构造一个空栈S*/ 
     38 Status InitStack(SqStack &S)
     39 {
     40     S.base = (SElemType *)malloc(STACK_INTI_SIZE * sizeof(SElemType));
     41     if (!S.base) exit(OVERFLOW);
     42     S.top = S.base;
     43     S.stacksize = STACK_INTI_SIZE;
     44     return OK;
     45 }
     46 /*初始条件:栈S已存在。
     47 操作结果:栈S被销毁*/ 
     48 Status DestroyStack(SqStack &S)
     49 {
     50     free(S.base);
     51     free(&S); 
     52     S.top = NULL;
     53     S.base = NULL;
     54     S.stacksize = 0;
     55     return OK;
     56 }
     57 /*初始条件:栈S已存在。
     58 操作结果:将S清为空栈*/ 
     59 Status ClearStack(SqStack &S)
     60 {
     61     S.top = S.base;
     62     return OK;
     63 }
     64 /*初始条件:栈S已存在。
     65 操作结果:若栈S为空栈,则返回TRUE,否则FALSE*/ 
     66 bool StackEmpty(SqStack S)
     67 {
     68     if (S.top == S.base)
     69         return true;
     70     else
     71         return false;
     72 }
     73 /*初始条件:栈S已存在。
     74 操作结果:返回S的元素个数,即栈的长度*/ 
     75 int StackLength(SqStack S)
     76 {
     77     return (S.top - S.base);
     78 }
     79 /*初始条件:栈S已存在且非空。
     80 操作结果:用e返回S的栈顶元素*/ 
     81 Status GetTop(SqStack S, SElemType &e)
     82 {
     83     if (S.top == S.base) return ERROR;    //若栈空 返回ERROR
     84     e = *(S.top - 1);
     85     return OK;
     86 }
     87 /*初始条件:栈S已存在。
     88 操作结果:插入元素e为新的栈顶元素*/ 
     89 Status Push(SqStack &S, SElemType e)
     90 {
     91     if (S.top - S.base >= S.stacksize) {        //栈满追加存储空间
     92         S.base = (SElemType *)realloc(S.base,     
     93                     (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
     94         if (!S.base) exit(OVERFLOW);            //存储分配失败 
     95         S.top = S.base + S.stacksize;/*realloc可能返回了新的地址,所以top的地址需重新确定。*/ 
     96         S.stacksize += STACKINCREMENT;            //更新stacksize的值
     97     }
     98     *S.top++ = e;  //*S.top = e; S.top++
     99     return OK;
    100 }
    101 /*初始条件:栈S已存在且非空。
    102 操作结果:删除S的栈顶元素,并用e返回其值*/ 
    103 Status Pop(SqStack &S, SElemType &e)
    104 {
    105     if (S.top == S.base) return ERROR;
    106     e = * --S.top;  //S.top--; e = *S.top;
    107     return OK;
    108 }
    109 /*初始条件:栈S已存在且非空。
    110 操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit()。
    111 一旦visit()失败,则操作失败。*/ 
    112 Status StackTraverse(SqStack S, Status(*visit)(SElemType e))
    113 {
    114     if (S.base == S.top)
    115     {
    116         printf("栈为空!");
    117         return ERROR;
    118     }
    119     for (SElemType *p = S.base;p < S.top;p++)
    120         visit(*p);
    121     
    122     printf("
    ");
    123     return OK;
    124 }
    125 int main()
    126 {
    127     SqStack s;
    128     int e,length;
    129     
    130     if (InitStack(s) == OK)
    131         for (int j = 1;j <= 10;j++)
    132             Push(s, j);
    133     length = StackLength(s);
    134     StackTraverse(s,visit);
    135     printf("length = %d
    ", length);
    136     if (StackEmpty(s) == true)
    137         printf("empty!
    ");
    138     else printf("not empty!
    ");
    139     Pop(s, e);
    140     printf("e = %d
    ", e);
    141     ClearStack(s);
    142     if (StackEmpty(s) == true)
    143         printf("empty!
    ");
    144     else printf("not empty!
    ");
    145     DestroyStack(s);
    146     if (StackEmpty(s) == true)
    147         printf("empty!
    ");
    148     else printf("not empty!
    ");
    149     system("pause");
    150     return 0;
    151 }
    sj2_0

    栈的顺序存储表示:

    #define STACK_INTI_SIZE 100            //存储空间初始分配量

    #define STACKINCREMENT 10           //存储空间分配增量

    typedef struct {

           SElemType *base;        //在栈构造之前和销毁之后,base值为NULL

           SElemType *top;          //栈顶指针

           int stacksize;         //当前已分配的存储空间

    }SqStack;

    顺序栈的基本操作:/*只需浏览,作了解,详情(代码:sj2_0)*/

    Status InitStack(SqStack &S);     

           操作结果:构造一个空栈S。

    Status DestroyStack(SqStack &S);

           初始条件:栈S已存在。

        操作结果:栈S被销毁。

    Status ClearStack(SqStack &S);

           初始条件:栈S已存在。

        操作结果:将S清为空栈

    Status StackEmpty(SqStack S);   

           初始条件:栈S已存在。

        操作结果:若栈S为空栈,则返回TRUE,否则FALSE。

    int StackLength(SqStack S);       

           初始条件:栈S已存在。

        操作结果:返回S的元素个数,即栈的长度。

    Status GetTop(SqStack S, SElemType &e);

        初始条件:栈S已存在且非空。

        操作结果:用e返回S的栈顶元素。

    Status Push(SqStack &S, SElemType e);    

           初始条件:栈S已存在。

        操作结果:插入元素e为新的栈顶元素。

    Status Pop(SqStack &S, SElemType &e);   

        初始条件:栈S已存在且非空。

        操作结果:删除S的栈顶元素,并用e返回其值。

    Status StackTraverse(SqStack S, Status(*visit)(SElemType e));

           初始条件:栈S已存在且非空。

        操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit()。

        一旦visit()失败,则操作失败。

    1.入栈操作

      算法思路:

      1. *top = e

      2. top++

      3.若栈满用realloc追加空间

      //malloc、calloc、realloc的区别  http://www.cnblogs.com/kuotian/p/5277335.html

     1 /*初始条件:栈S已存在。
     2 操作结果:插入元素e为新的栈顶元素*/ 
     3 Status Push(SqStack &S, SElemType e)
     4 {
     5     if (S.top - S.base >= S.stacksize) {        //栈满追加存储空间
     6         S.base = (SElemType *)realloc(S.base,     
     7                     (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
     8         if (!S.base) exit(OVERFLOW);            //存储分配失败 
     9         S.top = S.base + S.stacksize;/*realloc可能返回了新的地址,所以top的地址需重新确定。*/ 
    10         S.stacksize += STACKINCREMENT;            //更新stacksize的值
    11     }
    12     *S.top++ = e;  //*S.top = e; S.top++
    13     return OK;
    14 }
    View Code

    2.出栈操作

      算法思路:

      1.若top == base 即栈为空,不能pop,返回ERROR。

      2.top—

      3.e = *top

    1 /*初始条件:栈S已存在且非空。
    2 操作结果:删除S的栈顶元素,并用e返回其值*/ 
    3 Status Pop(SqStack &S, SElemType &e)
    4 {
    5     if (S.top == S.base) 
    6             return ERROR;
    7     e = * --S.top;  //S.top--; e = *S.top;
    8     return OK;
    9 }        
    View Code

    practice:

    1.假设以顺序存储结构实现一个双向栈,即在一维数组的存储空间中存在着两个栈,他们的栈底分别设在数组的两个端点。试编写实现这个双向栈tws的三个操作:初始化inistack(tws)、入栈push(tws,I,x)和出栈pop(tws,i)的算法,其中i为0或1,用以分别指示设在数组两端的两个栈,并讨论按过程(正/误状态变量可设为变参)或函数设计这些操作算法各有说明优缺点。(代码:sj2_1)

      1 /*顺序存储结构双向栈 */
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 
      5 typedef int Status;
      6 typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */
      7 
      8 #define OK 1
      9 #define ERROR 0
     10 #define INFEASIBLE -1
     11 #define OVERFLOW -2
     12 
     13 #define MAXSIZE 100
     14 
     15 #define LEFT 1
     16 #define RIGHT 0
     17 typedef struct
     18 {
     19     SElemType data[MAXSIZE];
     20     int top1;    /* 栈1栈顶 */
     21     int top2;    /* 栈2栈顶 */
     22 }SqDoubleStack;
     23 
     24 Status InitStack(SqDoubleStack &S);
     25 Status DestroyStack(SqDoubleStack &S);
     26 Status ClearStack(SqDoubleStack &S);
     27 bool StackEmpty(SqDoubleStack S);
     28 int StackLength(SqDoubleStack S, int flag);
     29 Status GetTop(SqDoubleStack S, SElemType &e,int flag);
     30 Status Push(SqDoubleStack &S, SElemType e, int flag);
     31 Status Pop(SqDoubleStack &S, SElemType &e, int flag);
     32 Status StackTraverse(SqDoubleStack S, Status(*visit)(SElemType e),int flag);
     33 
     34 Status visit(SElemType c)
     35 {
     36     printf("%d ", c);
     37     return OK;
     38 }
     39 
     40 Status InitStack(SqDoubleStack &S)
     41 {
     42     S.top1 = -1;
     43     S.top2 = MAXSIZE;
     44     return OK;
     45 }
     46 
     47 Status DestroyStack(SqDoubleStack &S)
     48 {
     49     S.top1 = -1;
     50     S.top2 = -1;
     51 //    S.top1 = NULL;
     52 //    S.top2 = NULL;
     53     return OK;
     54 }
     55 
     56 Status ClearStack(SqDoubleStack &S)
     57 {
     58     S.top1 = -1;
     59     S.top2 = MAXSIZE;
     60     return OK;
     61 }
     62 
     63 bool StackEmpty(SqDoubleStack S)
     64 {
     65     if (S.top1 == -1 && S.top2 == MAXSIZE)
     66         return true;
     67     else
     68         return false;
     69 }
     70 
     71 int StackLength(SqDoubleStack S, int flag)
     72 {
     73     if (flag == LEFT)
     74         return (S.top1 + 1);
     75     else
     76         return (MAXSIZE - S.top2);
     77 }
     78 Status GetTop(SqDoubleStack S, SElemType &e, int flag)
     79 {
     80     if (flag == LEFT)
     81         e = S.data[S.top1];
     82     else
     83         e = S.data[S.top2];
     84     return OK;
     85 }
     86 
     87 Status Push(SqDoubleStack &S, SElemType e, int flag)
     88 {
     89     if (S.top1 + 1 == S.top2)
     90         return ERROR;
     91     if (flag == LEFT)
     92         S.data[++S.top1] = e;
     93     else
     94         S.data[--S.top2] = e;
     95     return OK;
     96 }
     97 
     98 Status Pop(SqDoubleStack &S, SElemType &e, int flag)
     99 {
    100     if (flag == LEFT) {
    101         if (S.top1 == -1) return ERROR;
    102         else
    103             e = S.data[S.top1--];
    104 
    105     }
    106     else {
    107         if (S.top2 == MAXSIZE) return ERROR;
    108         else
    109             e = S.data[S.top2++];
    110     }
    111     return OK;
    112 }
    113 
    114 Status StackTraverse(SqDoubleStack S, Status(*visit)(SElemType e),int flag)
    115 {
    116     int i;
    117     if (flag == LEFT)
    118     {
    119         for (i = 0;i <= S.top1;i++) 
    120             visit(S.data[i]);
    121     }
    122     else
    123     {
    124         for (i = MAXSIZE - 1;i >= S.top2;i--) 
    125             visit(S.data[i]);
    126     }
    127     printf("
    ");
    128     return OK;
    129 }
    130 
    131 int main()
    132 {
    133     SqDoubleStack s;
    134     int e;
    135     InitStack(s);
    136     
    137     Push(s, 2, 1);
    138     Push(s, 7, 1);
    139     Push(s, 3, 0);
    140     Push(s, 5, 0);
    141     Push(s, 5, 0);
    142     
    143     StackTraverse(s, visit, 1);
    144     StackTraverse(s, visit, 0);
    145     system("pause");
    146     return 0;
    147 }
    sj2_1

    二.链栈

    栈的链式表示如图,栈的操作是线性表操作的特例。(代码: sj2_2)

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 #define OK 1
     5 #define ERROR 0
     6 
     7 
     8 typedef int Status;
     9 typedef int ElementType; /* SElemType类型根据实际情况而定,这里假设为int */
    10 
    11  
    12 struct SNode{
    13     ElementType data;
    14     struct SNode *next;
    15 };
    16 typedef struct SNode *PtrToSNode;//PtrToSNode指向结点的指针
    17 typedef PtrToSNode Stack;//Stack指向结点的指针 
    18 
    19 Stack CreateStack();
    20 bool IsEmpty(Stack S);
    21 bool Push(Stack S, ElementType X);
    22 ElementType Pop(Stack S);
    23 
    24 /* 构建一个堆栈的头结点,返回该结点指针 */
    25 Stack CreateStack() 
    26 { 
    27     Stack S;
    28     S = (PtrToSNode)malloc(sizeof(struct SNode));
    29     S->next = NULL;
    30     return S;
    31 }
    32 /* 判断堆栈S是否为空,若是返回true;否则返回false */
    33 bool IsEmpty(Stack S)
    34 { 
    35     return ( S->next == NULL );
    36 }
    37 
    38 /* 将元素X压入堆栈S */
    39 bool Push(Stack S, ElementType X)
    40 { 
    41     PtrToSNode tmpCell;
    42     tmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
    43     tmpCell->data = X;
    44     tmpCell->next = S->next;
    45     S->next = tmpCell;
    46     return true;
    47 }
    48 
    49 /* 删除并返回堆栈S的栈顶元素 */
    50 ElementType Pop(Stack S)  
    51 { 
    52     PtrToSNode firstCell;
    53     ElementType topElem;
    54     if( IsEmpty(S) ) {
    55         printf("堆栈空"); 
    56         return ERROR;
    57     } else {
    58         firstCell = S->next; 
    59         topElem = firstCell->data;
    60         S->next = firstCell->next;
    61         free(firstCell);
    62         return topElem;
    63     }
    64 }
    65 int main()
    66 {
    67     Stack S;
    68     S = CreateStack(); 
    69     if(IsEmpty(S))
    70         printf("堆栈空
    ");
    71     else 
    72         printf("堆栈不空
    ");
    73     Push(S, 10);
    74     if(IsEmpty(S))
    75         printf("堆栈空
    ");
    76     else 
    77         printf("堆栈不空
    ");
    78     printf("pop = %d
    ",Pop(S)); 
    79     Pop(S); 
    80     return 0;
    81 }
    sj2_2

    1.入栈操作

     

      算法思路:

    1. 新建一个结点tmpCell
    2. tmpCell->next = S->next  ①
    3. S->next = tmpCell        ②
     1 /* 将元素X压入堆栈S */
     2 bool Push(Stack S, ElementType X)
     3 { 
     4     PtrToSNode tmpCell;
     5     tmpCell = (PtrToSNode)malloc(sizeof(struct SNode));
     6     tmpCell->data = X;
     7     tmpCell->next = S->next;
     8     S->next = tmpCell;
     9     return true;
    10 }
    View Code

    2.出栈操作

      算法思路:

      1.判断堆栈是否为空,若为空,无法pop,返回 ERROR

      2.确定栈顶元素firstCell,将其data赋值给topElem    ①

      3.S->next = firstCell->next   ②

      4.free(firstCell)                 ③

     1 /* 删除并返回堆栈S的栈顶元素 */
     2 ElementType Pop(Stack S)  
     3 { 
     4     PtrToSNode firstCell;
     5     ElementType topElem;
     6     if( IsEmpty(S) ) {
     7         printf("堆栈空"); 
     8         return ERROR;
     9     } else {
    10         firstCell = S->next; 
    11         topElem = firstCell->data;
    12         S->next = firstCell->next;
    13         free(firstCell);
    14         return topElem;
    15     }
    16 }
    View Code

    三.堆栈的其他应用

    1.函数调用及递归实现

    2.深度优先搜索

    3.回朔算法

    4.……

  • 相关阅读:
    思考题
    对敏捷开发的见解
    Code Review(自评)
    求数组最大子数组和
    [ASP.NET]在虚拟目录中禁止web.config继承IIS根目录的web.config的配置
    客户的真实需求
    利用using和try/finally語句來清理資源.
    《代码整洁之道》简单总结
    ASP.NET页面级别的事
    根据DIV移动生成图片
  • 原文地址:https://www.cnblogs.com/kuotian/p/5307950.html
Copyright © 2011-2022 走看看