栈和队列及应用

栈和队列

栈:限定仅在栈顶进行插入和删除操作的线性表

队列:只允许在一端进行插入操作,而在另一端进行删除操作的线性表

一、栈

1.栈的定义

栈(stack):限定仅在栈顶进行插入和删除操作的线性表

允许插入和删除的一端称为栈顶(top),另一端称为栈底,不含任何数据元素的栈叫空栈

栈又被称为:后进先出的线性表,简称LIFO结构

栈的插入操作:进栈,压栈,入栈

栈的删除操作:出栈,弹栈

使用:如果栈的使用过程中元素变化不可预料,有时很大,有时很小,一般会用链式栈。

如果元素变化在可控范围内,一般使用顺序栈

2.栈的应用

要使用好栈先进后出的特性

递归

定义:把一个直接调用自己或者通过一系列的调用语句间接地调用自己的函数,叫做递归函数

注意:每个递归定义必须至少有一个,满足这个条件时,递归不在进行,即不在引用自身而是返回值出去

优点:能使程序的结构更清晰,简洁,更容易让人理解

缺点:大量的递归调用会建立函数的副本,会耗费大量的时间和内存

用栈来实现递归操作:

在递归前行阶段,对于每一层递归,函数的局部变量,参数值,以及返回地址都被压入栈中。在退回阶段,位于栈顶的局部变量,参数和返回地址被弹出,用于返回调用层次中执行代码的其余部分,也就是恢复了调用的状态。

四则运算表达式求值

后缀(逆波兰)表示法:一种不需要括号的后缀表示法

中缀表达式-》后缀表达式

转换规则:从左到右遍历表达式的每个数字和符号,遇到是数字就输出(成为后缀表达式的一部分),遇到是符号,需要判断其与栈顶符号的优先级,如果是右括号或者优先级不高于栈顶符号,则栈顶元素依次出栈并输出,并将当前符号进栈。

正常数学表达式:
    20-2*(5+3)+6/3;
后缀表达式:
    20 2 5 3 + * - 6 3 / +

后缀表达式计算方法:从左到右遍历表达式的每一个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶的两个数字出栈,进行运算,运算结果进栈。

3.顺序栈

#include<stdio.h>
#include<stdlib.h>
​
//栈的最大容量
#define maxSize 100
//顺序栈结构
typedef struct stack
{
    int* data;//存储栈的元素
    int top;//栈顶指针
}stack;
​
//初始化栈
stack initStack()
{
    //定义一个结构体
    stack s;
    //申请内存空间
    s.data = (int*)malloc(sizeof(int)*maxSize);
    //判断是否申请成功
    if (!s.data)
    {
        printf("malloc memory failed!\n");
        //异常退出
        exit(0);
    }
    //从0开始
    s.top = 0;
    return s;
}
​
//入栈
void push(stack *s,int key)
{
    //判断是否栈满
    if (s->top == maxSize)
    {
        printf("stack is full!\n");
        return;
    }
    else
    {
        s->data[s->top] = key;
        s->top++;
    }
}
​
//出栈
void pop(stack *s)
{
    //判断栈是否为空
    if (s->top == 0)
    {
        printf("this is a empty stack!\n");
        return;
    }
    else
    {
        s->top--;
    }
}
​
//打印栈中的元素
void print(stack* s)
{
    int i = 1;
    int count = s->top;
    while (count != 0)
    {
        printf("第 %d 个元素是:%d\n", i, s->data[--count]);
        i++;
    }
}

4.链式栈

#include<stdio.h>
#include<stdlib.h>
​
//链式栈结构
typedef struct stackNode
{
    int data;//数据域
    struct stackNode* next;//指针域
}stackNode;
​
typedef struct linkStack
{
    stackNode* top;//栈顶指针-和链表的头指针合并了
    int size;//栈里有多少个元素
}linkStack;
​
​
//初始化
linkStack init_LinkStack()
{
    linkStack s;
    s.size = 0;
    s.top = NULL;
    return s;
}
​
//入栈-使用头插法
void push(linkStack* s,int key)
{
    //申请一个节点
    stackNode* new_node = (stackNode*)malloc(sizeof(stackNode));
    if (!new_node)
    {
        printf("malloc memory failed!\n");
        exit(0);
    }
    //添加元素
    new_node->data = key;
    //让原来的首元结点变成第二个结点
    new_node->next = s->top;
    //移动栈顶指针
    s->top = new_node;
    //元素个数加1
    s->size++;
}
​
//出栈
void pop(linkStack* s)
{
    //临时结点,用来释放出栈节点
    stackNode* free_node;
    free_node = s->top;
    //移动top指针
    s->top = s->top->next;
    //释放节点
    free(free_node);
    //元素个数-1
    s->size--;
}
​
//打印
void print(linkStack* s)
{
    printf("栈中有 %d 个元素!\n", s->size);
    if (s->size)
    {
        //计数器
        int count = 1;
        //临时指针,用来遍历栈
        stackNode* pcurrent;
        pcurrent = s->top;
        while (pcurrent)
        {
            printf("第 %d 个元素是:%d\n", count, pcurrent->data);
            count++;
            pcurrent = pcurrent->next;
​
        }
    }
}

二、队列

缓存淘汰机制-先进先出,后进后出

1.队列的定义

队列(queue):是一种只允许进行插入操作,而在另一端进行删除操作的线性表

允许插入的一端叫:队尾

允许删除的一端叫:队头

队列是一种先进先出的线性表,简称FIFO

2.顺序队列

一般顺序队列是使用的循环队列,可以防止假溢出,和有效利用内存空间

循环队列:头尾相接的循顺序存储结构

#include<stdio.h>
#include<stdlib.h>
​
//队列大小
#define maxSize 100
//队列结构
typedef struct queue
{
    int* data;//存放数据
    int front;//头指针
    int rear;//尾指针
}queue;
​
//初始化队列
queue init_queue()
{
    queue q;
    q.data = (int*)malloc(sizeof(int)*maxSize);
    if (!q.data)
    {
        printf("malloc memory failed!\n");
        exit(0);
    }
    q.front = 0;
    q.rear = 0;
    return q;
}
​
//入队-队尾入队
void enQueue(queue* q,int key)
{
    //判断队列是否已满
    if ((q->rear + 1) % maxSize == q->front)
    {
        printf("queue is full!\n");
        return;
    }
    //加入数据
    q->data[q->rear] = key;
    //尾指针后移一位
    q->rear = (q->rear + 1) % maxSize;
}
​
//出队-队头出队
void deQueue(queue* q)
{
    //判断队列是否为空
    if (q->front == q->rear)
    {
        printf("queue is empty!\n");
        return;
    }
    //移动队头指针
    q->front = (q->front + 1) % maxSize;
}
​
//打印
void print(queue q)
{
    //计数器
    int count = 1;
    int front = q.front;
    int rear = q.rear;
    while (front != rear)
    {
        printf("第 %d 个元素是 %d \n", count, q.data[front]);
        count++;
        front = (front + 1) % maxSize;
    }
}
​

3.链式队列

#include<stdio.h>
#include<stdlib.h>
​
//队列结构
typedef struct queueNode
{
    int data;//数据域
    struct queueNode* next;//指针域
}queueNode;
​
typedef struct linkQueue
{
    queueNode* front;//头指针
    queueNode* rear;//尾指针
    int size;//元素个数
}linkQueue;
​
//入队从链表尾部,出队从链表头部
​
//初始化
linkQueue init_linkQueue()
{
    linkQueue q;
    q.rear = (queueNode*)malloc(sizeof(queueNode));
    if (q.rear == NULL)
    {
        printf("malloc memory failed!\n");
        exit(0);
    }
    q.front = q.rear;
    q.front->next = NULL;
    q.size = 0;
    return q;
}
​
//入队-尾插法
void enQueue(linkQueue* q, int key)
{
    //申请队列节点
    queueNode* new_node = (queueNode*)malloc(sizeof(queueNode));
    if (!new_node)
    {
        printf("malloc memory failed!\n");
        exit(1);
    }
    //加入元素
    new_node->data = key;
    new_node->next = NULL;
    //将新节点设置为最后一个节点
    q->rear->next = new_node;
    //移动尾指针
    q->rear = new_node;
    //元素个数+1
    q->size++;
}
​
//出队-链表头部出队
void deQueue(linkQueue* q)
{
    //判断队列是否为空
    if (q->front == q->rear)
    {
        printf("queue is empty!\n");
        exit(1);
    }
​
    //待删除节点
    queueNode* free_node;
    free_node = q->front->next;
​
    //移动头指针
    q->front = q->front->next->next;
    free(free_node);
    //元素个数-1
    q->size--;
}
​
//打印
void print(linkQueue q)
{
    printf("一共有 %d 个元素\n", q.size);
    //计数器
    int count = 1;
    //当队列不为空的时候
    if(q.front != q.rear)
    {
        //临时指针,用来遍历链表
        queueNode* temp = q.front->next;
        while (temp)
        {
            printf("第 %d 个元素是:%d\n", count, temp->data);
            count++;
            temp = temp->next;
​
        }
    }
}
​

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
栈和队列是两种常见的数据结构,它们都是线性结构,可以用于许多实际的应用场景。 首先,我们来讲解一下是一种后进先出(Last In First Out,LIFO)的数据结构,它的主要操作包括入和出。入指将元素添加到顶,出指从顶弹出一个元素。可以用数组或链表来实现。 应用场景非常广泛,例如: 1. 括号匹配:在编译器中,可以使用来判断代码中括号的匹配情况。 2. 系统调用:操作系统使用来存储进程调用时的参数和返回值。 3. 表达式求值:在计算机科学中,可以使用来实现中缀表达式到后缀表达式的转换,以及后缀表达式的计算。 接下来,我们来讲解一下队列队列是一种先进先出(First In First Out,FIFO)的数据结构,它的主要操作包括入队和出队。入队指将元素添加到队尾,出队指从队头弹出一个元素。队列可以用数组或链表来实现。 队列应用场景也非常广泛,例如: 1. 线程池:在多线程编程中,可以使用队列来实现任务的调度和执行,以避免线程频繁的创建和销毁。 2. 缓存:在网络编程中,可以使用队列来实现消息的缓存和转发,以提高系统的性能。 3. BFS算法:在图论中,可以使用队列来实现广度优先搜索(BFS)算法,以求解最短路径等问题。 总的来说,栈和队列是两种基本的数据结构,它们都有着广泛的应用场景。在实际开发中,根据需要选择合适的数据结构来实现功能,可以有效地提高程序的效率和可读性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值