揭开“栈和队列”的神秘面纱

 

前言

在线性表中不止有顺序表和链表,今天的主角就如标题所说--->认识栈和队列。把他们俩放一起总结是有原因的,还请看官听我娓娓道来~

 

什么是栈? 

栈(stack)是限定仅在表尾进行插入和删除操作的线性表

咱可以把栈理解成一个桶,栈底是固定的,放东西进去被称作“进栈”,拿东西被称作“出栈”, 所以栈也是按照后进先出的原则进行操作。

栈的基本方法有以下几种: 

 push()将元素入栈
 pop()将栈顶元素出栈并返回
 peek()获取栈顶元素
size()获取栈中有效元素个数
empty()检测栈是否为空
import java.util.Stack;public class MyStack {public static void main(String[] args) {Stack<Integer> stack =new Stack<>();//push入栈stack.push(12);stack.push(23);stack.push(34);//peek获取栈顶元素,但不移除int ret=stack.peek();System.out.println(ret);//pop移除栈顶元素int ret1=stack.pop();System.out.println(ret1);//注意看这里就发生了变化System.out.println(stack.peek());//获取栈的长度System.out.println(stack.size());//判断栈空if(stack.empty()){System.out.println("栈已经空");}else{System.out.println("栈不为空");}}
}

运行结果如图所示,搭配画图食用效果更佳

栈的模拟实现 

不要忘记栈也是线性表,我们是可以用数组来实现栈的,那么同样也可以用usedSize来记录

 首先初始化好一个数组,和顺序表是类似的,不记得的可以先回忆一下-->http://t.csdnimg.cn/t0Rjd

import java.util.Arrays;
public class MyStack {int []array;int usedSize=0;public MyStack(int[] array, int usedSize) {this.array = array;this.usedSize = usedSize;}

入栈也是要看满没满,是否需要扩容,道理和模拟实现顺序表是一样的

    //push入栈public void push(int val) {if (isFull()) {int[] newArray = Arrays.copyOf(array, array.length * 2);array = newArray;}array[usedSize] = val;usedSize++;}public boolean isFull(){return usedSize==array.length;}
   //peek获取栈顶元素,但不移除public int peek(){if(Empty()){return -1;}return array[usedSize-1];}

要记住peek和pop的区别:peek只是获取栈顶元素,pop可是会移除的 

  //pop移除栈顶元素public int pop(){if(Empty()){return -1;}int oldval=array[usedSize-1];usedSize--;return oldval;}
    //获取栈的长度public int size(){return usedSize;}//判断栈空public boolean Empty(){return usedSize==0;}
}

最后加上测试类,运行结果如图~

栈的运用

根据它的特性---数据都是后进先出的,来看几道题练练手

1.括号匹配

括号匹配icon-default.png?t=N7T8https://leetcode.cn/problems/valid-parentheses/description/

思考:从题目中就可以看出括号必须类型是一样的,这样左括号和右括号才会匹配,既然如此,顺着走下去,在遍历的过程中咱们把所有类型的左括号全部入栈,遇到不是左边的,便开始出栈去匹配左右括号,如果最后全部对上,那么最后栈必定为空,返回true。

但是左右括号不匹配是有两种情况,一种是还没遍历完字符串时,遇到右括号,栈已经空了,比如:()))))))。还有一种就是遍历结束后栈内还有元素,那就是典型的不匹配了

class Solution {public boolean isValid(String s) {Stack<Character> stack = new Stack<>();if(s==null||s.length()==0){return true;}for (int i = 0; i <s.length() ; i++) {char s1=s.charAt(i);if(s1=='{'||s1=='['||s1=='('){stack.push(s1);}else{if(stack.empty()){//右括号多于左括号return false;}char s2 = stack.pop();//记录出栈的元素if ((s2 == '{' && s1 != '}') || (s2 == '(' && s1 != ')') || (s2 == '[' && s1 != ']')) {return false;}}}return stack.empty();}
}

2.逆波兰表达式求值

逆波兰表达式求值icon-default.png?t=N7T8https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/

思考:观察实例1便能发现运算符写在操作数之后就是这个“逆波兰表达式”,据逆波兰表达式的特性,比如1+2,变成2 1 + ,栈便能解决,比如先将1入栈,2入栈,如果第三次入栈的是运算符号,则将前两次的出栈,然后进行实际的运算,将结果压入栈中。

所以整体符思路就出来了:

1.创建一个栈来存储操作数
2.遍历逆波兰表达式数组的每个元素
3.若当前元素为操作数,则将其压入栈中
4.若当前元素为运算符,则从栈中弹出两个操作数,执行相应的运算,并将结果压入栈中
5.遍历结束后,栈中仅剩下一个元素,即为整个表达式的计算结果

class Solution {public int evalRPN(String[] tokens) {Stack<Integer> stack= new Stack<>();for(int i=0;i<tokens.length;i++){//遍历字符串String temp=tokens[i];if(!isOperation(temp)){Integer val=Integer.valueOf(temp);//类型转化成整型stack.push(val); //不是运算符就入栈          }else{Integer val2 = stack.pop();Integer val1 = stack.pop();//否则弹出两个进行实际的运算switch(temp){//运算符进行匹配case "+":stack.push(val1+val2);break;case "-":stack.push(val1-val2);break;case "*":stack.push(val1*val2);break;case "/":stack.push(val1/val2);break;          }}}return stack.pop();
}
//遍历字符串的过程判断是否遇到运算符
public boolean isOperation(String s){if(s.equals("+")||s.equals("-")||s.equals("*")||s.equals("/")){return true;}else{return false;}
}
}

3.栈的压入,弹出顺序匹配

栈的压入、弹出序列匹配icon-default.png?t=N7T8https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106?tpId=13&&tqId=11174&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

思考:要判断出栈和入栈是否匹配,可以用上辅助栈,将 pushV 中的元素依次入辅助栈,在遍历 pushV 数组的过程中,判断popV数组对应的下标元素是否一样,一样的便出栈,popV遍历下一个,不一样的就pushV 指向下一个元素,直到栈顶元素不再与 popV 数组中对应位置的元素相等或者栈为空为止。最终,如果整个出栈过程符合规则,栈将会为空,此时返回 true;否则,返回 false,配合动图理解更好~

public boolean IsPopOrder (int[] pushV, int[] popV) {if (pushV == null || popV == null || pushV.length != popV.length) {return false;//排除一些常见情况}Stack<Integer> stack = new Stack<>();int j = 0;for (int i = 0; i < pushV.length; i++) {stack.push(pushV[i]);入栈while (j < popV.length && !stack.empty()&&  popV[j] == stack.peek()) {stack.pop();//出栈j++;}}return stack.empty();}
}

4.模拟实现最小栈

最小栈icon-default.png?t=N7T8https://leetcode.cn/problems/min-stack/description/

思路:这道题需要实现最小栈,那这道题单靠一个栈,不太好实现,那我们就定义一个辅助栈,把这个辅助栈当做最小栈,

1.在push 的过程中,如果都是空栈,两个栈都入,如果不是,那显而易见只有最小的才会被存进辅助栈中,于是val值和辅助栈的栈顶比较,只有更小的元素才会存进辅助栈

2.在出栈的过程中,两个栈都要出,只要保证出的是一样的元素即可

3.在获取栈顶元素但不出栈的过程中,只要返回普通栈的即可,因为push的过程中,元素可能不会入辅助栈

4.在获取最小元素的过程中,这是便可直接返回辅助栈的栈顶元素,这也是设置辅助的原因。

配合图片和代码理解效果更佳哦~

class MinStack {public Stack<Integer> stack;public Stack<Integer> minstack;public MinStack() {stack = new Stack<>();minstack = new Stack<>();}public void push(int val) {stack.push(val);if (minstack.empty()) {//第一次入栈minstack.push(val);}else{Integer peekval = minstack.peek();if (val <= peekval) {//只有更小才入栈minstack.push(val);}}}public void pop() {if (stack.empty()) {return;}int popVal = stack.pop();if (popVal == minstack.peek()) {//只要移除的元素和辅助栈的栈顶元素一致就能删minstack.pop();}}public int top() {if (minstack.empty()) {return -1;} else {return stack.peek();}}public int getMin() {if (minstack.empty()) {return -1;} else {return minstack.peek();}}
}

什么是队列?

只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表

咱可以把它理解成排队打饭的过程,进行排队(插入)操作的一端称为队尾, 进行打完饭走人(删除)操作的一端称为队头 ,配合下图就好理解多了~

队列的基本方法有以下几点:

offer()入队
poll()出队并返回出队元素——>就是队头
peek()获取对头元素
size()获取队列的元素个数
isEmpty()判断队列是否为空

咱们上机试试:

import java.util.LinkedList;
import java.util.Queue;public class MyQueue {public static void main(String[] args) {Queue<Integer> queue=new LinkedList<>();//入队列queue.offer(1);queue.offer(2);queue.offer(3);int ret=queue.peek();//获取对头元素System.out.println(ret);System.out.println(queue.size());//获取队列元素个数System.out.println(queue.isEmpty());//判断队列是否为空System.out.println(queue.poll());//出队列}
}

搭配图片就更好理解了:

队列的模拟实现

这里用到的是链式结构去模拟实现,要注意,看下图理解更好~

先定义好一个双向链表

class ListNode{public int val; // 节点的值public ListNode prev; // 前驱节点public ListNode next; // 后继节点// 节点构造函数public ListNode(int val){this.val=val;}}public ListNode head; // 头结点public ListNode last; // 尾结点

offer()入队----类似尾插

public void offer(int val){//尾插ListNode node=new ListNode(val); if(head==null){ head=last=node; // 将新节点作为唯一节点,即头结点和尾结点都指向它}else {last.next = node; // 将尾结点的后继节点指向新节点node.prev = last; // 将新节点的前驱节点指向原尾结点last = last.next; // 更新尾结点为新节点}
}

poll()出队----类似头删

public int poll(){if(head==null){return -1; }int ret=head.val; if(head.next==null){ // 如果头结点后面没有节点,即队列只有一个节点head=null; // 此时就是清空队列}else {head=head.next; // 更新头结点为原头结点的后继节点head.prev=null; // 清空新头结点的前驱节点}return ret; }

peek()-----返回头结点的值即可

public int peek(){if(head==null){ return -1;}return head.val; // 返回头结点的值}

isEmpty()----看头结点空不空

public boolean isEmpty(){return head==null; // 头结点为空表示队列为空}

最后加上一个测试类,看运行结果就模拟实现成功了~

循环队列

那队列用顺序结构实现是什么样呢?-------->就是循环队列

看上面的图解是不是理解了很多?就是卷起来~这样的话就能循环利用数组空间了

那接下来就用数组来模拟实现它吧!

设计循环队列icon-default.png?t=N7T8https://leetcode.cn/problems/design-circular-queue/description/

思考:既然是循环,首尾如何连接呢?这个又是数组,不能像链表一样去改变指向,这时就有一个公式:first=(first+1)%len;这样的走向是远远好于first++的,这样就不用考虑越界的问题了

于是先用数组去定义这个循环队列,定义好首和尾

public class MyCircularQueue {public int[] elem;public int first;public int last;public MyCircularQueue(int k) {elem = new int[k];}

 入队和出队原理是一样的,要考虑循环,所以不能直接++;

    public boolean enQueue(int value) {//入队if (isFull()) {return false;}elem[last] = value;//不为空直接入队last = (last + 1) % elem.length;//更新队尾指针,考虑循环情况return true;}public boolean deQueue() {//出队if (isEmpty()) {return false;}first = (first + 1) % elem.length;//出队就是first移动,道理是一样的return true;}

 队头元素直接获取即可,队尾就要注意了,一般情况下,直接获取下标是last-1的元素即可,因为这里浪费了一个空间,好区分空和满,但如果last刚好指向0,数组下标是没有-1的,所以这里要做判断,如果是last==0,返回的其实是最后一个元素,下标就是len-1的元素

  public int Front() {//获取队头元素if (isEmpty()) {return -1;}return elem[first];}public int Rear() {//获取队尾元素if (isEmpty()) {return -1;}int index = last == 0 ? //要考虑last是否是0elem.length - 1 : last - 1;return elem[index];}

空和满是首先考虑的问题,以浪费一个空间为代价进行区分

// 判断队列是否为空public boolean isEmpty() {return first == last; // 队头指针与队尾指针相等时,队列为空}// 判断队列是否满public boolean isFull() {return (last + 1) % elem.length == first; // 队尾的下一个是队头时,队列为满}

双端队列

直接上图理解效果

双端队列(deque)是一种具有两端插入和删除操作的数据结构,即可以在队列的两端进行插入和删除元素。这种数据结构可以看作是既具备栈的特点,又具备队列的特点

所以双端队列所具备的方法也是二者兼备,可以用链式结构或顺序结构实现都可以哦~

Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现
Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现

使用 ArrayDeque作为线性实现: 

import java.util.Deque;
import java.util.ArrayDeque;public class Main {public static void main(String[] args) {Deque<Integer> stack = new ArrayDeque<>();stack.push(1); stack.push(2);stack.push(3); System.out.println(stack.pop()); // 从栈顶弹出元素System.out.println(stack.peek()); //查看栈顶元素但不弹出}
}

使用 LinkedList 作为链式实现: 

import java.util.Deque;
import java.util.LinkedList;public class Main {public static void main(String[] args) {Deque<Integer> queue = new LinkedList<>();// 在队尾添加元素queue.addLast(1); queue.addLast(2); queue.addLast(3); System.out.println(queue.removeFirst()); //从队头移除元素System.out.println(queue.peekFirst()); //查看队头元素但不移除}
}

栈和队列的相互转化

无论是如何转化,单靠一个是肯定不行的,所以肯定要有辅助栈或队列的

1.用队列模拟实现栈

用队列实现栈icon-default.png?t=N7T8https://leetcode.cn/problems/implement-stack-using-queues/description/

思考:这道题是要咱用队列去模拟实现栈的功能,单单一个队列肯定不行,那就两个。一个做存储元素,一个来辅助。

class MyStack {public Queue<Integer> queue1; // 第一个队列public Queue<Integer> queue2; // 第二个队列public MyStack() {queue1 = new LinkedList<>(); // 初始化第一个队列queue2 = new LinkedList<>(); // 初始化第二个队列}

首先入栈push(),如果两个队列都是空,直接默认放入存储元素的队列即可,而在一般情况下,谁不为空就放谁那里,毕竟不为空就意味着有元素已经放入,直接入即可。

// 将元素压入栈顶public void push(int x) {if(empty()){ // 如果栈为空,直接将元素加入第一个队列queue1.offer(x);}else if (queue2.isEmpty()) { // 如果第二个队列为空,将元素加入第一个队列queue1.offer(x);} else { // 否则将元素加入第二个队列queue2.offer(x);}}

重点看出栈pop(),栈的特性是“先进后出,用队列去模拟实现这个功能,对于要出栈的元素,要把栈中除了最后元素以外的所有元素都弹出到辅助栈中去接收,这段详细解释下~

因为栈出栈只能是栈顶元素,而队列的特性先进先出,于是栈顶元素以下的元素都可以弹出到辅助队列中去,原队列中剩下的最后一个元素便是栈顶元素

当然两个队列都要考虑,哪个是存储元素的,哪个又是辅助的。 

// 弹出栈顶元素并返回public int pop() {if (empty()) {return -1; // 如果栈为空,返回-1}if (!queue1.isEmpty()) {int size = queue1.size();for (int i = 0; i < size - 1; i++) { // 将 queue1 中除最后一个元素外的其他元素转移到 queue2 中queue2.offer(queue1.poll());}return queue1.poll(); // 返回 queue1 中最后一个元素,即为栈顶元素} else {int size = queue2.size();for (int i = 0; i < size - 1; i++) { // 将 queue2 中除最后一个元素外的其他元素转移到 queue1 中queue1.offer(queue2.poll());}return queue2.poll(); // 返回 queue2 中最后一个元素,即为栈顶元素}}

然后是top(),和pop()很类似,但并不移除,道理是一样的,只不过要把所有元素都弹出到辅助队列中去,于是要定义一个变量去存储最后一次弹出元素,那就是栈顶元素

// 返回栈顶元素但不弹出public int top() {if(empty()){return -1; // 如果栈为空,返回-1}int ret = -1;if(!queue1.isEmpty()){int size = queue1.size();for (int i = 0; i < size; i++) {ret = queue1.poll(); // 将 queue1 中的元素逐个转移到 queue2 中,并记录最后一个元素queue2.offer(ret);}return ret; // 返回 queue1 中的最后一个元素,即为栈顶元素} else {int size = queue2.size();for (int i = 0; i < size; i++) {ret = queue2.poll(); // 将 queue2 中的元素逐个转移到 queue1 中,并记录最后一个元素queue1.offer(ret);}return ret; // 返回 queue2 中的最后一个元素,即为栈顶元素}}

最后就是判断是否为空,这个最好写了,只要两个队列都是空,也就代表栈是空

public boolean empty() {return queue1.isEmpty() && queue2.isEmpty();}

2.用栈模拟实现队列

用栈实现队列icon-default.png?t=N7T8https://leetcode.cn/problems/implement-queue-using-stacks/description/

有了第一题的经验,这道题也好写了。模仿着来:

首先定义出两个队列,一个存储元素,一个进行辅助

class MyQueue {public Stack<Integer> stack1; // 栈1public Stack<Integer> stack2; // 栈2public MyQueue() {stack1 = new Stack<>();stack2 = new Stack<>();}

然后是入队offer(),这个直接入存储元素的栈就行,这里就默认是stack1,这里还设置将栈2 的元素倒入栈1,这是为了保证栈1一直都是存储元素的栈:

public void push(int x) {
while (!stack2.isEmpty()) { // 将栈2中的元素倒入栈1stack1.push(stack2.pop());}stack1.push(x); // 将新元素压入栈1}

出队poll():因为其先进先出的特性,用栈模拟的时候弹出就是栈底元素,这个好办,直接把栈1的所有元素都倒入栈2去,然后直接去弹出栈2的栈顶元素,这样就移除成功了,最后别忘了把栈2的元素倒回栈1去,配合图片理解效果更佳~

public int pop() {while (!stack1.isEmpty()) { // 将栈1中的元素倒入栈2stack2.push(stack1.pop());}return stack2.pop(); // 弹出栈2顶部元素}

返回对头元素peek():这个和poll是一样的,只不过用变量接受就好

public int peek() {while (!stack1.isEmpty()) { // 将栈1中的元素倒入栈2stack2.push(stack1.pop());}int peek = stack2.peek(); // 获取栈2顶部元素但不弹出while (!stack2.isEmpty()) { // 将栈2中的元素倒回栈1stack1.push(stack2.pop());}return peek;}

判断是否为空也是一样empty(),直接上代码~

public boolean empty() {return stack1.empty() && stack2.empty();}

这就是本篇文章的全部内容啦~如果觉得有收获的,希望可以点点赞支持下=V=!

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

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

相关文章

Pro版 v3.0首页DIY热区神器,让图片更全能!

Pro版v3.0新增了很多新功能&#xff0c;为了方便大家能快速了解使用&#xff0c;今天&#xff0c;我们就开始来逐步了解这些新功能。 在此次更新中&#xff0c;Pro版的首页DIY功能实现了全新重构升级&#xff0c;新增了DIY热区、视频、排行榜、积分商城、预售、签到组件&#…

【Hadoop技术框架-MapReduce和Yarn的详细描述和部署】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;今天的内容主要是Hadoop的后两个组件&#xff1a;MapReduce和yarn的相关内容。同时还有Hadoop的完整流程。希望对大家有所帮助。感谢大家关注点赞。 &#x1f49e;&#x1f49e;前路漫漫&…

深度学习实战73-基于多模态CLIP模型的实战项目,CLIP模型的架构介绍与代码实现

大家好,我是微学AI,今天给大家介绍一下深度学习实战73-基于多模态CLIP模型的实战项目,CLIP模型的架构介绍与代码实现。多模态CLIP(Contrastive Language-Image Pre-training)模型是一种深度学习模型,其核心设计理念是通过大规模的对比学习训练,实现图像与文本之间的跨模…

【JAVASE】面向对象程序三大特性之一( 封装)

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609;\n &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 目标&#xff1a; 1.包的使用 2.static关键字的使用 3.代码…

Python+Vuecil笔记

Nginx 进入目录: C:\nginx-1.20.2\nginx-1.20.2 start nginx 开始 nginx -s stop 停止 nginx -s quit 退出CSS 通过标签去写css 循环展示数据 JS 点击时执行事件 Django 配置media 在seetings里面修改 STATIC_URL /static/ MEDIA_URL /upload/ MEDIA_ROOT os.pat…

windows terminal美化教程

安装terminal 微软商店下载安装terminal 配置文件 进入terminal&#xff0c;打开设置。 {"$schema": "https://aka.ms/terminal-profiles-schema",// global settings"profiles": {// profile settings"defaults": {// default sett…

阿里云服务器租赁一年收费标准

阿里云服务器租用价格表2024年最新&#xff0c;云服务器ECS经济型e实例2核2G、3M固定带宽99元一年&#xff0c;轻量应用服务器2核2G3M带宽轻量服务器一年61元&#xff0c;ECS u1服务器2核4G5M固定带宽199元一年&#xff0c;2核4G4M带宽轻量服务器一年165元12个月&#xff0c;2核…

【亲测有效】微信公众号设置菜单栏显示,未开启自定义菜单,微信公众平台自定义菜单接口开发

微信公众平台自定义菜单接口开发 问题:运营人员在设置微信公众号设置菜单栏显示,未开启自定义菜单解决方案(微信公众平台自定义菜单接口开发):自定义菜单-创建接口请求链接完整代码第一步:在WeChat类里添加代码情况一:没有WeChat类情况,如果已有请看情况二情况二:已有…

【系统架构师】-软件架构设计

1、软件架构的概念 架构的本质 1、软件架构为软件系统提供了一个结构、行为和属性的高级抽象。 2、软件架构风格是特定应用领域的惯用模式&#xff0c;架构定义一个词汇表和一组约束。 架构的作用 1、软件架构是项目干系人进行交流的手段。 2、软件架构是可传递和可复用的模型…

番茄 短abogus补环境

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01;wx a15018601872 本文章…

端到端单倍型参考基因组揭示了三倍体香芽蕉型香蕉亚基因组的分歧和疾病抵抗力-文献精读-5

T2T基因组文献分享Telomere-to-telomere haplotype-resolved reference genome reveals subgenome divergence and disease resistance in triploid Cavendish banana 三倍体植物基因组的文献&#xff0c;各位同仁还有什么有特色的基因组评论区留言~ 摘要 香蕉是世界上最重要…

JavaEE——手把手教你实现简单的 servlet 项目

文章目录 一、什么是 Servlet二、创建一个简单的 Servlet 程序1. 创建项目2.引入依赖3. 创建目录4.编写代码5. 打包程序6. 部署7.验证整体过程总结 三、使用 Smart Tomcat 插件简化项目创建四、创建项目时可能遇到的几个问题。 一、什么是 Servlet Servlet 是一种实现 动态页面…

12、最小覆盖子串

如何想到这个解法 问题的特点&#xff1a; 首先&#xff0c;认识到这是一个关于子串的问题&#xff0c;而且需要考虑子串的最小长度。这提示我们可能需要使用一种方式来逐步探索不同的子串。滑动窗口的适用性&#xff1a;滑动窗口是处理子串问题的常用技巧&#xff0c;特别是当…

【图像分割】nnUnetV1与V2的Linux部署与应用命令

以前觉得麻烦&#xff0c;一直没用过nnunet&#xff0c;虽然知道它很火&#xff0c;最近一个契机&#xff0c;部署使用了一下nnunet&#xff0c;记录一下其部署和使用的方法与命令。 1、部署 首先&#xff0c;我有一个环境&#xff0c;这个环境可以是以前就有的&#xff0c;也可…

1.c++入门(命名空间、缺省参数、函数重载、引用、内联函数、for循环、auto关键字、指针空值nullptr)

1.c的第一个程序 // 方法一 #include<iostream>// namespace为命名空间的关键字&#xff0c;std为空间名&#xff1b; C标准库的东西放进std命名空间 using namespace std; int main() {cout << "hello world" << endl;return 0; }// 方法二 #in…

YOLOv8的多分类模型如何计算准确率(Accuracy)、精确率(Precision)、召回率(recall)和F1-Score模型评估参数

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

【Linux】 OpenSSH_9.3p1 升级到 OpenSSH_9.6p1(亲测无问题,建议收藏)

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

【leetCode】2810. 故障键盘

文章目录 [2810. 故障键盘](https://leetcode.cn/problems/faulty-keyboard/)思路一&#xff1a;模拟代码&#xff1a;思路二&#xff1a;双端队列代码&#xff1a; 2810. 故障键盘 思路一&#xff1a;模拟 用StringBuilder来拼贴字符遍历字符串&#xff0c;如果遇到i,对拼贴好…

注解,自定义注解和元注解

1.注解 1.1.注解概述、作用 注解&#xff08;Annotation&#xff09;&#xff0c;也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性&#xff0c;与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面&#xff0…

《深入浅出多模态》:多模态经典模型CLIP

🎉AI学习星球推荐: GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料,配有全面而有深度的专栏内容,包括不限于 前沿论文解读、资料共享、行业最新动态以、实践教程、求职…