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

队列:先进先出
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:括号匹配
- 直接看是不是封闭
- 栈,最后看栈是否为空
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
- 双栈方法
- 竞赛方法
3+5 变成一颗树,+为根节点,左右节点分别为3和5
竞赛(数据结构)思维:把计算机不好理解的信息 变成计算机好理解的新的信息形态-数据结构
将字符串转为树:
- 去除括号,括号只影响优先级,不是加减乘除
- 得到每一个符号相关的权值
- 有括号的加上附加权重:遇到左括号附加权重+100 ,右括号附加权重-100
- 最终权重:符号权重+附加权重
- 找到权重最低的位置,然后表达式分割,最后递归求解
//
// 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;//调用递归表达式
}

被折叠的 条评论
为什么被折叠?



