My Gitee Link

数据结构笔记 — 栈和队列

栈和队列


 

1 栈

1.1 栈基本概念
  • 定义:栈 (Stack) 时一个后进先出的线性表,塔要求 只在表尾进行删除和插入操作

    • 栈的元素必须 “后进先出”

    • 栈的操作只能在这个线性表的表尾进行

    • 表尾称为栈的栈顶 (top) ,相应的表头称为栈底 (bottom)

  • 出栈和入栈

    • 栈的插入操作 (Push),叫做进栈(入栈)

    • 栈的删除操作 (Pop),叫做出栈(弹栈)

  • 栈的本质是一个线性表,线性表有两种存储形式,那么栈也有分为 栈的顺序存储结构栈的链式存储结构

  • 最开始栈中不含有任何数据,叫做 空栈 ,此时 栈顶就是栈底

  • 数据从栈顶进入,栈顶栈底分高,整个栈的当前容量变大

  • 数据出栈时从栈顶弹出,栈顶下移,整个栈的当前容量变小

1.2 栈结构组成
  • 栈结构的结构定义

    typedef struct{
        ElemType *base;
        ElemType *top;
        int stackSize;
    }sqStack;
    ​
    // *base : 指向栈底的指针变量
    // *top  : 指向栈顶的指针变量
    // stackSize : 指示栈当前可使用的最大容量
1.3 栈基本操作
  • 初始化一个栈

    #define STACK_INIT_SIZE 100
    ​
    initStack(sqSatck *s){
        s->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
        if(!s->base){
            exit(0);
        }
        s->top = s->base;   //最开始,栈顶就是栈底
        s->stackSize = STACK_INIT_SIZE;
    }
  • 入栈操作

    • 也叫作压栈操作,即香栈中存放数据

    • 入栈操作在栈顶进行,每压入一个数据, top 指针 +1 ,直到栈满为止

      #include <stdio.h>
      #include <stdlib.h>
      #define STACKINCREMENT 10void Push(sqStack *s, ElemType e){
          //若栈满,追加空间
          if (s->top - s->base >= s->stackSize){
              s->base = (ElemType *)realloc(s->base, (s->stackSize + STACKINCREMENT) * sizeof(ElemType));
              if (!s->base){
                  exit(0);
              }
              s->top = s->base + s->stackSize;    //设置栈顶
              s->stackSzie = s->stackSzie + STACKINCREMENT;   //设置栈最大容量
          }
          *(s->top) = e;
          s->top++;
      }
  • 出栈操作

    • 每从栈内弹出一个数据,栈容量 -1 ,栈顶指针下移

       #include <stdio.h>
      #include <stdlib.h>void Pop(sqStack *s, ElemType *e){
          if (s->top == s->base){ //栈为空
              exit(0);
          }
          *e = *--(s->top);
      }
  • 清空栈

    void clearStack(sqStack *s){
        s->base = s->top;
    }
  • 销毁栈

    void destroyStack(sqStack *s){
        int i, len;
        len = s->satckSize;
        for(i = 0; i < len, i++){
            free(s->base);
            s->base++;
        }
        s->base = s->top = NULL;
        s->stackSize = 0;
    }
  • 计算栈当前容量

    int StackLength(sqStack s){
        return (s.top - s.base);
    }
    // s.top - s.base 返回的是当前栈的容量(即当前栈的元素个数),该操作原理相当于:
    // (*top - *base) / sizeof(ElemType)
1.4 栈的链式存储结构
  • 链栈结构

    typedef struct StackNode{
        ElemType data;  //存放栈数据
        struct StackNode *next;
    } StackNode, *LinkStackPtr;
    ​
    typedef struct LinkStack{
        LinkStackPtr top;   // top 指针
        int count;          // 栈元素计数器
    }
  • 进栈操作

    Status Push(LinkStack *s, ElemType e){
        LinkStackPtr p (LinkStackPtr)malloc(sizeof(StackNode));
        p->data = e;
        p->next = s->top;
        s->top = p;
        s->count++;
        
        return OK;
    }
  • 出栈操作

    Status Pop(LinkStack *s,ElemType *e){
        LinkStackPtr p;
        if (StackEmpty(*s))     //判新是否为空栈
            return ERROR;
        *e = s->top->data;
        p = s->top;
        s->top = s->top->next;
        free(p);
        s->count--;
        
        return OK;
    }
1.5 逆波兰表达式

例如,对于 (1-2)*(4+5) ,表示为 1 2 - 4 5 + * ,利用了栈的特性

  • 先将 1、2 入栈,遇到操作符 - 后将 1、2 弹出栈并计算 1-2 结果,把结果 -1 入栈

  • 再将 4、5 入栈,遇到操作符 + 后将 4、5 弹出栈并计算 4+5 结果,把结果 9 入栈

  • 最后遇到操作符 * 入栈,将 -19 弹出栈,计算得到结果 -9 ,栈空,计算结束

【练习】

按照以上原理,实现逆波兰计算器,要求实现以下功能:

  • 实现对逆波兰输入的表达式进行计算

  • 支持带小数点的数据输入

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <ctype.h>
  4 #define STACK_INIT_SIZE 20
  5 #define STACK_INCREMENT 10
  6 #define MAX_BUFFER 10
  7   8 typedef double ElemType;
  9 typedef struct {
 10     ElemType *base;
 11     ElemType *top;
 12     int stackSize;
 13 } sqStack;
 14  15 //栈初始化
 16 void InitStack(sqStack *s){
 17     s->base = (ElemType *)malloc(STACK_INIT_SIZE * sizeof(ElemType));
 18     if (!s->base) exit(0);
 19     s->top = s->base;
 20     s->stackSize = STACK_INIT_SIZE;
 21 }
 22  23 //入栈操作
 24 void Push(sqStack *s, ElemType e){
 25  26     //栈满,追加空间
 27     if (s->top - s->base >= s->stackSize){
 28         s->base = (ElemType *)realloc(s->base, (s->stackSize + STACK_INCREMENT) * sizeof(ElemType));
 29         if (!s->base){
 30             exit(0);
 31         }
 32         s->top = s->base + s->stackSize;
 33         s->stackSize = s->stackSize + STACK_INCREMENT;
 34     }
 35     *(s->top) = e;
 36     s->top++;
 37 }
 38  39 //出栈操作
 40 void Pop(sqStack *s, ElemType *e){
 41     if (s->top == s->base)
 42         return;
 43     *e = *--(s->top);
 44 }
 45  46 //求栈长
 47 int stackLen(sqStack s){
 48     return (s.top - s.base);
 49 }
 50  51  52 int main() {
 53  54     sqStack s;
 55     int i = 0;
 56     char c;
 57     char str[MAX_BUFFER];
 58     double d, e;
 59     InitStack(&s);
 60  61     printf("请按照逆波兰表达式输入带计算数据,数据之间使用运算符隔开,以 @ 结束:\n");
 62     scanf("%c", &c);
 63     while (c != '@'){
 64         while (isdigit(c) || c == '.'){
 65             str[i++] = c;
 66             str[i] = '\0';
 67             if (i >= 10){
 68                 printf("输入单个数据过大!\n");
 69                 return -1;
 70             }
 71             scanf("%c", &c);
 72             if (c == ' '){
 73                 d = atof(str);
 74                 Push(&s, d);
 75                 i = 0;
 76                 break;
 77             }
 78         }
 79  80         switch (c) {
 81             case '+':
 82                 Pop(&s, &e);
 83                 Pop(&s, &d);
 84                 Push(&s, d+e);
 85                 break;
 86             case '-':
 87                 Pop(&s, &e);
 88                 Pop(&s, &d);
 89                 Push(&s, d-e);
 90                 break;
 91             case '*':
 92                 Pop(&s, &e);
 93                 Pop(&s, &d);
 94                 Push(&s, d*e);
 95                 break;
 96             case '/':
 97                 Pop(&s, &e);
 98                 Pop(&s, &d);
 99                 if (e){
100                     Push(&s, d/e);
101                 } else{
102                     printf("除数为零!\n");
103                     return -1;
104                 }
105                 break;
106         }
107         scanf("%c", &c);
108     }
109 110     Pop(&s, &d);
111     printf("最终的结果为: %f\n", d);
112 113     return 0;
114 }

2 队列

2.1 队列概念
  • 队列 (queue) 只允许在一端进行插入操作,在另一端进行删除操作的线性表,是一种 先进先出 的线性表

  • 结构定义

    typedef struct QNode{
        ElemType data;
        struct QNode *next;
    } QNode, *QueuePtr;
    ​
    typedef struct {
        QueuePtr front, rear;
    } LinkQueue;
2.2 队列基本操作
  • 创建队列

    void InitQueue(LinkQueue *q){
        q->front = q->rear = (QueuePtr)malloc(sizeof(ElemType));
        if (!q->front) exit(0);
        q->front->next = NULL;
    }
  • 入队列操作

    void InsertQueue(LinkQueue *q, ElemType e){
        QueuePtr p;
        p = (QueuePtr)malloc(sizeof(QNode));
        if (!p) exit(0);
        p->data = e;
        p->next = NULL;
        q->rear->next = p;
        q->rear = p;
    }
  • 出队列操作

    void DeleteQueue(LinkQueue *q, ElemType *e){
        QueuePtr p;
        if (q->front == q->rear) return;
        p = q->front->next;
        *e = p->data;
        q->front->next = p->next;
        if (q->rear == p)
            q->rear = q->front;
        free(p);
    }
  • 销毁队列

    void DestroyQueue(LinkQueue *q){
        while (q->front){
            q->rear = q->front->next;
            free(q->front);
            q->front = q->rear;
        }
    }
2.3 循环队列
  • 结构组成

    typedef struct {
        ElemType *base;
        int front, rear;
    } CycleQueue;
  • 初始化循环队列

    void InitCQueue(CycleQueue *q){
        q->base = (ElemType *)malloc(MAXSIZE * sizeof(ElemType));
        if (!q->base) exit(0);
        q->front = q->rear = 0;
    }
  • 入循环队列

    void InsertCQueue(CycleQueue *q, ElemType e){
        if ((q->rear*1) % MAXSIZE == q->front) return;
        q->base[q->rear] = e;
        q->rear = (q->rear+1) % MAXSIZE;
    }

 

  • 出循环队列
    void DeleteCQueue(CycleQueue *q, ElemType *e){
        if (q->front == q->rear) return;
        *e = q->base[q->front];
        q->front = (q->front+1) % MAXSIZE;
    }

     

 >>>>> END <<<<<

 

 

 
posted @ 2020-12-16 16:30  笨草戆沐  阅读(239)  评论(0)    收藏  举报