DS:栈和队列的相互实现
创作不易,感谢友友们三连!!
一、前言
栈和队列的相互实现是用两个栈去实现队列或者是用两个队列去实现栈,这样其实是把问题复杂化的,实际中没有什么应用价值,但是通过他们的相互实现可以让我们更加深入地理解栈和队列的特点,而我也是用两道相关的OJ题来分析这个过程!
二、用两个队列实现栈
力扣:队列实现栈

2.1 思路

2.2 代码实现
2.2.1 队列的代码
我们先把队列的实现声明放这
Queue.h
#include<stdbool.h>
#include<assert.h>
typedef int QDatatype;//方便后面修改存储数据的数据类型
typedef struct QueueNode//队列结点的数据结构
{QDatatype data;//存储数据struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* phead;//指向队头,用于出队(头删)QNode* ptail;//指向队尾,用于入队(尾插)int size;//记录有效元素个数
}Queue;//创建一个队列相关结构体
void QueueInit(Queue* pq);//队列的初始化
void QueuePush(Queue* pq, QDatatype x);//队列的入队(尾插)
void QueuePop(Queue* pq);//队列的出队(头删)
QDatatype QueueFront(Queue* pq);//获取队列头部元素
QDatatype QueueBack(Queue* pq);//获取队列尾部元素
int QueueSize(Queue* pq);//获取队列中有效元素个数
bool QueueEmpty(Queue* pq);//判断队列是否为空
void QueueDestory(Queue* pq);//队列的销毁
2.2.2 结构体的创建
封装一个myStack结构体管理两个队列
typedef struct MyStack
{Queue q1;Queue q2;
} MyStack;
//用两个队列实现栈,构建一个结构体去管理这两个队列
2.2.3 初始化栈
初始化栈,相当于先构建栈的结构体变量,然后再初始化他的两个队列成员
MyStack* myStackCreate() //返回一个MySack类型的指针
{MyStack* obj = (MyStack*)malloc(sizeof(MyStack));if (obj == NULL){perror("malloc fail");exit(1);}
//如果开辟成功,对栈初始化相当于对栈结构体中的两个队列初始化QueueInit(&obj->q1);QueueInit(&obj->q2);return obj;
}
2.2.4 模拟压栈
按照我们之前的思路,压栈直接找到不为空的队列尾插就行
void myStackPush(MyStack* obj, int x)
//压栈前必须在不为空的队列中压栈
{if (!QueueEmpty(&obj->q1))//如果q1不为空压q1QueuePush(&obj->q1, x);else//如果q1为空,则压q2QueuePush(&obj->q2, x);
}
2.2.5 模拟出栈并返回栈顶元素
按照之前的思路,出栈就是先找到非空的队列,移除到空的队列上,只留下最后一个元素,再头删
int myStackPop(MyStack* obj)
//出栈,必须找到不为空的队列,然后将该队列的元素倒倒另一个队列中,知道只剩最后一个元素的时候,就删除
{//要找到不为空的队列进行操作,所以先假设一个为空一个不为空,如果给个条件判断Queue* Emptyq = &obj->q1;Queue* NonEmptyq = &obj->q2;if (!QueueEmpty(&obj->q1))//错了的话就认个错然后换回来{NonEmptyq = &obj->q1;Emptyq = &obj->q2;}//开始导数据while (QueueSize(NonEmptyq) > 1){//将队列头的元素倒进去另一个队列,在出栈QueuePush(Emptyq, QueueFront(NonEmptyq));//压栈QueuePop(NonEmptyq);//倒入一个就将非空队列出队列一个}//倒完后只剩一个数据了,先记录返回值再删除int top = QueueFront(NonEmptyq);QueuePop(NonEmptyq);return top;
}
2.2.6 获取栈顶元素
找到不为空的队列,然后获取队列尾的元素,就是获取栈顶元素
int myStackTop(MyStack* obj)
//找到不为空的队列,然后获取队列尾的元素,相当于获取栈顶元素
{if (!QueueEmpty(&obj->q1))//如果q1不为空取q1队尾return QueueBack(&obj->q1);else//如果q2不为空取q2队尾return QueueBack(&obj->q2);
}
2.2.7 判断栈是否为空
判断栈是否为空,本质上就是判断两个队列是否为空
bool myStackEmpty(MyStack* obj) //栈为空当且仅当两个队列都为空
{return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
2.2.8 释放栈
要先释放掉栈的队列成员的空间,然后再释放栈的空间,并置空
void myStackFree(MyStack* obj)
{//释放obj前一定也要将q1和q2的空间释放了QueueDestory(&obj->q1);QueueDestory(&obj->q2);free(obj);//obj = NULL;没用,一级指针接受指针相当于值传递//要手动在main函数中置空
}
值得注意的是,这边给obj置空是没有的,要想改变obj必须用二级指针,所以我们最后要释放的话要在程序的最后自己手动释放。
2.3 全部代码
2.3.1 queue.h
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDatatype;//方便后面修改存储数据的数据类型
typedef struct QueueNode//队列结点的数据结构
{QDatatype data;//存储数据struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* phead;//指向队头,用于出队(头删)QNode* ptail;//指向队尾,用于入队(尾插)int size;//记录有效元素个数
}Queue;//创建一个队列相关结构体
void QueueInit(Queue* pq);//队列的初始化
void QueuePush(Queue* pq, QDatatype x);//队列的入队(尾插)
void QueuePop(Queue* pq);//队列的出队(头删)
QDatatype QueueFront(Queue* pq);//获取队列头部元素
QDatatype QueueBack(Queue* pq);//获取队列尾部元素
int QueueSize(Queue* pq);//获取队列中有效元素个数
bool QueueEmpty(Queue* pq);//判断队列是否为空
void QueueDestory(Queue* pq);//队列的销毁
2.3.2 queue.c
#include"Queue.h"void QueueInit(Queue* pq)
{assert(pq);//判断传的是不是空指针pq->phead = pq->ptail = NULL;pq->size = 0;//因为队列不像栈一样,有一个top表示栈顶元素的下标//所以如果我们想知道这个队列的有效数据个数,就必须遍历队列//由于其先进先出的特性,我们默认只能访问到头元素和尾元素//所以必须访问一个头元素,就出队列一次,这样才能实现遍历//但是这样的代价太大了,为了方便,我们直接用size
}
void QueuePush(Queue* pq, QDatatype x)
{assert(pq);//入队必须从队尾入!QNode* newnode = (QNode*)malloc(sizeof(QNode));//创建一个新节点if (newnode == NULL)//如果新节点申请失败,退出程序{perror("malloc fail");}//新节点创建成功,给新节点初始化一下newnode->data = x;newnode->next = NULL;//开始入队//如果直接尾插的话,由于会用到ptail->next,所以得考虑队列为空的情况if (pq->ptail == NULL)//如果为空,直接把让新节点成为phead和ptail{//按道理来说,如果ptail为空,phead也应该为空// 但是有可能会因为我们的误操作使得phead不为空,这个时候一般是我们写错的问题//所以使用assert来判断一下,有问题的话会及时返回错误信息assert(pq->phead == NULL);pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}void QueuePop(Queue* pq)
{assert(pq);//如果队列为空,没有删除的必要assert(!QueueEmpty(pq));//队列中的出队列相当于链表的头删//如果直接头删,那么如果队列只有一个有效数据的话,那么我们将phead的空间释放掉,但是没有将ptail给置空//这样会导致ptail成为一个野指针,所以我们需要考虑只有一个节点多个节点的情况if (pq->phead->next == NULL)//一个节点的情况,直接将这个节点释放并置空即可{free(pq->phead);pq->phead = pq->ptail = NULL;//置空,防止野指针}else//多个节点的情况,直接头删{QNode* next = pq->phead->next;//临时指针记住下一个节点free(pq->phead);pq->phead = next;//让下一个节点成为新的头}pq->size--;
}QDatatype QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));//队列如果为空,则不可能找得到队列头元素//队列不为空的时候,直接返回phead指向的数据return pq->phead->data;
}QDatatype QueueBack(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));//队列如果为空,则不可能找得到队尾元素//队列不为空的时候,直接返回ptail指向的数据return pq->ptail->data;
}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}bool QueueEmpty(Queue* pq)//链表为空的情况,可以根据容量,也可以根据ptail==NULL&&phead==NULL
{assert(pq);return pq->phead == NULL && pq->ptail == NULL;
}void QueueDestory(Queue* pq)
{assert(pq);//判断传的是不是空指针//要逐个节点释放QNode* pcur = pq->phead;while (pcur){QNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}
2.3.3 mystack.h
#include"Queue.h"typedef struct MyStack
{Queue q1;Queue q2;
} MyStack;
//用两个队列实现栈,构建一个结构体去管理这两个队列MyStack* myStackCreate();//初始化栈
void myStackPush(MyStack* obj, int x);//压栈
int myStackPop(MyStack* obj);//出栈
int myStackTop(MyStack* obj);//获取栈顶元素
bool myStackEmpty(MyStack* obj);//判断栈是否为空
void myStackFree(MyStack* obj);//释放栈
2.3.4 mystack.c
#include"MyStack.h"MyStack* myStackCreate() //返回一个MySack类型的指针
{MyStack* obj = (MyStack*)malloc(sizeof(MyStack));if (obj == NULL){perror("malloc fail");exit(1);}
//如果开辟成功,对栈初始化相当于对栈结构体中的两个队列初始化QueueInit(&obj->q1);QueueInit(&obj->q2);return obj;
}void myStackPush(MyStack* obj, int x)
//压栈前必须在不为空的队列中压栈
{if (!QueueEmpty(&obj->q1))//如果q1不为空压q1QueuePush(&obj->q1, x);else//如果q1为空,则压q2QueuePush(&obj->q2, x);
}int myStackPop(MyStack* obj)
//出栈,必须找到不为空的队列,然后将该队列的元素倒倒另一个队列中,知道只剩最后一个元素的时候,就删除
{//要找到不为空的队列进行操作,所以先假设一个为空一个不为空,如果给个条件判断Queue* Emptyq = &obj->q1;Queue* NonEmptyq = &obj->q2;if (!QueueEmpty(&obj->q1))//错了的话就认个错然后换回来{NonEmptyq = &obj->q1;Emptyq = &obj->q2;}//开始导数据while (QueueSize(NonEmptyq) > 1){//将队列头的元素倒进去另一个队列,在出栈QueuePush(Emptyq, QueueFront(NonEmptyq));//压栈QueuePop(NonEmptyq);//倒入一个就将非空队列出队列一个}//倒完后只剩一个数据了,先记录返回值再删除int top = QueueFront(NonEmptyq);QueuePop(NonEmptyq);return top;
}int myStackTop(MyStack* obj)
//找到不为空的队列,然后获取队列尾的元素,相当于获取栈顶元素
{if (!QueueEmpty(&obj->q1))//如果q1不为空取q1队尾return QueueBack(&obj->q1);else//如果q2不为空取q2队尾return QueueBack(&obj->q2);
}bool myStackEmpty(MyStack* obj) //栈为空当且仅当两个队列都为空
{return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}void myStackFree(MyStack* obj)
{//释放obj前一定也要将q1和q2的空间释放了QueueDestory(&obj->q1);QueueDestory(&obj->q2);free(obj);//obj = NULL;没用,一级指针接受指针相当于值传递//要手动在main函数中置空
三、用两个栈实现队列
力扣:用栈实现队列

3.1 思路

3.2 代码实现
3.2.1 栈的代码
这里先把栈的声明放这里
stack.h
#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>typedef int STDataType;
//支持动态增长的栈
typedef struct Stack
{STDataType* a;int top;//栈顶int capacity;//栈容量
}Stack;void StackInit(Stack* ps);//初始化栈
void StackPush(Stack* ps, STDataType x);//入栈
void StackPop(Stack* ps);//出栈
STDataType StackTop(Stack* ps);//获取栈顶元素
int StackSize(Stack* ps);//获取栈中有效元素个数
bool StackEmpty(Stack* ps);//检测栈是否为空,为空返回true
void StackDestory(Stack* ps);//销毁栈
3.2.2 结构体的创建
根据前面的思路,一个栈专门用来入栈,一个栈专门用来出栈
typedef struct MyQueue
{Stack Pushst;//专门用来入栈Stack Popst;//专门用来出栈
} MyQueue;MyQueue* myQueueCreate();//初始化队列
void myQueuePush(MyQueue* obj, int x);//模拟入队
int myQueuePop(MyQueue* obj);//模拟出队,并返回出去的头元素
int myQueuePeek(MyQueue* obj);//获取队列头元素并返回
bool myQueueEmpty(MyQueue* obj);//判断队列是否为空
void myQueueFree(MyQueue* obj);//销毁队列
3.2.3 初始化队列并返回节点
初始化队列本质上就是对两个栈进行初始化
MyQueue* myQueueCreate()
{MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));if (obj == NULL){perror("malloc fail");exit(1);}//对队列初始化其实就是对里面的两个栈初始化StackInit(&obj->Pushst);StackInit(&obj->Popst);return obj;
}
3.2.4 模拟入队
入队就很简单了,直接往第一个栈里面入栈就行
void myQueuePush(MyQueue* obj, int x)
{StackPush(&obj->Pushst, x);
}
3.2.5 获取队列头的元素并返回
队列头的元素要在第二个栈去获取,但在获取前还得确保第二个栈有元素,如果没有,就得先把第一个栈倒过去
int myQueuePeek(MyQueue* obj)
//获取队列头元素有两种情况
//1、一种是popst不为空,直接返回其top下标的元素就行了
//2、一种是popst为空,这时候需要将pushst中的数据全部倒过去,再重复情况1
{if (StackEmpty(&obj->Popst)){while (!StackEmpty(&obj->Pushst)){//挪数据就是一边给popst入栈,一边给pushst出栈StackPush(&obj->Popst, StackTop(&obj->Pushst));StackPop(&obj->Pushst);}}return StackTop(&obj->Popst);
}
3.2.6 模拟出队,并返回出去的头元素
出队也要确保第二个栈不为空,但其实我们有了上面这个函数,直接调用一次就相当于是把我们把这个操作给完成了,所以我们直接接受上面那个函数的返回值然后直接pop就行
int myQueuePop(MyQueue* obj)
{
//跟myQueuePeek一样有两种情况,但是我们调用了这个函数相当于是帮我们判断过了,此时直接删就可以了int top = myQueuePeek(obj);StackPop(&obj->Popst);return top;
}
3.2.7 判断队列是否为空
队列是否为空,本质上就是两个栈是否为空
bool myQueueEmpty(MyQueue* obj)
{return StackEmpty(&obj->Popst) && StackEmpty(&obj->Pushst);
}
3.2.8 销毁队列
队列销毁,本质上就是两个栈的销毁,但是要在最后把队列的结构体的释放掉
void myQueueFree(MyQueue* obj)
{StackDestory(&obj->Popst);StackDestory(&obj->Pushst);free(obj);//没用obj = NULL;
}
注意的是这边接受obj的是一级指针,相当于值传递,这里置空没什么意义,要在外面手动置空
3.3 全部代码
3.3.1 stack.h
#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>typedef int STDataType;
//支持动态增长的栈
typedef struct Stack
{STDataType* a;int top;//栈顶int capacity;//栈容量
}Stack;void StackInit(Stack* ps);//初始化栈
void StackPush(Stack* ps, STDataType x);//入栈
void StackPop(Stack* ps);//出栈
STDataType StackTop(Stack* ps);//获取栈顶元素
int StackSize(Stack* ps);//获取栈中有效元素个数
bool StackEmpty(Stack* ps);//检测栈是否为空,为空返回true
void StackDestory(Stack* ps);//销毁栈
3.3.2 stack.c
#include"Stack.h"void StackInit(Stack* ps)
{ps->a = NULL;ps->top = ps->capacity = 0;
}void StackPush(Stack* ps, STDataType x)
{assert(ps);//判断是否需要扩容if (ps->top == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;STDataType* temp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newcapacity);if (temp == NULL){perror("realloc fail");exit(1);}ps->a = temp;ps->capacity = newcapacity;}//压栈ps->a[ps->top++] = x;
}void StackPop(Stack* ps)
{assert(ps);//如果栈为空,则没有删除的必要assert(!StackEmpty(ps));ps->top--;
}STDataType StackTop(Stack* ps)
{assert(ps);//如果栈为空,不可能有栈顶元素assert(!StackEmpty(ps));return ps->a[ps->top - 1];
}int StackSize(Stack* ps)
{assert(ps);return ps->top;
}bool StackEmpty(Stack* ps)
{assert(ps);return ps->top == 0;
}void StackDestory(Stack* ps)
{free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
3.3.3 myqueue.h
#include"Stack.h"typedef struct MyQueue
{Stack Pushst;//专门用来入栈Stack Popst;//专门用来出栈
} MyQueue;MyQueue* myQueueCreate();//初始化队列并返回节点
void myQueuePush(MyQueue* obj, int x);//模拟入队
int myQueuePop(MyQueue* obj);//模拟出队,并返回出去的头元素
int myQueuePeek(MyQueue* obj);//获取队列头元素并返回
bool myQueueEmpty(MyQueue* obj);//判断队列是否为空
void myQueueFree(MyQueue* obj);//销毁队列
3.3.4 myqueue.c
#include"MyQueue.h"MyQueue* myQueueCreate()
{MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));if (obj == NULL){perror("malloc fail");exit(1);}//对队列初始化其实就是对里面的两个栈初始化StackInit(&obj->Pushst);StackInit(&obj->Popst);return obj;
}void myQueuePush(MyQueue* obj, int x)
{StackPush(&obj->Pushst, x);
}int myQueuePop(MyQueue* obj)
{
//跟myQueuePeek一样有两种情况,但是我们调用了这个函数相当于是帮我们判断过了,此时直接删就可以了int top = myQueuePeek(obj);StackPop(&obj->Popst);return top;
}int myQueuePeek(MyQueue* obj)
//获取队列头元素有两种情况
//1、一种是popst不为空,直接返回其top下标的元素就行了
//2、一种是popst为空,这时候需要将pushst中的数据全部倒过去,再重复情况1
{if (StackEmpty(&obj->Popst)){while (!StackEmpty(&obj->Pushst)){//挪数据就是一边给popst入栈,一边给pushst出栈StackPush(&obj->Popst, StackTop(&obj->Pushst));StackPop(&obj->Pushst);}}return StackTop(&obj->Popst);
}bool myQueueEmpty(MyQueue* obj)
{return StackEmpty(&obj->Popst) && StackEmpty(&obj->Pushst);
}void myQueueFree(MyQueue* obj)
{StackDestory(&obj->Popst);StackDestory(&obj->Pushst);free(obj);//没用obj = NULL;
}

相关文章:
DS:栈和队列的相互实现
创作不易,感谢友友们三连!! 一、前言 栈和队列的相互实现是用两个栈去实现队列或者是用两个队列去实现栈,这样其实是把问题复杂化的,实际中没有什么应用价值,但是通过他们的相互实现可以让我们更加深入地理…...
Hack The Box-Office
端口扫描&信息收集 使用nmap对靶机进行扫描 nmap -sC -sV 10.10.11.3开放了80端口,并且注意到该ip对应的域名为office.htb,将其加入到hosts文件中访问之 注意到扫描出来的还有robots文件,经过尝试后只有administrator界面是可以访问的 …...
android aidl进程间通信封装通用实现
接上一篇的分析,今天继续 aidl复杂流程封装-CSDN博客 今天的任务就是将代码梳理下放进来 1 项目gradle配置: 需要将对应的代码放到各自的目录下,这里仅贴下关键内容,细节可以下载代码慢慢看 sourceSets { main { manifest.srcFile src/main/And…...
FL Studio 21.2.3.4004 All Plugins Edition Win/Mac音乐软件
FL Studio 21.2.3.4004 All Plugins Edition 是一款功能强大的音乐制作软件,提供了丰富的音频处理工具和插件,适用于专业音乐制作人和爱好者。该软件具有直观的用户界面,支持多轨道录音、混音和编辑,以及各种音频效果和虚拟乐器。…...
vivado RAM HDL Coding Guidelines
从编码示例下载编码示例文件。 块RAM读/写同步模式 您可以配置块RAM资源,为提供以下同步模式给定的读/写端口: •先读取:在加载新内容之前先读取旧内容。 •先写:新内容立即可供阅读先写也是众所周知的如通读。 •无变化&…...
springboot/ssm甘肃旅游服务平台Java在线旅游规划管理系统
springboot/ssm甘肃旅游服务平台Java在线旅游规划管理系统 开发语言:Java 框架:springboot(可改ssm) vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库:mysql 5.7&am…...
第三百五十四回
文章目录 1. 概念介绍2. 使用方法2.1 获取所有时区2.2 转换时区时间 3. 示例代码4. 内容总结 我们在上一章回中介绍了"分享一些好的Flutter站点"相关的内容,本章回中将介绍timezone包.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在…...
【Funny Game】 吃豆人
目录 【Funny Game】 吃豆人 吃豆人 文章所属专区 Funny Game 吃豆人 吃豆人,这款经典游戏如今依旧魅力四射。玩家需操控小精灵,在迷宫内吞噬所有豆子,同时避开狡猾的鬼怪。当吃完所有豆子后,便可消灭鬼怪,赢得胜利。…...
PyCharm - Run Debug 程序安全执行步骤
PyCharm - Run & Debug 程序安全执行步骤 1. Run2. DebugReferences 1. Run right click -> Run ‘simulation_data_gene…’ or Ctrl Shift F10 2. Debug right click -> Debug ‘simulation_data_gene…’ 在一个 PyCharm 工程下,存在多个 Pytho…...
作为一个程序员,最少要看过这几部电影吧?
计算机专业必看的几部电影 计算机专业必看的几部电影,就像一场精彩的编程盛宴!《黑客帝国》让你穿越虚拟世界,感受高科技的魅力;《社交网络》揭示了互联网巨头的创业之路,《源代码》带你穿越时间解救世界,…...
备战蓝桥杯 Day4
目录 注意:递推开long long 1140:验证子串 1131:基因相关性 1176:谁考了第k名 1177:奇数单增序列 1180:分数线划定 1184:明明的随机数 1185:单词排序 1186:出现…...
用HTML和CSS打造跨年烟花秀视觉盛宴
目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>跨年烟花秀</title><meta name"viewport" content"widthdevi…...
SSH密钥认证登陆流程(Vscode连接到远程)
目录 前言连接远程步骤1. 下载工具包wsCli到本地机器2. 本地机器上生成ssh密钥3. 在服务器上安装公钥4. vscode连接到远程 参考资料 前言 SSH(Secure Shell)是一种用于远程登录和安全传输数据的网络协议。它提供了两种主要的远程连接方式: 密…...
k8s进阶之路-pod探针:容器内的监控机制,检测应用是否存活
配合Pod重启策略: RestartPolicy 应用程序是否启动完成: 3.startupProbe启动探针1.16:排他性 如果三个都配置了,会优先启动,会禁用前两个反馈成功后,才会启动以下两个 应用启动成功后: 1.L…...
2.1.1 摄像头
摄像头 更多内容,请关注: github:https://github.com/gotonote/Autopilot-Notes.git 摄像头是目前自动驾驶车中应用和研究最广泛的传感器,其采集图像的过程最接近人类视觉系统。基于图像的物体检测和识别技术已经相当成熟&#…...
linux安装mysql8且初始化表名忽略大小写
mysql8下载地址 MySQL8.0安装步骤 1、把安装包上传到linux系统,解压、重命名并移动到/usr/local/目录: cd ~ tar -xvf mysql-8.0.32-linux-glibc2.12-x86_64.tar.xz mv mysql-8.0.32-linux-glibc2.12-x86_64/ mysql80/ mv mysql80/ /usr/local/2、在M…...
Java-长字符串加密
引言: 在数据安全领域,加密技术是保护信息不被未授权访问的重要手段。特别是在处理长字符串时,如何保证加密后的数据既安全又高效,是一个值得探讨的话题。本文将介绍几种常见的加密算法,并展示如何在Java中实现这些算法…...
使用pytest单元测试框架执行单元测试
Pytest 是一个功能强大且灵活的 Python 单元测试框架,它使编写、组织和运行测试变得更加简单。以下是 Pytest 的一些主要特点和优点: 简单易用:Pytest 提供了简洁而直观的语法,使编写测试用例变得非常容易。它支持使用 assert 语…...
Flutter 中 DraggableScrollableSheet 的属性介绍与使用
在 Flutter 中,DraggableScrollableSheet 是一个非常有用的小部件,它允许用户通过手势来拖动一个可滚动的区域,通常被用作底部弹出式面板或者随手势拖动的控件。本文将介绍 DraggableScrollableSheet 的属性以及如何在 Flutter 中使用它。 D…...
分库分表面试必背
一,背景 随着互联网的普及,使用人数和场景爆炸式增长,现在随便一个应用系统都可能达到数百万千万甚至更大数量级的数据。大量的数据带来了新的挑战,怎么快速完成增删改查的业务,是应用服务开发者最头痛的问题。面对这个…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...

