zoukankan      html  css  js  c++  java
  • 数据结构之_栈的顺序存储和链式存储的代码实现

    数据结构之_栈的顺序存储和链式存储的代码实现

    加入我们QQ群:183791416 致读者的话:曾经的我们很年少,现在我们要为理想的路疯狂的走下去。

    目录

    正文

    回到顶部

    数据结构之_栈的顺序存储和链式存储的代码实现

    1.栈的基本概念

    • 概念:

        首先它是一个线性表,也就是说,栈元素具有线性关系,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中说是在线性表的表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。

    • 特性

        它的特殊之处在于限制了这个线性表的插入和删除的位置,它始终只在栈顶进行。这也就使得:栈底是固定的,最先进栈的只能在栈底。

    • 操作
      •   栈的插入操作,叫做进栈,也成压栈。类似子弹入弹夹(如下图所示)
      •   栈的删除操作,叫做出栈,也有的叫做弾栈,退栈。如同弹夹中的子弹出夹(如下图所示)
      •   创建栈
      •   销毁栈
      •   清空栈
      •   进栈
      •   出栈
      •   获取栈顶元素
      •   获取栈的大小 

    栈的抽象数据类型

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    ADT 栈(stack)

    Data

        通线性表。元素具有相同的类型,相邻的元素具有前驱和后继关系。

    Operation

        // 初始化,建立一个空栈S

        InitStack(*S);

        // 若栈存在,则销毁它

        DestroyStack(*S);

        // 将栈清空

        ClearStack(*S);

        // 若栈为空则返回true,否则返回false

        StackEmpty(S);

        // 若栈存在且非空,用e返回S的栈顶元素

        GetTop(S,*e);

        // 若栈S存在,插入新元素e到栈S中并成为其栈顶元素

        Push(*S,e);

        // 删除栈S中的栈顶元素,并用e返回其值

        Pop(*S, *e);

        // 返回栈S的元素个数

        StackLength(S);

    endADT

    2.栈的顺序存储代码实现

    • 基本概念

        栈的顺序存储结构简称顺序栈,它是运算受限制的顺序表。顺序栈的存储结构是:利用一组地址连续的的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针top只是栈顶元素在顺序表中的位置。

    • 设计与实现

        因为栈是一种特殊的线性表,所以栈的顺序存储可以通过顺序线性表来实现。

    SeqStack.h  

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    #ifndef SEQSTACK_H

    #define SEQSTACK_H

    #include<stdlib.h>

    #include<stdio.h>

    //数组去模拟栈的顺序存储

    #define MAX_SIZE 1024

    #define SEQSTACK_TRUE 1

    #define SEQSTACK_FALSE 0

    typedef struct SEQSTACK {

        void* data[MAX_SIZE];

        int size;

    }SeqStack;

    //初始化栈

    SeqStack* Init_SeqStack();

    //入栈

    void Push_SeqStack(SeqStack* stack, void* data);

    //返回栈顶元素

    void* Top_SeqStack(SeqStack* stack);

    //出栈

    void Pop_SeqStack(SeqStack* stack);

    //判断是否为空

    int IsEmpty(SeqStack* stack);

    //返回栈中元素的个数

    int Size_SeqStack(SeqStack* stack);

    //清空栈

    void Clear_SeqStack(SeqStack* stack);

    //销毁

    void FreeSpace_SeqStack(SeqStack* stack);

    #endif

    SeqStack.c  

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    84

    #include"SeqStack.h"

    //初始化栈

    SeqStack* Init_SeqStack() {

        SeqStack* stack = (SeqStack*)malloc(sizeof(SeqStack));

        for (int i = 0; i < MAX_SIZE; i++) {

            stack->data[i] = NULL;

        }

        stack->size = 0;

        return stack;

    }

    //入栈

    void Push_SeqStack(SeqStack* stack, void* data) {

        if (stack == NULL) {

            return;

        }

        if (stack->size == MAX_SIZE) {

            return;

        }

        if (data == NULL) {

            return;

        }

        stack->data[stack->size] = data;

        stack->size++;

    }

    //返回栈顶元素

    void* Top_SeqStack(SeqStack* stack) {

        if (stack == NULL) {

            return NULL;

        }

        if (stack->size == 0) {

            return NULL;

        }

        return stack->data[stack->size - 1];

    }

    //出栈

    void Pop_SeqStack(SeqStack* stack) {

        if (stack == NULL) {

            return;

        }

        if (stack->size == 0) {

            return;

        }

        stack->data[stack->size - 1] = NULL;

        stack->size--;

    }

    //判断是否为空

    int IsEmpty(SeqStack* stack) {

        if (stack == NULL) {

            return -1;

        }

        if (stack->size == 0) {

            return SEQSTACK_TRUE;

        }

        return SEQSTACK_FALSE;

    }

    //返回栈中元素的个数

    int Size_SeqStack(SeqStack* stack) {

        return stack->size;

    }

    //清空栈

    void Clear_SeqStack(SeqStack* stack) {

        if (stack == NULL) {

            return;

        }

        for (int i = 0; i < stack->size; i++) {

            stack->data[i] = NULL;

        }

        stack->size = 0;

    }

    //销毁

    void FreeSpace_SeqStack(SeqStack* stack) {

        if (stack == NULL) {

            return;

        }

        free(stack);

    }

    栈的顺序存储.c  

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    #define _CRT_SECURE_NO_WARNINGS

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include "SeqStack.h"

    typedef struct PERSON {

        char name[64];

        int age;

    }Person;

    int main(void) {

        //创建栈

        SeqStack* stack = Init_SeqStack();

        //创建数据

        Person p1 = { "aaa", 10 };

        Person p2 = { "bbb", 20 };

        Person p3 = { "ccc", 30 };

        Person p4 = { "ddd", 40 };

        Person p5 = { "eee", 50 };

        //入栈

        Push_SeqStack(stack, &p1);

        Push_SeqStack(stack, &p2);

        Push_SeqStack(stack, &p3);

        Push_SeqStack(stack, &p4);

        Push_SeqStack(stack, &p5);

        //输出

        while (Size_SeqStack(stack) > 0) {

            //访问栈顶元素

            Person* person = (Person*)Top_SeqStack(stack);

            printf("Name:%s Age:%d\n", person->name, person->age);

            //弹出栈顶元素

            Pop_SeqStack(stack);

        }

        //释放内存

        FreeSpace_SeqStack(stack);

        system("pause");

        return 0;

    }

    3.栈的链式存储  

    • 基本概念

        栈的链式存储结构简称链栈。

        思考如下问题

             栈只是栈顶来做插入和删除操作,栈顶放在链表的头部还是尾部呢?

        答:由于单链表有头指针,而栈顶指针也是必须的,那干嘛不让他俩合二为一呢,所以比较好的办法就是把栈顶放在单链表的头部。另外都已经有了栈顶在头部了,单链表中比较常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。

    • 设计与实现

        链栈是一种特殊的线性表,链栈可以通过链式线性表来实现。

     LinkStack.h

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    #ifndef LINKSTACK_H

    #define LINKSTACK_H

    #include <stdlib.h>

    #include <stdio.h>

    //链式栈的结点

    typedef struct LINKNODE {

        struct LINKNODE* next;

    }LinkNode;

    //链式栈

    typedef struct LINKSTACK {

        LinkNode head;

        int size;

    }LinkStack;

    //初始化函数

    LinkStack* Init_LinkStack();

    //入栈

    void Push_LinkStack(LinkStack* stack, LinkNode* data);

    //出栈

    void Pop_LinkStack(LinkStack* stack);

    //返回栈顶元素

    LinkNode* Top_LinkStack(LinkStack* stack);

    //返回栈元素的个数

    int Size_LinkStack(LinkStack* stack);

    //清空栈

    void Clear_LinkStack(LinkStack* stack);

    //销毁栈

    void FreeSpace_LinkStack(LinkStack* stack);

    #endif

    LinkStack.c  

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    #include"LinkStack.h"

    //初始化函数

    LinkStack* Init_LinkStack() {

        LinkStack* stack = (LinkStack*)malloc(sizeof(LinkStack));

        stack->head.next = NULL;

        stack->size = 0;

        return stack;

    }

    //入栈

    void Push_LinkStack(LinkStack* stack, LinkNode* data) {

        if (stack == NULL) {

            return;

        }

        if (data == NULL) {

            return;

        }

        data->next = stack->head.next;

        stack->head.next = data;

        stack->size++;

    }

    //出栈

    void Pop_LinkStack(LinkStack* stack) {

        if (stack == NULL) {

            return;

        }

        if (stack->size == 0) {

            return;

        }

        //第一个有效结点

        LinkNode* pNext = stack->head.next;

        stack->head.next = pNext->next;

        stack->size--;

    }

    //返回栈顶元素

    LinkNode* Top_LinkStack(LinkStack* stack) {

        if (stack == NULL) {

            return NULL;

        }

        if (stack->size == 0) {

            return NULL;

        }

        return stack->head.next;

    }

    //返回栈元素的个数

    int Size_LinkStack(LinkStack* stack) {

        if (stack == NULL) {

            return -1;

        }

        return stack->size;

    }

    //清空栈

    void Clear_LinkStack(LinkStack* stack) {

        if (stack == NULL) {

            return;

        }

        stack->head.next = NULL;

        stack->size = 0;

    }

    //销毁栈

    void FreeSpace_LinkStack(LinkStack* stack) {

        if (stack == NULL) {

            return;

        }

        free(stack);

    }

    栈的链式存储.c  

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    #define _CRT_SECURE_NO_WARNINGS

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include "LinkStack.h"

    typedef struct PERSON {

        LinkNode node;

        char name[64];

        int age;

    }Person;

    int main(void) {

        //创建栈

        LinkStack* stack = Init_LinkStack();

        //创建数据

        Person p1, p2, p3, p4, p5;

        strcpy(p1.name, "aaa");

        strcpy(p2.name, "bbb");

        strcpy(p3.name, "ccc");

        strcpy(p4.name, "ddd");

        strcpy(p5.name, "eee");

        p1.age = 10;

        p2.age = 20;

        p3.age = 30;

        p4.age = 40;

        p5.age = 50;

        //入栈

        Push_LinkStack(stack, (LinkNode*)& p1);

        Push_LinkStack(stack, (LinkNode*)& p2);

        Push_LinkStack(stack, (LinkNode*)& p3);

        Push_LinkStack(stack, (LinkNode*)& p4);

        Push_LinkStack(stack, (LinkNode*)& p5);

        //输出

        while (Size_LinkStack(stack) > 0) {

            //取出栈顶元素

            Person* p = (Person*)Top_LinkStack(stack);

            printf("Name:%s Age:%d\n", p->name, p->age);

            //弹出栈顶元素

            Pop_LinkStack(stack);

        }

        //销毁栈

        FreeSpace_LinkStack(stack);

        system("pause");

        return 0;

    }

    4.栈的应用(案例)

    4.1案例1: 就近匹配

    几乎所有的编译器都具有检测括号是否匹配的能力,那么如何实现编译器中的符号成对检测?如下字符串:

    1

    #include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0;}

    • 算法思路
      •  从第一个字符开始扫描
      •  当遇见普通字符时忽略,
      •  当遇见左符号时压入栈中
      •  当遇见右符号时从栈中弹出栈顶符号,并进行匹配
      •  匹配成功:继续读入下一个字符
      •  匹配失败:立即停止,并报错
      •  结束:
      •  成功: 所有字符扫描完毕,且栈为空
      •  失败:匹配失败或所有字符扫描完毕但栈非空
    • 总结
      •  当需要检测成对出现但又互不相邻的事物时可以使用栈“后进先出”的特性
      •  栈非常适合于需要“就近匹配”的场合

    案例代码:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    #include"LinkStack.h"

    //案例一 就近匹配

    void test02(){

        char* str = "#include <stdio.h> int main() { int a[4][4]; int (*p)[4]; p = a[0]; return 0;}";

        //初始化栈

        LinkStack* lstack = InitLinkStack();

        //匹配括号

        char* pCurrent = str;

        while (*pCurrent != '\0'){

            if (*pCurrent == '('){

                PushLinkStack(lstack, pCurrent);

            }

            else if (*pCurrent == ')'){

                char* p = (char*)TopLinkStack(lstack);

                if (*p == '('){

                    PopLinkStack(lstack);

                }

            }

            pCurrent++;

        }

        if (GetLengthLinkStack(lstack) > 0){

            printf("匹配失败!\n");

        }

        //销毁栈

        DestroyLinkStack(lstack);

    }

    int main(){

        test02();

        system("pause");

        return EXIT_SUCCESS;

    4.2案例2:中缀表达式和后缀表达式

    • l  后缀表达式(由波兰科学家在20世纪50年代提出)
      •  将运算符放在数字后面 ===》 符合计算机运算
      •  我们习惯的数学表达式叫做中缀表达式===》符合人类思考习惯
    • l  实例
      •  5 + 4 => 5 4 + 
      •  1 + 2 * 3 => 1 2 3 * + 
      •  8 + ( 3 – 1 ) * 5 => 8 3 1 – 5 * +
    • l  中缀转后缀算法:

      遍历中缀表达式中的数字和符号:

      •  对于数字:直接输出
      •   对于符号:
        •    左括号:进栈 
        •    运算符号:与栈顶符号进行优先级比较
      •   若栈顶符号优先级低:此符号进栈 (默认栈顶若是左括号,左括号优先级最低)
      •   若栈顶符号优先级不低:将栈顶符号弹出并输出,之后进栈
    • l  右括号:将栈顶符号弹出并输出,直到匹配左括号

      遍历结束:将栈中的所有符号弹出并输出

    • l  中缀转后缀伪代码 priority

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    transform(exp)

    {

        创建栈S;

        i= 0;

        while(exp[i] != ‘\0’)

    {

            if(exp[i] 为数字)

            {

                Output(exp[i]);

            }

            else if(exp[i] 为符号)

            {

                while(exp[i]优先级 <= 栈顶符号优先级)

                {

                    output(栈顶符号);

                    Pop(S);

                }

                Push(S, exp[i]);

            }

            else if(exp[i] 为左括号)

            {

                Push(S, exp[i]);

            }

            else if(exp[i] 为右括号)

            {

                while(栈顶符号不为左括号)

                {

                    output(栈顶符号);

                    Pop(S);

                }

                从S中弹出左括号;

            }

            else

            {

                报错,停止循环;

            }

            i++;

    }

    while(size(S) > 0 && exp[i] == ‘\0’)

    {

            output(栈顶符号);

            Pop(S);

    }

    }

    • l  动手练习

      将我们喜欢的读的中缀表达式转换成计算机喜欢的后缀表达式

      中缀表达式: 8 + ( 3 – 1 ) * 5

           后缀表达式:  8 3 1 – 5 * +

    4.3案例3:计算机如何基于后缀表达式计算

    • l  思考

        计算机是如何基于后缀表达式计算的?

        例如:8 3 1 – 5 * +

    • l  计算规则

        遍历后缀表达式中的数字和符号

      •   对于数字:进栈
      •   对于符号:
        •    从栈中弹出右操作数
        •    从栈中弹出左操作数
        •    根据符号进行运算
        •    将运算结果压入栈中

        遍历结束:栈中的唯一数字为计算结果

    • l  代码实现(伪代码) express

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    compute(exp)

    {

        创建栈;

        int i = 0;

        whileexp[i] != ‘\0’)

        {

            ifexp[i]为数字)

            {

                Push(S, exp[i]);

            }

            else if(exp[i]为符号)

            {

    1. 从栈顶弹出右操作数;

    2. 从栈中弹出左操作数;

    3. 根据符号进行运算;

    4. Push(stack, 结果);

            }

            else

            {

                报错,停止循环;

            }

            i++;

        }

        if( Size(s) == 1 && exp[i] == ‘\0’)

        {

            栈中唯一的数字为运算结果;

        }

        返回结果;

    }

      

    别去打扰一个不愿意理你的人,因为他心里那个最重要的人不是你,想陪你吃饭的人,酸甜苦辣都爱吃 ,想送你回家的人,东南西北都顺路,想和你聊天的人,永远不会嫌你话多,想回你信息的人,苦累忙烦都有空,努力过,付出活,就豪气的挥挥手 大步走开,没必要非得等到伤痕累累才知道离开,所有人和事,自己问心无愧就好,不是你的也别强求,其实,对不理你的人来说,你的每一条信息 每一个电话都是打扰,每一次关心,每一遍问候都是压力

  • 相关阅读:
    redis你要知道的事
    Nginx七层负载均衡的几种调度算法
    JQuery的父、子、兄弟节点选择器
    laravel通用和万能路由
    jquery竖向企业组织结构图
    phpexcel功能操作
    animatext.js使用介绍
    Centos firewalld开放端口
    获取微信accesstoken并文件缓存方式
    css处理文字不换行、换行截断、溢出省略号
  • 原文地址:https://www.cnblogs.com/grj001/p/12223739.html
Copyright © 2011-2022 走看看