第3章栈和队列

树深度遍历、深度优先搜索(图算法基础)
队列树层序遍历,广度优先搜索(图算法基础)
单调栈临近最大最小值
单调队列区间最大最小值

第三章栈和队列

请添加图片描述

队列:先进先出

size head tail

出队:头指针后移一位 head+1 pop

入队:尾指针 元素放进去之后tail+1 push

循环队列:当tail==size的时候,tail=0,解决假溢出问题

再加一个count:表明数据元素个数,

当tail==size且count!=size的时候,tail=0,然后count+=1

//
// Created by cry on 2024/3/12.
//
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//TODO 封装顺序表
typedef struct vector{
    int *data;
    int size;
}vector;
vector *initVector(int n){
    vector *v=(vector *) malloc(sizeof(vector));
    v->size=n;
    v->data=(int *) malloc(sizeof(int)*n);
    return v;
}
void clearVector(vector *v){
    if(v==NULL) return;
    free(v->data);
    free(v);
}
int insertVector(vector *v,int pos,int val){
//    将某个位置的值改写为val
    if (pos < 0 or pos >= v->size){return 0;}
    v->data[pos]=val;
    return 1;
}
void vectorSeek(vector *v,int pos,int &res){
    if(pos <0 or pos >= v->size){res=-1;}
    res= v->data[pos];
}
//TODO 封装队列
typedef struct acm_1_3_duilie_Queue{
    //数据存储区
    vector *data;
    int size,tail,head,count;
}acm_1_3_duilie_Queue;
//初始化队列
acm_1_3_duilie_Queue *acm_1_3_duilie_initQueue(int n){
    acm_1_3_duilie_Queue *q=(acm_1_3_duilie_Queue *) malloc(sizeof(acm_1_3_duilie_Queue));
    q->data=initVector(n);
    q->size=n;
    q->head=q->tail=q->count=0;
    return q;
}
//清除队列
void acm_1_3_duilie_clearQueue(acm_1_3_duilie_Queue *q){
    if(q==NULL) return;
    //先cleardata,然后回收本身
    clearVector(q->data);
    free(q);
    return;
}
//push
int acm_1_3_duilie_push(acm_1_3_duilie_Queue *q,int val){
    if(q->count==q->size){
        return 0;
    } //没满
    //将val放入队列
    insertVector(q->data,q->tail,val);
    q->count+=1;
    q->tail+=1;
    if(q->tail==q->size){
        q->tail=0;
    }
    return 1;
}
//pop
int acm_1_3_duilie_pop(acm_1_3_duilie_Queue *q){
    if(q->count==0)return 0;
    q->head+=1; //出队只需要头指针向后移动一个就行
    q->count-=1;
    return 1;


}
//查看队首
int acm_1_3_duiliefront(acm_1_3_duilie_Queue *q){
    int res=0;
    vectorSeek(q->data,q->head,res);
    return res;
}
//判空
int acm_1_3_duilieempty(acm_1_3_duilie_Queue *q){
    return q->count==0;
}
void acm_1_3_duilieo_outputQueue(acm_1_3_duilie_Queue *q){
    printf("Queue:\n");
    for(int i=0;i<q->count;i++){
        int res=0;
        vectorSeek(q->data,(q->head)+i %(q->size),res);
        printf("%4d ",res);
    }
    printf("\n");
}
void acm_1_3_duilie_test(){
    srand(time(0));
#define MAX_OP 10
    acm_1_3_duilie_Queue *q= acm_1_3_duilie_initQueue(5);
    acm_1_3_duilieo_outputQueue(q);
    for(int i=0;i<MAX_OP;i++){
        int op=rand() %5,val=rand()%100; // 0 1:pop ,2,3,4:push
        switch(op){
            case 0:
            case 1:
                printf("front of queue:%d\n",acm_1_3_duiliefront(q));
                acm_1_3_duilie_pop(q);
                break;
            case 2:
            case 3:
            case 4:
                printf("push %d to queue \n",val);
                acm_1_3_duilie_push(q,val);
                break;
        }
        acm_1_3_duilieo_outputQueue(q);
    }
    acm_1_3_duilie_clearQueue(q);
}

队列链表

//
// Created by cry on 2024/3/12.
//
//链表模式的队列queue
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//TODO 链表定义
typedef struct Node{
    int data;
    Node *next;
}Node;
typedef struct LinkList{
    Node head,*tail; //头结点,不存数据 -> 有头链表
}LinkList;
LinkList *initLinkList(){
    LinkList *l=(LinkList *) malloc(sizeof(LinkList));
    l->head.next=NULL;
    l->tail=&(l->head);
    return l;
}
Node *getNewNode(int val){
    Node *p=(Node *) malloc(sizeof(Node));
    p->data=val;
    p->next=NULL;
    return p;
}
void clearLinkList(LinkList *l){
    Node *p=l->head.next,*q;
    while (p){
        q=p->next; //跑到下一个
        free(p); //删除上一个
        p=q; //回到下一个,完成
        //释放一连串
    }
    free(l);
    return ;
}
int frontLinkList(LinkList *l){
    if(l->head.next==NULL){return 0;} //空链表
    return l->head.next->data;
}
int insertTail(LinkList *l,int val){
    //尾部添加节点
    Node *node=getNewNode(val); //将val封装成节点
    l->tail->next=node;
    //改变tail指向
    l->tail=node;
    return 1;

}
int emptyList(LinkList *l){
    return l->head.next==NULL;
}
//清除第一个节点
int eraseHead(LinkList *l){
    if(emptyList(l))return 0;
    Node *p=l->head.next; //待删除节点
    l->head.next=l->head.next->next; //重新指向
    if(p==l->tail) l->tail=&(l->head);
    free(p);

}

typedef struct Queue{
    LinkList *l;
    int count; //链表就不需要循环队列了,不需要头尾指针了
    //count用于判断队列是否为空
}Queue;
// TODO 队列链表初始化
Queue *initQueue(){
    Queue *q=(Queue *)malloc(sizeof(Queue));
    q->l=initLinkList();//初始化队列链表
    q->count=0;
    return q;
}

//TODO 是否为空
int empty(Queue *q){
    return q->count==0;
}
//TODO 查看队首元素
int front(Queue *q){
    if(empty(q)) return 0;
    return frontLinkList(q->l); //返回链表第一个存储的数据
}
//TODO 销毁
void clearQueue(Queue *q){
    if(q==NULL) return;
    clearLinkList(q->l);
    free(q);
    return ;
}
//TODO 队列链表入队
int push(Queue *q,int val){
    q->count+=1;
    return insertTail(q->l,val);
}
//TODO 队列链表出队
int pop(Queue *q){
    q->count-=1;
    return eraseHead(q->l);
}
void outputQueue(Queue *q){
    printf("Queue:\n");
    Node *p=q->l->head.next;
    for(int i=0;i<q->count;i++,p=p->next){
        printf("%4d ",p->data);
    }
    printf("\n");
    return ;
}
void acm_1_3_duilie_lianbiao_test(){
    srand(time(0));
#define MAX_OP 10
    Queue *q= initQueue();
    for(int i=0;i<MAX_OP;i++){
        int op=rand() %5,val=rand()%100; // 0 1:pop ,2,3,4:push
        switch(op){
            case 0:
            case 1:
                printf("front of queue:%d\n",front(q));
                pop(q);
                break;
            case 2:
            case 3:
            case 4:
                printf("push %d to queue \n",val);
                push(q,val);
                break;
        }
        outputQueue(q);
    }
}

栈 先进后出 FILO

有一个size和top

栈可以处理具有完全包含关系的问题

//
// Created by cry on 2024/3/13.
//
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//数组实现栈
typedef struct Stack{
    int *data;
    int size,top;
}Stack;
Stack *initStack(int n){
    Stack *s=(Stack *) malloc(sizeof(Stack));
    s->data=(int *) malloc(sizeof(int)*n);
    s->size=n;
//    top指向的永远是栈顶元素

}
void clearStack(Stack *s){
    if(s==NULL) return ;
    free(s->data);
    free(s);
}
//TODO 栈基本操作,判空 查看栈顶元素 入栈 出栈
int empty(Stack *s){
    return s->top==-1;

}
int top(Stack *s){
    if(empty(s))return 0;
    return s->data[s->top];
}
int push(Stack *s,int val){
    if(s->top+1==s->size){return 0;} //栈满了
    s->top+=1;
    s->data[s->top]=val;

    return 1;
}
int pop(Stack *s){
    if(empty(s)) return 0;//空的出不了
    s->top-=1;
    return 1;
}
void output(Stack *s){
    printf("Stack: ");
    for(int i=s->top;i>0;--i){
        printf("%4d ",s->data[i]);
    }
    printf("\n");
}

void acm_1_4_zhan_test(){
    srand(time(0));
#define MAX_OP 10
    Stack *s=initStack(10);
    for(int i=0;i<MAX_OP;i++){
        int op=rand()%3,val=rand()%100;
        switch (op) {
            case 0:
                printf("pop stack,item=%d\n",top(s));
                pop(s);
                break;
            case 1:
            case 2:
                printf("push stack,item=%d\n",val);
                push(s,val);
                break;
        }
        output(s);
    }
    clearStack(s);
}

leetcode 20:括号匹配

  1. 直接看是不是封闭
  2. 栈,最后看栈是否为空
class Solution {
    public boolean isValid(String s) {
        int length=s.length()/2;
        for(int i=0;i<length;i++){
            s=s.replace("()","").replace("{}","").replace("[]","");
        }
        return s.length()==0;
    }
}
class Solution {
public:
    void solve(char str[]){
        int flag=1;
        Stack *s=initStack(100);
        for(int i=0;str[i];i++){
            if(str[i]=='(' || str[i]=='[' || str[i]=='{'){
                push(s,str[i]);
            }else{
                //反向匹配栈顶元素
                // if (top(s)=='(' && str[i]==')'){
                //     pop(s);
                // }
                switch(str[i]){
                    case ')':{
                        if(empty(s) && top(s)=='(') pop(s);
                        else flag=0;
                        }
                        break;
                    case ']':{
                        if(empty(s) && top(s)=='[') pop(s);
                        else flag=0;
                        }
                        break;
                    case '}':
                        if(empty(s) && top(s)=='{') pop(s);
                        else flag=0;
                        }
                        break;
                }
                if(flag===0) break; //不匹配,直接退出
            }
        }
        if(flag==0 || !empty(s)){
            printf("error\n");
        }else{
            printf("success\n");
        }
        clearStack(s);
        return;
    }
    bool isValid(string s) {
        char str[100]; //读取字符序列
        while(~scanf("%s",str)){
            solve(str);
        }
        return 0;
    }
};

请添加图片描述

样例输入
5
fun1()
fun2()
return
fun3()
fun4()
fun4()
样例输出
fun1()->fun3()->fun4()
#include <iostream>
#include <cstdio>
#include <queue>
#include <stack>
#include <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>
using namespace std;
int main(){
	int n;
    cin >> n;
    vector<string> ops(n),s; //ops数组
    //最方便的是用数组模拟战
    string target;
    for(int i=0;i<n;i++){
        cin >> ops[i]; //读的存到i里
    }
    cin>>target; //读取目标函数
    int flag=0;
    for(int i=0;i<n;i++){
        if(target==ops[i]){
            s.push_back(ops[i]); //将新的元素压入到数组最尾端
            flag=1;
            break;
        }
        if(ops[i]=="return"){
            s.pop_back(); //从末尾弹出一个
        }
        else{ //不是return ,就是程序,入栈
            s.push_back(ops[i]);
        }
    }
    if(flag){ //找到了目标函数,就输出所有元素
        for(int i=0;i<s.size();i++){
            if(i) cout << "->";
            cout << s[i];
        }
        cout <<endl;
    }else{
        cout << "NOT REFERENCED" <<endl;

    }
	return 0;
}

HZOJ838:2020计算机考研数据结构的第41题

D=|a-b|+|b-c|+|c-a| 求最小距离

//
// Created by cry on 2024/3/13.
//
#include <iostream>
#include <cstdlib>
#include <queue>
using namespace std;

int min_num(int a, int b, int c) {
    if (a > b) swap(a, b);
    if (a > c) swap(a, c);
    return a;
}
//求最小值
int func(queue<int> que1, queue<int> que2, queue<int> que3) {
    //TODO
    int ans=0x3f3f3ff;
    while(!que1.empty() && !que2.empty() && !que3.empty()){
        int a=que1.front(),b=que2.front(),c=que3.front();
        int temp_ans=abs(a-b)+abs(b-c)+abs(a-c);
        if(temp_ans < ans)ans=temp_ans;
        int d= min_num(a,b,c);
        if(a==d)que1.pop();
        if(b==d)que2.pop();
        if(c==d)que3.pop();
    }
    return ans;
}

int main() {
    int m, n, k, x;
    queue<int> que1, que2, que3;
    cin >> m >> n >> k;
    for (int i = 0; i < m; i++) {
        cin >> x;
        que1.push(x);
    }
    for (int i = 0; i < n; i++) {
        cin >> x;
        que2.push(x);
    }
    for (int i = 0; i < k; i++) {
        cin >> x;
        que3.push(x);
    }
    cout << func(que1, que2, que3) << endl;
    return 0;
}

退格,比较两个含有退格的字符串

class Solution {
public:
    void pushStack(string &s,stack<char> &s1){
    for(int i=0;s[i];i++){

            if(s[i]=='#'){
                if(!s1.empty())
                s1.pop();
                }
            else s1.push(s[i]);
        }
    }
    bool backspaceCompare(string s, string t) {
        stack<char> s1,s2;
        pushStack(s,s1);
        pushStack(t,s2);
        if(s1.size() != s2.size()) return false;
        while(!s1.empty()){
            if(s1.top() != s2.top()) return false;
            s1.pop();s2.pop();
        }
        return true;
    }
};

海贼263 火车进栈

//
// Created by cry on 2024/3/14.
//
#include <iostream>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#include <stack>

using namespace std;
bool isValid(int a[],int n){
    //判断一个序列是否为一个合法的出栈序列
    stack<int> s;
    int x = 1;
    for(int i=0;i<n;i++){
        if(s.empty() || s.top() <a[i]){
            //入栈
            while(x<=a[i]){
                s.push(x++);
            }
        }
        if(s.empty() || s.top()!=a[i]){
            //不合法
            return false;
        }
        s.pop();
    }
    return true;
}
void acm_1_4_zhan_huocheruzhan_test(){
    int n,a[25],cnt=20;
    cin >> n;
    for(int i=0;i<n;i++) a[i]=i+1; //将n个数字放到数组前n位
    do{
        if(isValid(a,n)){
            for(int i=0;i<n;i++){
                cout << a[i];
            }
            cout <<endl;
            cnt -=1;
        }
    }while(next_permutation(a,a+n) && cnt) ; //cnt为0的时候循环退出

}

leetcode946:验证栈序列

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        int x=0,n=pushed.size();
        stack<int> s;
        for(int i=0;i<n;i++){
            //看出栈的每一位是否是合法的
            //当前元素即不等于栈顶元素
            if(s.empty() || s.top()!=popped[i]){
                while(x < pushed.size() && pushed[x]!=popped[i]){
                    s.push(pushed[x]);
                    x+=1;
                }
                if(x==pushed.size())//都压进去了还没有找到
                    return false;
                //找到了才停
                s.push(pushed[x]);
                x+=1;
            }
            s.pop(); //出栈一个元素
        }
        return true;
    }
};

最长有效括号

//
// Created by cry on 2024/3/14.
//
#include <iostream>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#include <stack>

using namespace std;
#define MAX_N 10000
int main(){
    char str[MAX_N+5];
    int match[MAX_N +5] ={0};
    stack<int> s;
    cin >> (str+1);
    for (int i = 1; str[i]; i++) {
        switch(str[i]){
            case '(':
            case '[':
            case '{':
                s.push(i);
                break;
            case ')': {
                if (!s.empty() && str[s.top()] == '(') {

                    match[s.top()] = i;
                    match[i] = s.top();
                    s.pop();
                } else {
                    //不匹配就把右括号压入栈顶,为了让之前都非法
                    s.push(i);
                }
            }break;
            case ']': {
                if (!s.empty() && str[s.top()] == '[') {

                    match[s.top()] = i;
                    match[i] = s.top();
                    s.pop();
                } else {
                    //不匹配就把右括号压入栈顶,为了让之前都非法
                    s.push(i);
                }
            }break;
            case '}': {
                if (!s.empty() && str[s.top()] == '{') {
                    match[s.top()] = i;
                    match[i] = s.top();
                    s.pop();
                } else {
                    //不匹配就把右括号压入栈顶,为了让之前都非法
                    s.push(i);
                }
            }break;
        }
    }

    int temp_ans=0,ans=0,i=1; //temp_ans记录当前连续阴影长度
    while(str[i]){
        if(match[i]){
            temp_ans+=(match[i]-i+1);
            i=match[i]+1;
        }else{
            i+=1;
            temp_ans=0;
        }
        if(temp_ans>ans) ans=temp_ans;
    }
    cout << ans <<endl;
	return 0;

}

leetcode 622设计循环队列

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。
  • Front: 从队首获取元素。如果队列为空,返回 -1 。
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
  • isEmpty(): 检查循环队列是否为空。
  • isFull(): 检查循环队列是否已满。
//
// Created by cry on 2024/3/15.
//
#include <iostream>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#include <stack>

using namespace std;
//节点
struct Node{
    int data;
    Node *next;
};
class MyCircularQueue{
public:
    //类变量
    Node *head,*tail;
    int size,count;

    MyCircularQueue(int k){
//        (head,tail]
        //初始化
        size=k;
        count=0;
        head=new Node();
        tail=head;
        for(int i=1;i<k;i++){ //0是head
            tail->next=new Node();
            tail=tail->next;
        }
        tail->next=head;
        return ;
    }
    bool enQueue(int value) {
        if(isFull()) return false;
        tail=tail->next;
        tail->data=value;
        count+=1;
        return true;
    }

    bool deQueue() {
        if(isEmpty())return false;
//queue 先进后出
        head=head->next;
        count-=1;
        return true;
    }
//返回首节点 head
    int Front() {
        if(isEmpty()) return -1;
        return head->data;
    }
//返回尾节点 tali
    int Rear() {
        if(isEmpty()) return -1;
        return tail->data;
    }
//count为0表空
    bool isEmpty() {
        return count==0;
    }
//count==size表满
    bool isFull() {
        return count==size;
    }
};

HZ 266 表达式计算

样例输入1
(2+2)^(1+1)
样例输出1
16
  1. 双栈方法
  2. 竞赛方法

3+5 变成一颗树,+为根节点,左右节点分别为3和5

竞赛(数据结构)思维:把计算机不好理解的信息 变成计算机好理解的新的信息形态-数据结构

将字符串转为树:

  1. 去除括号,括号只影响优先级,不是加减乘除
  2. 得到每一个符号相关的权值
  3. 有括号的加上附加权重:遇到左括号附加权重+100 ,右括号附加权重-100
  4. 最终权重:符号权重+附加权重
  5. 找到权重最低的位置,然后表达式分割,最后递归求解
//
// Created by cry on 2024/3/15.
//
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
#define INF 0x3f3f3f3f

#define DEBUG
//#if DEBUG
//void output(string &s,int l,int r){
//    for(int i=l;i<r;i++){
//        cout << s[i];
//    }
//    cout << endl;
//    return ;
//}
//#endif
bool is_operator(char c){
    switch(c){
        case '+':
        case '-':
        case '*':
        case '/':
        case '^': return true;
        default: return false;
    }
    return false;
}
//找到表达式中优先级
long long calc(string &s,long long l,long long r){
    //找权重最低的符号位置
//#if DEBUG
//cout << s<<" " << l <<" "<< r <<":";
//output(s,l,r);
//#endif

    long long pos =-1,pri=INF-1,cur_pri,temp_pri=0; //当前权重和附加权重
    for (long long i = l; i <r; i++) {
        cur_pri=INF;
        switch (s[i]) {
            case '(':
                temp_pri+=100;break;
            case ')':
                temp_pri-=100;
                break;
            case '+':
            case '-':
                cur_pri=temp_pri+1;
                break;
            case '*':
            case '/':
                cur_pri=temp_pri+2;
                break;
            case '^':
                cur_pri=temp_pri+3;
                break;
        }
//  处理负数 -9  +9
        if( (s[i]=='-' || s[i]=='+') && (i-1<0 || is_operator(s[i-1]))){
            cur_pri+=1000;
        }
//        cur_pri就是当前符号优先级
//如果不是加减乘除次方 ,那就是数字,数字权重默认极大值
//INF-1  >= INF ,pri为INF-1就不会将pos指向数值了
        if(pri >= cur_pri) //比如如果都是加减,权重一样
        {
            //两个符号优先级一样的话,取后面的
            pri=cur_pri;
            pos=i;
        }
    }
//    整个表达式没有运算符,全是数字,直接返回数字
    if(pos ==-1){
        long long num=0;
        for(long long i=l;i<r;i++)
        {
            if(s[i] < '0' || s[i]>'9') continue;
            num=num *10+(s[i]-'0');
        }
        return num;
    }else{
//        可以分成两部分
//        从l到pos-1  从pos+1 到r
        long long a= calc(s,l,pos); //[) 左闭右开,所以到pos
        long long b= calc(s,pos+1,r);
        switch(s[pos]){
            case '+':return a+b;
            case '-':return a-b;
            case '*':return a*b;
            case '/':return a/b;
            case '^':return pow(a,b);
        }
    }
    return 0;

}
void acm_1_4_zhan_biaodashiQiuzhi_test(){
    string str;
    cin >> str;
    cout << calc(str,0,str.size())<<endl;//调用递归表达式
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厨 神

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值