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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/690076.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue的十大面试题详情

1 v-show与v-if区别 v-if与v-show可以根据条件的结果,来决定是否显示指定内容&#xff1a; v-if: 条件不满足时, 元素不会存在. v-show: 条件不满足时, 元素不会显示(但仍然存在). <div id"app"><button click"show !show">点我</but…

(2024,提示优化,监督微调,强化学习,近端策略优化)用于安全生成文本到图像的通用提示优化器

Universal Prompt Optimizer for Safe Text-to-Image Generation 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 相关工作 3. 提议的框架 4. 实验 0. 摘要 文本-图像&a…

软件实例分享,酒店酒水寄存管理系统软件教程

软件实例分享&#xff0c;酒店酒水寄存管理系统软件教程 一、前言 以下软件教程以 佳易王酒水寄存管理系统软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、寄存的商品名称可以预先设置 2、寄存人可以使用手.机号识别 3、会员充值…

详解4大C语言内存函数【超详细建议点赞收藏】

目录 1. memcpy----内存拷贝1.1 函数介绍1.2 函数使用1.3 模拟实现 2. memmove----重叠内存的数据拷贝2.1 函数介绍2.2 函数使用2.3 模拟实现 3. memcmp----内存比较3.1 函数介绍3.2 函数使用 4.memset----内存设置4.1 函数介绍4.2 函数使用 注意&#xff1a;以下4个内存函数在…

Springboot医院信息管理系统源码 带电子病历和LIS Saas应用+前后端分离+B/S架构

目录 系统特点 技术架构 系统功能 1、 标准数据维护 2、 收费&#xff08;门诊/住院&#xff09;系统 3、 药剂管理系统 4、 医生工作站系统 5、 护士工作站系统 6、电子病历系统 系统优点 云HIS系统简介 云HIS系统功能模块 门急诊挂号管理 门诊收费管理 门诊医…

ansible剧本中的角色

1 roles角色 1.1 roles角色的作用&#xff1f; 可以把playbook剧本里的各个play看作为一个角色&#xff0c;将各个角色打的tasks任务、vars变量、template模版和copy、script模块使用的相关文件等内容放置在指定角色的目录里统一管理&#xff0c;在需要的时候可在playbook中使…

直接选择排序算法

​​​​​​目录 选择排序 SelectSort直接选择排序 整体思路 图解分析 ​ 代码实现 时间复杂度 选择排序 基本思想&#xff1a; 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排…

【SV的面向对象 SV的类_2024.01.02】

OOP术语 OOP&#xff1a;object oriented programming Class类&#xff1a;包含变量和子程序的基本构建块 Object对象&#xff1a;类的一个实例 Handle句柄&#xff1a;指向对象的指针 Property属性&#xff1a;存储数据的变量&#xff1b;在V中&#xff0c;可以是wire或reg类…

NOTA-马来酰亚胺,1295584-83-6,可作为过渡金属离子的配体

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;NOTA-马来酰亚胺&#xff0c;NOTA Maleimide &#xff0c;NOTA-Mal&#xff0c;1295584-83-6 一、基本信息 产品简介&#xff1a;NOTA Maleimide, also known as NOTA maleimide, is a novel bifunctional integrat…

Sora不懂物理世界,翻车神图全网爆笑!LeCun马斯克DeepMind大佬激辩世界模型

大火的Sora&#xff0c;让许多动画、影视行业的人大为恐慌。 不过&#xff0c;今天网上广为流传的这张图&#xff0c;让大家倒是放心了不少。 可以看到&#xff0c;在这个视频中&#xff0c;玻璃杯碎裂的方式十分诡异—— 它被抬到半空中时&#xff0c;桌子上就忽然出现了一滩…

PWM功能介绍 和配置

泰山派默认提供了3组PWM的GPIO &#xff0c; 为了检测PWM的输出&#xff0c;我们可以配合逻辑分析仪来查看效果&#xff0c;或者搭配STC8的LED灯 PWM 测试 列举所有的PWM设备&#xff1a; # 查找所有有pwm名称的文件 find / -name "pwm" # pwm4: pwmfe6e0000 edp屏幕…

【图像分割 2023 WACV】HiFormer

【图像分割 2023 WACV】HiFormer 论文题目&#xff1a;HiFormer: Hierarchical Multi-scale Representations Using Transformers for Medical Image Segmentation 中文题目&#xff1a;HiFormer:基于Transformer的分层多尺度表示医学图像分割 论文链接&#xff1a; 论文代码&a…

解决updatexml和extractvalue查询显示不全

报错注入是一种常见的SQL 注入方式&#xff0c;通过注入代码&#xff0c;触发数据库的错误响应&#xff0c;并从错误信息中获取有用的信息。 updatexml和extractvalue updatexml和extractvalue 是常用的两个报错注入函数 http://localhost/sqli/Less-5/?id1%27and%20updat…

Maxwell - 增量数据

前言 今天来学习一个新的大数据小工具 Maxwell &#xff0c;它和 Sqoop 很像。Sqoop主要用于在 Hadoop &#xff08;比如 HDFS、Hive、HBase 等&#xff09;和关系型数据库之间进行数据的批量导入和导出&#xff0c;而 Maxwell 则主要用于监控数据库的变化&#xff08;通过监控…

如何使用Docker部署Drupal并结合cpolar实现固定公网地址访问

文章目录 前言1. Docker安装Drupal2. 本地局域网访问3 . Linux 安装cpolar4. 配置Drupal公网访问地址5. 公网远程访问Drupal6. 固定Drupal 公网地址 前言 Dupal是一个强大的CMS&#xff0c;适用于各种不同的网站项目&#xff0c;从小型个人博客到大型企业级门户网站。它的学习…

2024年及以后在您的项目中使用的最佳CSS框架

在过去几年中&#xff0c;CSS已经取得了长足的进步。在过去&#xff0c;您可能会使用CSS来创建依赖于HTML表格和CSS浮动作为其布局系统的简单外观的Web应用程序。而现在&#xff0c;您可以设计复杂的交互式用户界面&#xff0c;具有优雅的设计。 尽管CSS变得越来越先进&#x…

虚拟机centos7 网络IP冲突

修改其中一个虚拟机IP 1&#xff1a; 设置虚拟机网络配置器的模式为NAT模式&#xff0c;操作方式如下图所示 2&#xff1a;点击虚拟网络编辑器 3&#xff1a;点击NAT设置 4&#xff1a;点击DHCP配置 5&#xff1a; 修改配置文件来指定IP并可以连接到外网&#xff0c;在roo…

【通讯录案例-数据存储总结 Objective-C语言】

一、我们简单的把“数据存储”总结一下, 1.上午,我们说的三种存储方式, 1)plist 2)Preference(偏好设置) 3)NSKeyedArchiver(归档、解档) 三种存储方式, 2.什么能做plist存储, 1)writeToFile:方法, 实际上,这个东西,才是关键, 有一个对象,可以去写w…

ETL数据集成工具DataX、Kettle、ETLCloud特点对比

ETL数据集成工具 对于数据仓库&#xff0c;大数据集成类应用&#xff0c;通常会采用ETL工具辅助完成。ETL&#xff0c;是英文 Extract-Transform-Load 的缩写&#xff0c;用来描述将数据从来源端经过抽取(extract) 、交互转换(transform) 、加载(load)至的端的过程当前的很多应…

spring @Transactional注解参数详解

事物注解方式: Transactional 当标于类前时, 标示类中所有方法都进行事物处理 , 例子: 1 Transactional public class TestServiceBean implements TestService {}当类中某些方法不需要事物时: Transactional public class TestServiceBean implements TestService {private…