2024.11.23 这里是大一的我。 自己目前还不是很能理解栈和队列的相关知识,只是简单的做一下竞赛课程的笔记。
不是很了解,所以我就先把我目前学到的东西记录下来,以后再慢慢补充。
我们在以后的数据结构再见吧!

由于老师上课的速度很快,所以难免笔记会有疏漏,并且代码大部分由Marscode生成。 如果你发现有什么问题或者有什么建议,欢迎在评论区留言。

Btw,如果你觉的这篇文章对你有帮助,不妨点个赞吧⬇️


栈(stack)

定义

线性表是具有相同数据结构的n个元素的有限序列

栈是只允许一段进行插入或删除操作的线性表

相关术语 栈顶:允许插入和删除的一段 栈底:不允许操作的一段 空栈:无元素

特点:先进后出

基本操作

线性表

  • 初始化 构造一个空的线性表,分配内存空间
  • 销毁 释放线性表所占用的内存空间
  • 插入 在指定位置插入元素
  • 删除 删除指定位置的元素,并返回值
  • 按值查找 查找具有给定关键字值的元素
  • 按位查找

  • 初始化
  • 销毁
  • 进栈 Push(&s, x)
  • 出栈 Pull(&s, &x)
  • 查 获取栈顶元素

顺序栈的实现

定义

//Powered By Marscode
#define MAXSIZE 10
typedef struct{
    ElemType data[MAXSIZE];
    int top;//栈顶指针,指向栈顶元素
}SqStack;

//使用
void testStack(){
    SqStack Q;
    //.......
}

void Init(SqStack &s){
    s.top = -1;
}// 初始化

bool Push(SqStack &s, ElemType &x){
    if(s.top == MAXSIZE - 1){
        return false;
    }//栈满,报错

    s.data[++s.top] = x;//指针先加1,再入栈
    return true;
}// 入栈

bool Pop(SqStack &s, ElemType &x){
    if(s.top == -1){
        return false;
    }//栈空,报错
    //考虑算法的时候要首先考虑异常情况

    x = s.data[s.top--];//先出栈,指针再减1
    //只需要逻辑上的出栈,无需真的删除元素
    //函数运行结束之后会自动释放内存空间
    return true;
}// 出栈

bool GetTop(SqStack &s, ElemType &x){
    if(s.top == -1){
        return false;
    }//栈空,报错

    x = s.data[s.top];
    return true;
}// 取栈顶元素

bool StackEmpty(SqStack &s){
    if(s.top == -1){
        return true;
    }else{
        return false;
    }
}// 判断栈是否为空

栈的链式存储

//链栈的结点结构、栈类型定义
typedef struct StackNode{
    ElemType data;
    struct StackNode *next;
}StackNode, *LinkStack;

例题1

题目描述: 给定一个长度为N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出-1。 输入格式: 第一行包含整数N,表示数列长度。 第二行包含N个整数,表示整数数列。 输出格式: 共一行,包含N个整数,其中第i个数表示第i个数的左边第一个比它小的数,如果不存在则输出-1。 输入样例: 5 3 4 2 7 5 输出样例: -1 3 -1 2 2

思路:

  • 从前往后遍历数组
  • 用栈维护一个单调递增的序列
  • 如果栈顶元素大于当前元素,则弹出栈顶元素,直到栈顶元素小于当前元素或者栈为空
  • 如果栈为空,则当前元素左边没有比它小的元素,输出-1
  • 如果栈不为空,则栈顶元素就是当前元素左边第一个比它小的元素,输出栈顶元素
  • 将当前元素入栈
// Powered By Marscode
//参考代码
#include <stdio.h>
#define MAXN 1000010
int n, top, stk[MAXN]; // 定义变量 n 表示数列长度,top 表示栈顶指针,stk 数组用于存储栈中的元素
int main(){
    scanf("%d", &n); // 读入数列长度
    for(int i = 0; i < n; i++){
        int x;
        scanf("%d", &x); // 读入当前数
        while(top && stk[top] >= x){ // 如果栈顶元素大于等于当前数,弹出栈顶元素
            top--;
        }
        if(top){ // 如果栈不为空
            printf("%d ", stk[top]); // 输出栈顶元素,即当前数左边第一个比它小的数
        }else{
            printf("-1 "); // 如果栈为空,输出 -1
        }
        stk[++top] = x; // 将当前数入栈
    }
    return 0;
}

例题2

题目描述: 斐波那契数(通常用F(n)表示)形成的序列称为斐波那契数列,该数列由0和1开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中n > 1 给定一个整数n,请计算F(n)。

思路:

如果我们不使用递归的方式,直接使用栈,那又该如何求解呢?

思路非常的简单。比如说我们求F(4),我们需要一个栈来存储F(1)和F(2)。然后我们依次取出栈顶元素,计算F(3),然后将F(3)入栈。以此类推,直到我们计算出F(4)为止。

// Powered By Marscode
// 参考代码
#include <stdio.h>
#define MAXN 1000010
int n, top, stk[MAXN]; // 定义变量 n 表示数列长度,top 表示栈顶指针,stk 数组用于存储栈中的元素
int main(){
    scanf("%d", &n); // 读入数列长度
    if (n <= 0){
        printf("0\n"); // 如果 n <= 0,输出 0
    }
    if (n == 1 || n == 2){
        printf("1\n"); // 如果 n == 1,输出 1
    }
    top = 0; // 初始化栈顶指针
    stk[++top] = 1; // 将 F(1) 入栈
    stk[++top] = 1; // 将 F(2) 入栈
    for(int i = 3; i <= n; i++){ // 从 F(3) 开始计算
        int a = stk[top - 1]; // 取出栈顶元素
        int b = stk[top]; // 取出栈顶元素
        stk[++top] = a + b; // 将 F(i) 入栈
    }
    printf("%d\n", stk[top]); // 输出栈顶元素,即 F(n)
    return 0;
}

例题3

题目描述: 在编程当中,我们经常需要处理括号匹配的问题。例如,在编写一个编译器的时候,我们需要检查括号是否匹配。括号匹配指的是,对于一个给定的括号序列,其中的括号必须是成对出现的,并且每个右括号都必须与其对应的左括号匹配。 样例输入: {([])} 样例输出: YES

思路

如果字符是左括号,则入栈;如果字符是右括号,则出栈。如果出栈的字符不是对应的左括号,则不匹配。如果栈为空,则匹配。

// Powered By Marscode
// 参考代码
#include <stdio.h>
#include <string.h>
#define MAXN 1000010
int n, top, stk[MAXN]; // 定义变量 n 表示数列长度,top 表示栈顶指针,stk 数组用于存储栈中的元素
int main(){
    char s[MAXN]; // 定义字符串 s
    scanf("%s", s); // 读入字符串
    n = strlen(s); // 计算字符串长度
    top = 0; // 初始化栈顶指针
    for(int i = 0; i < n; i++){ // 遍历字符串
        if(s[i] == '(' || s[i] == '[' || s[i] == '{'){ // 如果是左括号
            stk[++top] = s[i]; // 将左括号入栈
        }else{ // 如果是右括号
            if(top == 0){ // 如果栈为空
                printf("NO\n"); // 输出 NO
                return 0; // 结束程序
            }
            char c = stk[top--]; // 取出栈顶元素
            if(s[i] == ')' && c!= '('){ // 如果右括号和左括号不匹配
                printf("NO\n"); // 输出 NO
                return 0; // 结束程序
            }
            if(s[i] == ']' && c!= '['){ // 如果右括号和左括号不匹配
                printf("NO\n"); // 输出 NO
                return 0; // 结束程序
            }
            if(s[i] == '}' && c!= '{'){ // 如果右括号和左括号不匹配
                printf("NO\n"); // 输出 NO
                return 0; // 结束程序
            }
        }
    }
    if(top == 0){ // 如果栈为空
        printf("YES\n"); // 输出 YES
    }else{ // 如果栈不为空
        printf("NO\n"); // 输出 NO
    }
    return 0;
}