第二十四天(数据结构:栈和队列)队列实践请看下一篇

发布于:2025-08-05 ⋅ 阅读:(18) ⋅ 点赞:(0)
栈和队列
    栈 : 是限定在表尾进行插入和删除操作的线性表
        实现是一回事,但是必须要满足栈的基本特点
    它的设计思路是:先进后出,后进先出

    栈有两端
        1 栈顶(top) :插入数据删除数据都只能在这一端
            访问也只能访问栈顶
        2 栈底(bottom) : 栈底是不会动

    实现栈我们就需要实现如下操作:
        init    初始化这个栈
        top     返回栈顶元素,但是不出栈
        empty   判断栈是否为空
        size    栈里面有多少个元素
        push    入栈
        pop     出栈
        clear   清空这个栈
        destory 销魂这个栈

    我们可以使用链式结构或者顺序结构来实现这个栈
        1 链式 --- 利用链表,对链表的操作进行限定
            struct stacknode
            {
                int data;
                struct stacknode * prev;
            };

            //利用头节点来搞定stacknode的管理  对于用户来说是最友好的
            struct ListStack
            {
                struct stacknode * top;//指向栈顶元素的

                int num;
                //为了防止爆栈(溢出)  我们可以弄一个最大值来进行限定
                int maxnum;
                .....
            };

        2 顺序 --- 利用数组,对数组的操作进行限定
            struct ArrayStack //同样是为了管理我们的栈的
            {
                //int stack[];//容纳所有的栈里面的元素
                int * stack;//我给你开辟一个数组出来让stack去保存
                int  top;//指向栈顶元素的

                int num;
                //为了防止爆栈(溢出)  我们可以弄一个最大值来进行限定
                int maxnum;
                .....
            };


先弄一遍链式栈,请实现顺序栈



    队列:是限定在表尾进行插入,在表头删除操作的线性表
        实现是一回事,但是必须要满足队列的基本特点
    它的设计思路是:先进先出,后进后出
        有两头:队头(front),删除操作在这一边进行
                队尾(rear),插入操作在这一边进行
队列在实现的时候有两种
    1 链式队列 --- 链表实现 -> 不存在假溢出
            struct queuenode
            {
                int data;
                struct queuenode * next;//做尾插
            };

            //利用头节点来搞定queuenode的管理  对于用户来说是最友好的
            struct ListQueue
            {
                struct stacknode * front;//指向队头元素的 删除的时候砍掉这个头
                struct stacknode * rear;//指向队尾元素的  插入的时候往rear的后面进行插入
                int num;//队列里面有多少个元素
                //为了防止爆队(溢出)  我们可以弄一个最大值来进行限定
                int maxnum;
                .....
            };

    2 顺序队列 --- 利用数组来实现
        根据队列的特点我们可以知道
            入队出队front rear都是在++
            总有一个时候队列没有满,但是入队的时候已经溢出了 -- 假溢出
            因此我们设计顺序队列一定要设计为循环队列
            让前面已经出队的地方可以继续容纳新的元素
        设计循环队列有几种思路
            1 用num来表示我们的循环队列里面有多少个元素
                只要num没有达到它的最大容纳上限我就可以继续入队
                只是rear跑到最后去了之后,我们需要让它从头开始

            2 我们可以利用front 和 rear来进行元素个数,是否为空,是否满的判断
                -> 没有变量num来对我们的元素个数来进行判断 ---- 这种是常用的
                根据我们的分析可以知道 
                    当front == rear的时候没有办法判断这个队列是空的还满的
                    因此循环队列设计的时候,我们实际队列容纳个数要比最大的容纳个数少一个
                    maxnum == 5,实际队列容纳就是 5 - 1
                公式:
                    队空的判断:front == rear
                    队满的判断:(rear + 1) % maxnum == front
                    队列的元素个数:(rear - front + maxnum) % maxnum
        
            struct ArrayQueue //同样是为了管理我们的队列的
            {
                //int queue[];//容纳所有的队列里面的元素
                int * queue;//我给你开辟一个数组出来让queue去保存
                int  front;//指向对头元素的 指向要删除的数据
                int rear;//指向队尾元素 指向要插入的数据
                //为了防止爆队(溢出)  我们可以弄一个最大值来进行限定
                int maxnum; // 实际队列容纳个数为 maxnum - 1
            };
    队列需要实现如下操作
            init        初始化这个队列
            front       返回队头元素,但是不出队
            empty       判断是否为空
            full        判断是否为满
            size        返回元素个数
            push(inqueue)        入队
            pop(outqueue)         出队
            clear       清空这个队列
            destory     销毁这个队列

搞定循环队列,然后将链式队列写出来


栈最基本的应用就是算表达式的值
    2+3*5-6*7+8*9-10%3=
    你输入2+3*5-6*7+8*9-10%3=这个字符串
            简单一点就用scanf(%s) -> 中间就不能有空格
        回车就会得到它的结果
        gets -> 从终端获取一行字符串
        不想要警告,请使用fgets

    链式栈

.h与.c

#ifndef __LISTSTACK_H__
#define __LISTSTACK_H__


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef int LS_DataType;
#define LS_ERRORVALUE (LS_DataType)(1 << 31)//栈的错误值


//节点
typedef struct LS_Node
{
    LS_DataType _data;//栈的数据
    struct LS_Node * _next;//写next就用头插
}LS_Node;

//管理栈的头节点
typedef struct
{
    LS_Node * _top;//栈顶  插入删除访问都这一端
    int _num;//现在栈里面有多少个元素
    int _maxnum;//最大的容纳个数
}ListStack;


//init    初始化这个栈
//maxnum:程序员限定的最大元素个数   如果小于等于0   默认10000000
ListStack * ListStack_init(int maxnum);


//top     返回栈顶元素,但是不出栈
//返回LS_ERRORVALUE表示失败
LS_DataType ListStack_top(ListStack * st);

//empty   判断栈是否为空
bool ListStack_empty(ListStack * st);

//full    判断是不是满了
bool ListStack_full(ListStack * st);

//size    栈里面有多少个元素
int ListStack_size(ListStack * st);

//push    入栈  失败返回false
bool ListStack_push(ListStack * st,const LS_DataType data);

//pop     出栈 没有返回元素  失败返回false
//如果你有需求返回元素也是可以的
//如果你要得到出栈元素 你需要先top再pop
bool ListStack_pop(ListStack * st);

//clear   清空这个栈
//callback是否要处理数据,传NULL为不处理
void ListStack_clear(ListStack * st,void (*callback)(const LS_DataType));

//destory 销魂这个栈
//callback是否要处理数据,传NULL为不处理
void ListStack_destory(ListStack ** st,void (*callback)(const LS_DataType));





#endif

#include "ListStack.h"


//创建栈的节点  这个接口是不需要给用户用的
static LS_Node * LS_Node_create(const LS_DataType data)
{
    LS_Node * ptr = (LS_Node *)calloc(1,sizeof(LS_Node));
    ptr ->_data = data;
    return ptr;
}

//init    初始化这个栈
//maxnum:程序员限定的最大元素个数   如果小于等于0   默认10000000
ListStack * ListStack_init(int maxnum)
{
    if(maxnum <= 0)
    {
        maxnum = 10000000;
    }
    ListStack * st = (ListStack *)calloc(1,sizeof(ListStack));
    st ->_maxnum = maxnum;
    return st;
}


//top     返回栈顶元素,但是不出栈
//返回LS_ERRORVALUE表示失败
LS_DataType ListStack_top(ListStack * st)
{
    if(ListStack_empty(st))//栈是空的 返回不了一点
        return LS_ERRORVALUE;
        
    return st ->_top ->_data;
}


//empty   判断栈是否为空
bool ListStack_empty(ListStack * st)
{
    if(!st)
        return true;
    return st ->_num == 0;
}
//full    判断是不是满了
bool ListStack_full(ListStack * st)
{
    if(!st)
        return true;
    return st ->_num == st ->_maxnum;
}
//size    栈里面有多少个元素
int ListStack_size(ListStack * st)
{
    return !st ? 0 : st ->_num;
}



//push    入栈  失败返回false
bool ListStack_push(ListStack * st,const LS_DataType data)
{
    //入栈就是一个头插
    if(!st || ListStack_full(st))
        return false;
    //先弄一个节点
    LS_Node * ptr = LS_Node_create(data);
    //对这个节点进行头插
    ptr ->_next = st ->_top;
    st ->_top = ptr;//将栈顶弄到新加入的节点上面来
    st ->_num++;
    return true;
}

//pop     出栈 没有返回元素  失败返回false
//如果你有需求返回元素也是可以的
//如果你要得到出栈元素 你需要先top再pop
bool ListStack_pop(ListStack * st)
{
    if(!st || ListStack_empty(st))
        return false;
 
    //将top给删除
    LS_Node * ptr = st ->_top;//标记要删除的节点
    st ->_top = st ->_top ->_next;//top到后面去了
    st ->_num--;//数量少一个了
    ptr ->_next = NULL;//孤立这个节点
    free(ptr);
    return true;
}


//clear   清空这个栈
//callback是否要处理数据,传NULL为不处理
void ListStack_clear(ListStack * st,void (*callback)(const LS_DataType))
{
    while(!ListStack_empty(st))//只要你的栈不是空的 就一直出栈
    {
        LS_DataType data = ListStack_top(st);//获取栈顶元素

        ListStack_pop(st);
        if(callback && LS_ERRORVALUE != data)
        {
            callback(data);
        }
    }
}
//destory 销魂这个栈
//callback是否要处理数据,传NULL为不处理
void ListStack_destory(ListStack ** st,void (*callback)(const LS_DataType))
{
    if(!st)
        return;
    ListStack_clear(*st,callback);//先清空
    //将头节点给删除
    free(*st);
    *st = NULL;
}

顺序栈:

.h与.c

#ifndef __ARRAYSTACK_H__
#define __ARRAYSTACK_H__

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>

typedef int AS_DataType;
#define AS_ERRORVALUE (AS_DataType)(1 << 31)//栈的错误值

typedef struct  //同样是为了管理我们的栈的
{
    AS_DataType * _st_arr;//我给你开辟一个数组出来让_st_arr去保存数据
    int  _top;//指向栈顶元素的  下标 入栈从_top开始,栈顶元素为_top-1
    int _num;
    //为了防止爆栈(溢出)  我们可以弄一个最大值来进行限定
    int _maxnum;
}ArrayStack;



//init    初始化这个栈
//maxnum:程序员限定的最大元素个数   如果小于等于0   默认10000000
ArrayStack * ArrayStack_init(int maxnum);


//top     返回栈顶元素,但是不出栈
//返回LS_ERRORVALUE表示失败
AS_DataType ArrayStack_top(ArrayStack * st);

//empty   判断栈是否为空
bool ArrayStack_empty(ArrayStack * st);

//full    判断是不是满了
bool ArrayStack_full(ArrayStack * st);

//size    栈里面有多少个元素
int ArrayStack_size(ArrayStack * st);

//push    入栈  失败返回false
bool ArrayStack_push(ArrayStack * st,const AS_DataType data);

//pop     出栈 没有返回元素  失败返回false
//如果你有需求返回元素也是可以的
//如果你要得到出栈元素 你需要先top再pop
bool ArrayStack_pop(ArrayStack * st);

//clear   清空这个栈
//callback是否要处理数据,传NULL为不处理
void ArrayStack_clear(ArrayStack * st,void (*callback)(const AS_DataType));

//destory 销魂这个栈
//callback是否要处理数据,传NULL为不处理
void ArrayStack_destory(ArrayStack ** st,void (*callback)(const AS_DataType));









#endif

#include "ArrayStack.h"


//init    初始化这个栈
//maxnum:程序员限定的最大元素个数   如果小于等于0   默认10000000
//入栈从_top开始,栈顶元素为_top-1
ArrayStack * ArrayStack_init(int maxnum)
{
    if(maxnum <= 0) {
        printf("动动你的猪脑,0和负数能存东西吗,给你开了10000000,慢慢填吧\n");
        maxnum = 10000000;
    }

    ArrayStack *st = (ArrayStack *)calloc(1,sizeof(ArrayStack));
    st ->_maxnum = maxnum;
    //开辟数组  用于保存数据
    st ->_st_arr = (AS_DataType *)calloc(st ->_maxnum,sizeof(AS_DataType));
    return st;
}


//top     返回栈顶元素,但是不出栈
//返回LS_ERRORVALUE表示失败
AS_DataType ArrayStack_top(ArrayStack * st)
{
    if (ArrayStack_empty(st)) {
        return AS_ERRORVALUE;
    }
    return st ->_st_arr[st ->_top - 1];
}

//empty   判断栈是否为空
bool ArrayStack_empty(ArrayStack * st)
{
    if (!st || st ->_num == 0) {
        return true;
    }
    return false;
}

//full    判断是不是满了
bool ArrayStack_full(ArrayStack * st)
{
    if (!st || st ->_num == st ->_maxnum) {
        return true;
    }
    return false;
}

//size    栈里面有多少个元素
int ArrayStack_size(ArrayStack * st)
{
    if (!st) {
        return AS_ERRORVALUE;
    }
    return st ->_num;
}

//push    入栈  失败返回false
bool ArrayStack_push(ArrayStack * st,const AS_DataType data)
{
    if (!st || ArrayStack_full(st)) {
        return false;
    }
    st ->_st_arr[st ->_top] = data;
    st ->_top++;
    st ->_num++;
    return true;
}

//pop     出栈 没有返回元素  失败返回false
//如果你有需求返回元素也是可以的
//如果你要得到出栈元素 你需要先top再pop
bool ArrayStack_pop(ArrayStack * st)
{
    if (ArrayStack_empty(st)) {
        return false;
    }
    st ->_top--;
    st ->_num--;
    return true;
}

//clear   清空这个栈
//callback是否要处理数据,传NULL为不处理
void ArrayStack_clear(ArrayStack * st,void (*callback)(const AS_DataType))
{
    while (!ArrayStack_empty(st)) {
        ArrayStack_pop(st);
    }
}

//destory 销魂这个栈
//callback是否要处理数据,传NULL为不处理
void ArrayStack_destory(ArrayStack ** st,void (*callback)(const AS_DataType))
{
    free((*st) ->_st_arr);
    free(*st);
    *st =NULL;

}

网站公告

今日签到

点亮在社区的每一天
去签到