风也温柔

计算机科学知识库

堆栈的数据结构 【数据结构和算法】了解认识栈,并实现栈的相关函数

  到现在我们了解并认识了线性表的概念,动态、静态顺序表的建立,以及两种链表的实现,接下来我们要认识一个新的内容,新的概念堆栈数据结构,栈,是基于顺序表或者链表的一种新型数据结构。

  目录

  一、栈是什么?

  栈:是一种特殊的线性表。其只允许在固定的一端进行插入和删除操作。进行数据的插入和删除的一端称为栈顶堆栈的数据结构 【数据结构和算法】了解认识栈,并实现栈的相关函数,另外的一端称为栈底。栈中的数据元素遵循先进后出(后进先出)的原则

  之前在学习C语言的时候,就i听说过的两种概念

  1.压栈:栈的插入操作叫做进栈、压栈、入栈等,插入数据在栈顶

  2.出栈:栈的删除操作叫做出栈。出数据也在栈顶

  什么是硬件堆栈结构_堆栈的数据结构_堆栈式结构

  二、栈的实现 1.实现的方式

  有两种

  1.我们可以通过顺序表的形式实现,因为进行尾插尾删除,代价小,就算是更改或者删除栈中指定的元素,不过也是移动位置而已。

  如图所示:

  堆栈的数据结构_堆栈式结构_什么是硬件堆栈结构

  结构体代码如下:

   #define MAX 100

    #define CAp 4 ///初始化的时候capacity的容量
    #define Make 2//每一次增加的newCapacity的容量
    //静态
    typedef struct Stacknode {
        int data[MAX];//数据域
        int size;//表示元素个数
    }Stack;
    //动态
    typedef struct Stacknode2 {
        int* data;//数据域
        int size;//表示元素个数
        int capacity;//表示当前容量
    }Stack1;

  2.通过链表的形式进行实现栈表

  结构体如下:

   //创建基础结构

    typedef struct node {
        int data;
        struct node* next;
    }ST;
    //栈实际上就是一个只能进行头插头删的单向链表
    //创建栈的头尾结点 结构体
    typedef struct stack {
        struct node* top;//栈顶元素地址
        struct node* bottom;//栈底元素地址
        int size;//栈的元素个数

  2.实现栈的函数

  以链表实现栈为例,在本文结尾处,一并放置用数组实现栈的完整代码

  1.初始化栈

  结构体如上,使用的是上文的结构体类型

  代码如下:

  

    //初始化栈
    struct stack* create_stack()
    {
        struct stack* s = (struct stack*)malloc(sizeof(struct stack));
        s->size = 0;
        s->bottom = s->top = NULL;
        return s;
    }

  使用函数,申请空间,将s的size大小置为0,和top表示栈底栈顶都指向NULL

  2.入栈

  如图所示:

  堆栈式结构_堆栈的数据结构_什么是硬件堆栈结构

  什么是硬件堆栈结构_堆栈的数据结构_堆栈式结构

  代码如下:

   //创建新的结点

    struct node* create_node(int data) {
        struct node* newnode = (struct node*)malloc(sizeof(struct node));
        newnode->next = NULL;
        newnode->data = data;
        return newnode;
    }
    //入栈
    //入栈首先要将准备入栈的元素封装成结点,和链表没有差别
    void stackPush(struct stack* s, int x) {
        ST* newnode = create_node(x);
        newnode->next = s->top;
        s->top = newnode;
        s->size++;
    }

  3.出栈

  如图所示:

  什么是硬件堆栈结构_堆栈的数据结构_堆栈式结构

  代码如下:

   //出栈

    void stackPop(struct stack* s, int* x) {
    //判断是否为空栈   如果是 空栈的话就  使得输出 Pop failed
        if (s->size == 0) {
            printf("Pop failed\n");
            exit(-1);
        
        }
        //创建结点临时变量  赋值得到栈顶元素
        ST* tmp = s->top;
        *x = tmp->data;//得到数值
        s->top = tmp->next;
        s->size--;

  4.查看栈顶元素

  代码如下:

   //查看栈顶元素

    void stackTop(struct stack* s, int* x) {
        if (s->size == 0) {
            printf("空栈~~\n");
            exit(-1);
        }
        *x = s->top->next->data;

  5.打印栈和清空栈

  代码如下:

   //清空栈

    void make_stack_empty(struct stack* s) {
        s->size = 0;
        s->bottom = s->top ;
        //将栈底等于栈顶就可以  然后将size为0
    }
    void stackPrint(struct stack* s) {
        //打印栈表
        ST* list = s->top;
        printf("top -> ");
        while (list!=NULL) {
    <p>

            printf("%d -> ", list->data);
            list = list->next;
        }

</p>
  三、完整代码实现 1.链表实现栈

   #define _CRT_SECURE_NO_WARNINGS

    #include
    #include
    #include
    #include
    //创建基础结构
    typedef struct node {
        int data;
        struct node* next;
    }ST;
    //栈实际上就是一个只能进行头插头删的单向链表
    //创建栈的头尾结点 结构体
    typedef struct stack {
        struct node* top;//栈顶元素地址
        struct node* bottom;//栈底元素地址
        int size;//栈的元素个数
    };
    //表示每一个栈都是struct stack* 类型的,栈中的每一个怨怒是都是struct node *类型的  不仅需要为栈分配内存,还需要为压入栈中的元素分配内存
    /*
    node中的next指针用于让栈中上面的节点连接到下面的节点,stack中的top和bottom分别存放当前栈顶元素的地址和栈底元素的后一个位置的地址(NULL),
    因为是用于指向栈中节点的指针,所以得是struct node* 类型。*/
    //初始化栈
    struct stack* create_stack()
    {
        struct stack* s = (struct stack*)malloc(sizeof(struct stack));
        s->size = 0;
        s->bottom = s->top = NULL;
        return s;
    }
    //一开始栈是空的所以 size为0  top  bottom是NULL
    //创建新的结点
    struct node* create_node(int data) {
        struct node* newnode = (struct node*)malloc(sizeof(struct node));
        newnode->next = NULL;
        newnode->data = data;
        return newnode;
    }
    //入栈
    //入栈首先要将准备入栈的元素封装成结点,和链表没有差别
    void stackPush(struct stack* s, int x) {
        ST* newnode = create_node(x);
        newnode->next = s->top;
        s->top = newnode;
        s->size++;
    }
    //出栈
    void stackPop(struct stack* s, int* x) {
    //判断是否为空栈   如果是 空栈的话就  使得输出 Pop failed
    <p>![堆栈的数据结构_什么是硬件堆栈结构_堆栈式结构][6]

        if (s->size == 0) {
            printf("Pop failed\n");
            exit(-1);
        
        }
        //创建结点临时变量  赋值得到栈顶元素
        ST* tmp = s->top;
        *x = tmp->data;//得到数值
        s->top = tmp->next;
        s->size--;
    }
    //查看栈顶元素
    void stackTop(struct stack* s, int* x) {
        if (s->size == 0) {
            printf("空栈~~\n");
            exit(-1);
        }
        *x = s->top->next->data;
    }
    //清空栈
    void make_stack_empty(struct stack* s) {
        s->size = 0;
        s->bottom = s->top ;
        //将栈底等于栈顶就可以  然后将size为0
    }
    void stackPrint(struct stack* s) {
        //打印栈表
        ST* list = s->top;
        printf("top -> ");
        while (list!=NULL) {
            printf("%d -> ", list->data);
            list = list->next;
        }
    }
    int main()
    {
        struct stack *s = create_stack();
        stackPush(s, 1);
        stackPush(s, 2);
        stackPush(s, 3);
        stackPush(s, 4);
        stackPush(s, 5);
        stackPrint(s);
        int a = 0;
        stackPop(s,&a);
        printf("\n%d\n", a);
        stackPrint(s);
        return 0;

</p>
  2.数组(顺序表)实现栈

   #define _CRT_SECURE_NO_WARNINGS

    #include"steck.h"
    #define _CRT_SECURE_NO_WARNINGS
    #include
    #include
    #include
    #include
    //栈是限定在一个表里面的一段进行插入删除操作的线性表
    // 数据进出的顺序为先进后处
    <p>

    // 应用场景:网页浏览的时候的后退  编辑软件的撤销
    // 
    //创建栈  两个方式:数组(顺序表)和 单链表
    //1.数组:选用数组用来做栈的存储结构,只需要在数组末尾进行操作即可,完美避开数组操作中挪动数据缺陷
          //   显然是可以用数组来做栈的存储结构
    //2.单链表  :因为栈是吸纳星表的一段进行操作,所以一般是用链表头进行操作
    //进行头插头删  是用链表更好 效率更高
    //1.用数组的方式
    typedef int StackDataType;
    typedef struct Stcak {
        StackDataType* data;
        int top;
        int capacity;   //数据域和元素个数
    }ST;
    //初始化
    void StackInit(ST* ps) {
        ps->data = (StackDataType*)malloc(sizeof(StackDataType) * 4);
        if (ps->data == NULL) {
            printf("malloc failed\n");
            exit(-1);
        }
        ps->top = 0;
        ps->capacity = 4;
    }
    //压栈
    void StackPush(ST* ps, int x) {
        assert(ps);//断言
        //满了就扩容
        if (ps->top == ps->capacity) {
            StackDataType* tmp = (StackDataType*)realloc(ps->data, sizeof(StackDataType) * ps->capacity * 2);
            if (tmp == NULL) {
                printf("realloc failed\n");
                exit(-1);
            }
            else {
                ps->data = tmp;
                ps->capacity *= 2;
            }
        }
        ps->data[ps->top] = x;
        ps->top++;
    }
    //出栈
    void StackPop(ST* ps) {
        //出栈是将最后一个元素放出来  先进后出
        assert(ps);
        assert(ps->top > 0);//断言进行判断是否栈为空  即top!=0
        ps->top--;
        //直接减减就可以  没有了对应元素 的数据  如果再次压栈的话 会把之前的数据进行更改
    }
    //取得栈顶元素
    StackDataType StackTop(ST* ps) {
        assert(ps);
    &emsp;&emsp;

        assert(ps->top > 0);
        return ps->data[ps->top - 1];//因为top栈顶始终要保持比元素个数大一,保证压栈的时候先压栈然后再加加
    //所以取栈顶元素 的时候 top-1
    }
    //销毁栈
    void StackDestory(ST* ps) {
        assert(ps);
        free(ps->data);
        //释放数组data的空间
        ps->data = NULL;
        ps->top = ps->capacity = 0;
    }
    //求栈中元素个数
    int StackSize(ST* ps) {
        assert(ps);
        return ps->top;
    }
    //判断是否为空
    bool StackEmpty(ST* ps) {
        assert(ps);
        return ps->top == 0;
    }
    void StackPrint(ST* ps) {
        //打印栈表
        assert(ps);
        for (int i = 0; i < ps->top; i++) {
            printf("%d ", ps->data[i]);
        }
        printf("\n");
    }
    int main()
    {
        ST s;
        ST *ps=&s;
      /*  StackInit(&ps);
        StackPush(&ps, 1);
        StackPush(&ps, 2);
        StackPush(&ps, 3);
        StackPush(&ps, 4);
        StackPush(&ps, 5);
        StackPrint(&ps);*/
        StackInit(ps);
        StackPush(ps, 1);
        StackPush(ps, 2);
        StackPush(ps, 3);
        StackPush(ps, 4);
        StackPush(ps, 5);
        StackPop(ps);//出栈成功
        StackPrint(ps);
        printf("%d \n", StackTop(ps));//取得栈顶元素
        printf("%d \n", StackSize(ps));//获得栈表元素个数
        StackDestory(ps);
        StackPrint(ps);//销毁栈表成功
        return 0;
    }

</p>
  总结

  栈是限定在一个表里面的一段,对其进行插入删除操作的线性表,数据进出的顺序为先进后处,应用场景:网页浏览的时候的后退 编辑软件的撤销,实际上栈的功能就这样,学会顺序表以及链表的使用,对于栈来讲,只是懂得头擦头删,理解概念了,就好掌握并实现栈。

  下文,我们会讲解一下队列,和栈相似,但是另有不同,敬请期待吧堆栈的数据结构,感谢大家支持!!!

  文章来源:https://blog.csdn.net/qq_63319459/article/details/128793244