• 数据结构笔记#栈


    可以说线性表的一个具体应用就是栈,可能看完以下代码你觉得这是什么嘛有什么卵用啊,但是栈在现实生活的中的应用,或者说这种概念的应用是非常广泛的。

    比如说各种浏览器的返回上一级功能。

    栈与线性表最大的差别就是它对数据的操控是受限的,遵守Last in First out(LIFO)“后进先出原则”的数据结构都可以叫栈。

    栈一般长这个样子(美工欠下了3.5个亿带着他的小姨子跑了!)

    右边是我们对线性表之单链表的正常理解,数据从表头到表尾依次排放。

    左边是栈的特性,处于上层的元素(较新)叫top,处于底部的元素(最先放进去的那个)叫bottom。

    这里注意一下top指针指向的位置,是一个空白的位置,而不是最顶层的那个数据。

    而bottom指针则一直指向最底层的那个数据。

    对栈的常见操作有push(入栈,将数据放入栈)和pop(出栈,将数据提取出来)。

    这两个操作只能影响最顶层的元素。

    以下是我的具体的代码实现,实现的方式有很多种,以下仅供参考。

     Github

    首先是栈的头文件.h

    Stack.h

    声明一下结构体及函数。

    链表一样,栈你可以搞成链式也可以搞成顺序的,这里我用了顺序存储结构,方便操作。

     1 #ifndef _STACK_H_
     2 #define _STACK_H_
     3 
     4 #include<stdio.h>
     5 #include<stdlib.h>
     6 
     7 //以下两个数据大小视实际情况而定
     8 //初始栈容量
     9 #define STACK_INIT_SIZE 10
    10 //每次扩容的增量
    11 #define STACKINCREMENT 10
    12 
    13 typedef int DataType;
    14 
    15 struct stack
    16 {
    17     //指向栈最顶上的元素的接下来一个位置
    18     //表示新入栈的值可以放在指向的地方
    19     DataType *Top;
    20     //指向栈底部,最里面的元素
    21     DataType *Bottom;
    22     //表示了当前栈的容量
    23     int stacksize;
    24 };
    25 typedef struct stack STACK;
    26 
    27 //新建栈
    28 int InitStack(STACK *S);
    29 
    30 //销毁栈
    31 int DestroyStack(STACK *S);
    32 
    33 //获取栈长度
    34 int StackLength(STACK S);
    35 
    36 //获取栈顶部元素
    37 int GetTop(STACK S, DataType *e);
    38 
    39 //Push操作,入栈,压栈
    40 int Push(STACK *S, DataType e);
    41 
    42 //Pop操作,出栈
    43 int Pop(STACK *S, DataType *e);
    44 
    45 //打印整表
    46 int StackTraverse(STACK S);
    47 
    48 #endif

    Stack.c

    不知道为什么感觉栈的代码比链表的简单。。。直接都贴上来吧。

    首先是初始化链表和销毁链表。

     1 int InitStack(STACK *S)
     2 {
     3     //创建出设定长度的顺序表,地址赋给bottom指针
     4     S->Bottom = (DataType*)malloc(STACK_INIT_SIZE*sizeof(DataType));
     5     if (!S->Bottom)
     6     {
     7         return 0;
     8     }
     9     S->stacksize = STACK_INIT_SIZE;
    10     S->Top = S->Bottom;
    11     return 1;
    12 }
    13 
    14 int DestroyStack(STACK *S)
    15 {
    16     S->Top = NULL;
    17     free(S->Bottom);
    18     S->Bottom = NULL;
    19     return 1;
    20 }

    然后是Push和Pop的函数,注释应该把代码解释的比较清楚了

     1 int Push(STACK *S, DataType e)
     2 {
     3     //当超出当前栈的容量时进行扩容
     4     //这里应该只有等于的情况
     5     //而不会大于
     6     if ((S->Top - S->Bottom) >= S->stacksize)
     7     {
     8         //realloc函数将开辟指定大小的储存空间
     9         //并将原来的数据全部移到这个新的储存空间
    10         S->Bottom = (DataType*)realloc(S->Bottom, (S->stacksize + STACKINCREMENT)*sizeof(DataType));
    11         if (!S->Bottom)
    12         {
    13             return 0;
    14         }
    15         //由于重新开辟了空间
    16         //需要重新根据bottom指针的位置指定top
    17         S->Top = S->Bottom + S->stacksize;
    18         //最后增加当前栈容量
    19         S->stacksize += STACKINCREMENT;
    20     }
    21     //再把入栈的数据存放好
    22     *(S->Top++) = e;
    23     return 1;
    24 }
    25 
    26 int Pop(STACK *S, DataType *e)
    27 {
    28     if (S->Bottom == S->Top)
    29     {
    30         printf("Empty Stack!Can not pop!
    ");
    31         return 0;
    32     }
    33     //top指针先减1再取值
    34     *e = *(--S->Top);
    35     return 1;
    36 }

    然后是其他一些奇奇怪怪的“辅助”函数

     1 int StackLength(STACK S)
     2 {
     3     return  S.Top - S.Bottom;
     4 }
     5 
     6 int GetTop(STACK S, DataType *e)
     7 {
     8     if (S.Bottom != S.Top)
     9     {
    10         //由于top指向的是最顶上元素的下一个位置
    11         //所以取出最顶上元素的时候
    12         //要把top减去1
    13         *e = *(S.Top - 1);
    14         return 1;
    15     }
    16     return 0;
    17 }

    最后是打印整个栈的数据的函数

     1 int StackTraverse(STACK S)
     2 {
     3     int timer = 0;
     4     int *cur=S.Bottom;
     5     if (S.Bottom ==S.Top)
     6     {
     7         printf("Empty!
    ");
     8         return 1;
     9     }
    10     while (cur < S.Top)
    11     {
    12         printf("%d) ", timer++);
    13         printf("%d
    ", *(cur++));
    14     }
    15     return 1;
    16 }

    最后随便写个main函数测试一下

    Stacktest.c

     1 #include"Stack.h"
     2 
     3 int main()
     4 {
     5     STACK s;
     6     int input=0;
     7     int output = 0;
     8     
     9     InitStack(&s);
    10     StackTraverse(s);
    11 
    12     while(scanf("%d",&input) && input!=999)
    13     {
    14         Push(&s, input);
    15     }
    16     StackTraverse(s);
    17     printf("Length: %d
    ", StackLength(s));;
    18 
    19     if (Pop(&s, &output))
    20     {
    21         printf("Poped : %d
    ", output);
    22     }
    23 
    24     DestroyStack(&s);
    25     return 0;
    26 }
    Stacktest.c

    不同人的代码差别是很大的。。。但数据结构代码又没有一个标准,适和自己的需求就好,我也不敢确定我这么写最好。

    如果感兴趣的话可以用栈做一个简单的计算器程序,用于计算比如

    (3+(3-2))*10 = ?

    这种的复合计算。

    具体实现方法,我还在摸索。。

  • 相关阅读:
    chapter 12_1 数据文件
    chapter11_3 字符串缓冲
    chapter11_2 Lua链表与队列
    chapter11_1 Lua数组、列表
    chapter9_4 非抢占式的多线程
    Java设计模式
    java内存回收机制
    javaIO流概述
    java集合概述
    java多线程
  • 原文地址:https://www.cnblogs.com/makejeffer/p/4808142.html
Copyright © 2020-2023  润新知