数据结构和算法-栈
数据结构和算法-栈
1. 栈的介绍
栈的介绍:
- 栈的英文为(stack)
- 栈是一个先入后出的有序列表
- 栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶,另一端为固定的一端,称为栈底。
- 根据栈的定义可知,最先放入栈中元素的栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除。
- 出栈(POP)和入栈(PUSH)的概念
==注意:==栈和上次介绍的队列是不同的
- 栈的栈底是固定的,先入后出。一个指针
- 而队列的首尾都是不固定的,先入先出。两个指针
2. 栈的应用场景
- 子程序的调用:在跳往子程序前,会先将下个指令的地址存到堆栈中,直到子程序执行完后再将地址取出,以回到原来的程序中。
- 处理递归调用:和子程序的调用类似,只是除了存储下一个指令的地址外,也将参数、区域变量等数据存入堆栈中。
- 表达式的转换[中缀表达式转后缀表达式]与求值(实际解决)。
- 二叉树的遍历
- 图形的深度优先(depth-first)搜索法。
3. 栈的快速入门
3.1 用数组模拟栈
用数组模拟栈的使用,由于栈是一种有序列表,可以使用数组的结构来存储栈的数据内容。下面用数组模拟栈的出栈、入栈等操作
实现栈的思路分析
- 使用栈的思路分析
- 定义一个top来表示栈顶,初始化为-1
- 入栈的操作,当有数据加入到栈时,top++;stack[top]=data;
- 出栈的操作,int value = stack[top];top–;return value;
韩老师代码如下
//定义一个ArrayStack 表示栈
class ArrayStack {private int maxSize; //栈的大小private int[] stack; //数组 数组模拟栈 数据就放在该数组private int top = -1; //top表示栈顶 初始化为-1 arr[top] 是栈的最后一个有效数据public ArrayStack(int maxSize) {this.maxSize = maxSize;stack = new int[maxSize];}//栈满public boolean isFull() {return top == maxSize - 1;}//栈空public boolean isEmpty() {return top == -1;}//入栈-pushpublic void push(int value) {//先判断是否满if (isFull()) {System.out.println("栈满");return;}stack[++top] = value;}//出栈-pop 将栈顶的数据返回public int pop() {//先判断栈是否空if (isEmpty()) {//抛出异常处理throw new RuntimeException("栈为空");}return stack[top--];}//显示栈的情况 遍历时 需要从栈顶开始显示public void list() {//先判断栈是否空if (isEmpty()) {//抛出异常处理throw new RuntimeException("栈为空");}for (int i = top; i >= 0; i--) {System.out.println(stack[i]);}}
}
3.2 课堂作业-用链表模拟栈
自己写的代码如下
//无头结点的单链表模拟栈
class ListStack {private final int maxSize; //栈的最大容量private Node list = new Node(0); //栈的第一个存储空间private int top = -1; //指向栈顶public ListStack(int maxSize) {//maxSize 最大容量this.maxSize = maxSize;Node temp = list;for (int i = 1; i < maxSize; i++) {temp.setNext(new Node(i)); //将上一个节点连接新节点temp = temp.getNext(); //将temp指向新节点(链表的最后一个节点)}}//判断栈是否满了public boolean isFull() {return top == maxSize - 1;}//判断栈是否为空public boolean isEmpty() {return top == -1;}//入栈public void push(int value) {if (isFull()) { //如果满了System.out.println("满了兄弟");return;//退出函数}Node temp = list;++top;while (temp.getNo() != top) {//当找到时退出循环temp = temp.getNext();}//当退出循环时 temp就是目标temp.setValue(value);}//出栈-pop 将栈顶的数据返回public int pop(){if (isEmpty()){ //说明为空throw new RuntimeException("空了");}Node temp = list;while (temp.getNo() != top) {//当找到时退出循环temp = temp.getNext();}top--;return temp.getValue();}//显示栈的情况 遍历时 需要从栈顶开始显示public void show(){if (isEmpty()){ //说明为空System.out.println("空的");}for (int i = 0; i < top + 1; i++) {Node temp = list;for (int j = 0; j < top - i; j++) {temp = temp.getNext();}System.out.println(temp.getValue());}}
}//单链表的节点
class Node {private int no; //编号private int value; //保存的值private Node next; //next域public Node(int no) {this.no = no;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public int getValue() {return value;}public void setValue(int value) {this.value = value;}public Node getNext() {return next;}public void setNext(Node next) {this.next = next;}@Overridepublic String toString() {return "Node{" +"no=" + no +", value=" + value +", next=" + ((next == null) ? "null" : next.hashCode()) +'}';}
}
看到弹幕说有直接头插法,试了一下,发现确实更好
//有头结点的单链表模拟栈
class ListStack2 {private final int maxSize; //栈的最大容量private Node2 head = new Node2(); //头节点private int top = -1; //指向栈顶public ListStack2(int maxSize) {this.maxSize = maxSize;}//判断栈是否满了public boolean isFull() {return top == maxSize - 1;}//判断栈是否为空public boolean isEmpty() {return top == -1;}//入栈public void push(int value) {if (isFull()) { //如果满了System.out.println("满了兄弟");return;//退出函数}Node2 temp = new Node2(value);//创建新节点//将此节点插入到头节点和旧的第一个节点中 成为新的第一个节点(栈顶)temp.setNext(head.getNext());head.setNext(temp);top++;//计数加一}//出栈-pop 将栈顶的数据返回public int pop() {if (isEmpty()) { //说明为空throw new RuntimeException("空了");}top--; //计数减一int value = head.getNext().getValue(); //得到返回值//将第一个节点从链表中删除head.setNext(head.getNext().getNext()); //将头节点的next指向第二个节点 作为新的第一个节点return value;}//显示栈的情况 遍历时 需要从栈顶开始显示public void show() {if (isEmpty()) { //说明为空System.out.println("空的");return;}Node2 temp = head.getNext();while (temp != null) {//遍历完所有节点System.out.println(temp.getValue());temp = temp.getNext();//节点后移}}
}//单链表的节点
class Node2 {private int value; //保存的值private Node2 next; //next域public Node2(int value) {this.value = value;}public Node2() {}public int getValue() {return value;}public void setValue(int value) {this.value = value;}public Node2 getNext() {return next;}public void setNext(Node2 next) {this.next = next;}
}
4. 栈实现综合计算器
使用栈完成表达式的计算思路
- 通过一个index值(索引),来遍历我们的表达式
- 如果我们发现是一个数字,就直接入数栈
- 如果发现扫描到是一个符号,就分如下情况
- 如果发现当前的符号栈为空,就直接入栈
- 如果符号栈有操作符,就进行比较,如果当前的操作符的优先级小于或者等于栈中的操作符,就需要从数栈中pop出两个数,在从符号栈中pop出一个符号,进行运算,将得到结果,入数栈,然后将当前的操作符入符号栈,如果当前的操作符的优先级大于栈中的操作符,就直接入符号栈.
- 当表达式扫描完毕,就顺序的从数栈和符号栈中pop出相的数和符号,并运行.
- 最后在数栈只有一个数字,就是表达式的结果
自己写的多位数代码如下
package com.atguigu.stack;/*** @author 小小低头哥* @version 1.0*/public class Calculator {public static void main(String[] args) {//根据前面思路 完成表达式的运算
// String expression = "2+2*3-2*1-1+2-3-2-3";
// String expression = "2+3+1-4-3-2+2*20*450/50+6+4-3-4-2*2";String expression = "30*2-6*9+1";//创建两个栈 数栈、符号栈ArrayStack2 numStack = new ArrayStack2(30);ArrayStack2 operStack = new ArrayStack2(50);//定义需要的相关变量int index = 0; //用于扫描int num1 = 0;int num2 = 0;int oper = 0;int res = 0;char ch = ' '; //将每次扫描得到char保存到chint count = 0; //计数器 记录是几位数 放在符号栈的符号中//开始while循环的扫描expressionwhile (true) {//依次得到expression的每一个字符ch = expression.substring(index, index + 1).charAt(0);//判断ch是什么 然后做出相应的处理if (operStack.isOper(ch)) { //如果是运算符//判断当前的符号栈是否为空if (!operStack.isEmpty()) { //不为空则一个个判断operStack.push(count); //先放进去//if (operStack.priority(ch) < operStack.priority(operStack.peek()))while (operStack.priority(ch) < operStack.priority(operStack.peek())) {//下面num1、oper、num2弹出的顺序不能变num1 = numStack.popN(operStack.pop()); //得到符号位前面的整数 并弹出符号栈中对应的数字标志oper = operStack.pop(); //出栈num2 = numStack.popN(operStack.pop());res = numStack.cal(num1, num2, oper);//把运算的结果放入数栈numStack.push(res);count = 1;if (!operStack.isEmpty()) { //说明前面没有运算符了 自然也不需要更新了operStack.pop(); //把前一个运算符后面的数字位数去掉 因为此时已经变成res了 由于res是一个整体 所以相当于count=1operStack.push(count); //更新前一个运算符后面的数字位数}else {break;}}}//为空或者判断完毕后 把当前符号入符号栈operStack.push(count); //把符号前面的数是几位数记录下来 并放在ch的前面operStack.push(ch);count = 0; //重新置零} else {//如果是数 则直接入数栈count++; //数字数加一numStack.push(ch - 48); //转换为数字}//让index + 1 ,并判断是否扫描到expression最后index++;if (index >= expression.length()) { //扫描结束operStack.push(count); //扫描结束最后一个肯定是数字 需要把此数字的位数压入到符号栈break;}}while (true) {//下面num1、oper、num2弹出的顺序不能变num1 = numStack.popN(operStack.pop()); //得到符号位前面的整数 并弹出符号栈中对应的数字标志oper = operStack.pop(); //出栈num2 = numStack.popN(operStack.pop());if (!operStack.isEmpty() && oper == '-' && operStack.peek() == '-') { //如果此时的操作符和上一个操作符都是负号//那么说明此时不是相减 而是相加res = numStack.cal(num1, num2, '+');} else if (!operStack.isEmpty() && oper == '+' && operStack.peek() == '-') { //则应是num2-num1res = numStack.cal(num1, num2, '-');} else {res = numStack.cal(num1, num2, oper);}numStack.push(res); //入栈//如果符号栈为空 则计算到最后的结果,数栈中只有一个数字if (operStack.isEmpty()) {break;}operStack.pop(); //把前一个运算符后面的数字位数去掉 因为此时已经变成res了operStack.push(1); //更新前一个运算符后面的数字位数}System.out.println(expression + "表达式的结果是:" + numStack.pop());}
}//先定义一个栈 直接使用前面创建好
//定义一个ArrayStack表示栈class ArrayStack2 {private int maxSize; //栈的大小private int[] stack; //数组 数组模拟栈 数据就放在该数组private int top = -1; //top表示栈顶 初始化为-1 arr[top] 是栈的最后一个有效数据public ArrayStack2(int maxSize) {this.maxSize = maxSize;stack = new int[maxSize];}//栈满public boolean isFull() {return top == maxSize - 1;}//栈空public boolean isEmpty() {return top == -1;}//入栈-pushpublic void push(int value) {//先判断是否满if (isFull()) {System.out.println("栈满");return;}stack[++top] = value;}//出栈 连续出栈几个并组成数字 为数栈准备public int popN(int n) {int res = 0;for (int i = 0; i < n; i++) {if (i == 0) {res = res + pop();} else {res = res + pop() * (int) Math.pow(10, i); //从个位、十位等依次入手}}return res;}//出栈-pop 将栈顶的数据返回public int pop() {//先判断栈是否空if (isEmpty()) {//抛出异常处理throw new RuntimeException("栈为空");}return stack[top--];}//显示栈的情况 遍历时 需要从栈顶开始显示public void list() {//先判断栈是否空if (isEmpty()) {//抛出异常处理throw new RuntimeException("栈为空");}for (int i = top; i >= 0; i--) {System.out.println(stack[i]);}}//返回运算符的优先级 优先级是程序员确定的 优先级使用数组表示//数字越大 则优先级越高public int priority(int oper) {if (oper == '*' || oper == '/') {return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1; //假定目前表达式只有加减乘除}}//增加一个方法 可以返回当前栈顶的值 但是不是真正的poppublic int peek() {return stack[top - 1];}//判断是不是一个运算符public boolean isOper(char val) {return val == '+' || val == '-' || val == '*' || val == '/';}//计算方法public int cal(int num1, int num2, int oper) {int res = 0; //res用于存放计算的结果switch (oper) {case '+':res = num1 + num2;break;case '-':res = num2 - num1; //注意顺序break;case '*':res = num1 * num2;break;case '/':res = num2 / num1;break;default:break;}return res;}}
韩老师写的多位数代码如下
package com.atguigu.stack;/*** @author 小小低头哥* @version 1.0*/
public class Calculator2 {public static void main(String[] args) {//根据前面思路 完成表达式的运算String expression = "30*2-6*9+1";//创建两个栈 数栈、符号栈ArrayStack2 numStack = new ArrayStack2(10);ArrayStack2 operStack = new ArrayStack2(10);//定义需要的相关变量int index = 0; //用于扫描int num1 = 0;int num2 = 0;int oper = 0;int res = 0;char ch = ' '; //将每次扫描得到char保存到chString keepNum = ""; //用于拼接多位数//开始while循环的扫描expressionwhile (true) {//依次得到expression的每一个字符ch = expression.substring(index, index + 1).charAt(0);//判断ch是什么 然后做出相应的处理if (operStack.isOper(ch)) { //如果是运算符//判断当前的符号栈是否为空if (!operStack.isEmpty()) { //不为空则一个个判断if (operStack.priority(ch) <= operStack.priority(operStack.peek())) {num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop(); //出栈res = numStack.cal(num1, num2, oper);//把运算的结果放入数栈numStack.push(res);operStack.push(ch);} else {operStack.push(ch);}} else {operStack.push(ch);}} else {//如果是数 则直接入数栈//分析思路//1. 当处理多位数时 不能发现一个数就立即入栈 因为可能是多位数//2. 在处理数,需要翔expression的表达式的index后再看一位 如果是数就进行扫描 如果是符号才入栈//3. 因此需要定义一个变量 用于拼接//处理多位数keepNum += ch;//如果ch已经是expression的最后一位 就直接入栈if (index == expression.length() - 1) {numStack.push(Integer.parseInt(keepNum));} else {//判断下一个字符是不是数字 如果是数字 就继续扫描 如果是运算符 则入栈//注意看后一位 不是index++if (operStack.isOper(expression.substring(index + 1, index + 2).charAt(0))) {//如果后一位是运算符 则入栈numStack.push(Integer.parseInt(keepNum));keepNum = ""; //清空!!}}}//让index + 1 ,并判断是否扫描到expression最后index++;if (index >= expression.length()) { //扫描结束break;}}while (true) {//如果符号栈为空 则计算到最后的结果,数栈中只有一个数字if (operStack.isEmpty()) {break;}num1 = numStack.pop();num2 = numStack.pop();oper = operStack.pop(); //出栈res = numStack.cal(num1, num2, oper);numStack.push(res); //入栈}System.out.println(expression + "表达式的结果是:" + numStack.pop());}
}//先定义一个栈 直接使用前面创建好
//定义一个ArrayStack表示栈class ArrayStack2 {private int maxSize; //栈的大小private int[] stack; //数组 数组模拟栈 数据就放在该数组private int top = -1; //top表示栈顶 初始化为-1 arr[top] 是栈的最后一个有效数据public ArrayStack2(int maxSize) {this.maxSize = maxSize;stack = new int[maxSize];}//栈满public boolean isFull() {return top == maxSize - 1;}//栈空public boolean isEmpty() {return top == -1;}//入栈-pushpublic void push(int value) {//先判断是否满if (isFull()) {System.out.println("栈满");return;}stack[++top] = value;}//出栈-pop 将栈顶的数据返回public int pop() {//先判断栈是否空if (isEmpty()) {//抛出异常处理throw new RuntimeException("栈为空");}return stack[top--];}//显示栈的情况 遍历时 需要从栈顶开始显示public void list() {//先判断栈是否空if (isEmpty()) {//抛出异常处理throw new RuntimeException("栈为空");}for (int i = top; i >= 0; i--) {System.out.println(stack[i]);}}//返回运算符的优先级 优先级是程序员确定的 优先级使用数组表示//数字越大 则优先级越高public int priority(int oper) {if (oper == '*' || oper == '/') {return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1; //假定目前表达式只有加减乘除}}//增加一个方法 可以返回当前栈顶的值 但是不是真正的poppublic int peek() {return stack[top];}//判断是不是一个运算符public boolean isOper(char val) {return val == '+' || val == '-' || val == '*' || val == '/';}//计算方法public int cal(int num1, int num2, int oper) {int res = 0; //res用于存放计算的结果switch (oper) {case '+':res = num1 + num2;break;case '-':res = num2 - num1; //注意顺序break;case '*':res = num1 * num2;break;case '/':res = num2 / num1;break;default:break;}return res;}}
4.1 课堂作业-加入小括号
在前面的基础上加上了判断小括号的功能,觉得还行 不过没加入判断负数的功能
package com.atguigu.stack;/*** @author 小小低头哥* @version 1.0*/public class Calculator {public static void main(String[] args) {//根据前面思路 完成表达式的运算
// String expression = "2+2*3-2*1-1+2-3-2-3";
// String expression = "2+3+1-4-3-2+2*20*450/50+6+4-3-4-2*2";String expression = "30*2-(6*9)-(1+5*4)+(4*6)";//创建两个栈 数栈、符号栈ArrayStack2 numStack = new ArrayStack2(30);ArrayStack2 operStack = new ArrayStack2(50);//定义需要的相关变量int index = 0; //用于扫描int num1 = 0;int num2 = 0;int oper = 0;int res = 0;char ch = ' '; //将每次扫描得到char保存到chint count = 0; //计数器 记录是几位数 放在符号栈的符号中boolean flag = false; //flag为真时 说明接收到了左、右括号 且还没有接收到符号位//开始while循环的扫描expressionwhile (true) {//依次得到expression的每一个字符ch = expression.substring(index, index + 1).charAt(0);//判断ch是什么 然后做出相应的处理if (operStack.isOper(ch)) { //如果是运算符//判断当前的符号栈是否为空if (!operStack.isEmpty()) { //不为空则一个个判断if (!flag) {//如果上一个是 ( 则不用放进去operStack.push(count); //先放进去}flag = false;//if (operStack.priority(ch) < operStack.priority(operStack.peek()))while (operStack.priority(ch) < operStack.priority(operStack.peek(1))) {//0的优先权最小 不会进入循环 正要如此//下面num1、oper、num2弹出的顺序不能变num1 = numStack.popN(operStack.pop()); //得到符号位前面的整数 并弹出符号栈中对应的数字标志oper = operStack.pop(); //出栈num2 = numStack.popN(operStack.pop());res = numStack.cal(num1, num2, oper);//把运算的结果放入数栈numStack.push(res);count = 1;//前面还有运算符了 需要更新 或者计算完括号中的数if (!operStack.isEmpty() && operStack.peek(0) != 0) {operStack.pop(); //把前一个运算符后面的数字位数去掉 因为此时已经变成res了 由于res是一个整体 所以相当于count=1operStack.push(count); //更新前一个运算符后面的数字位数} else {break;}}}//为空或者判断完毕后 把当前符号入符号栈operStack.push(count); //把符号前面的数是几位数记录下来 并放在ch的前面operStack.push(ch);count = 0; //重新置零} else if (ch == '(') { //按数学规矩 (的前面一个肯定是运算符flag = true;operStack.push(0); //把零送进去当作是起点} else if (ch == ')') {flag = true;operStack.push(count); //)前必然是数字 所以这里先送进去一个计数器while (true) {//说明还没计算完括号内的运算//下面num1、oper、num2弹出的顺序不能变num1 = numStack.popN(operStack.pop()); //得到符号位前面的整数 并弹出符号栈中对应的数字标志oper = operStack.pop(); //出栈num2 = numStack.popN(operStack.pop());if (operStack.peek(0)!= 0 && oper == '-' && operStack.peek(1) == '-') { //如果此时的操作符和上一个操作符都是负号//那么说明此时不是相减 而是相加res = numStack.cal(num1, num2, '+');} else if (operStack.peek(0)!= 0 && oper == '+' && operStack.peek(1) == '-') { //则应是num2-num1res = numStack.cal(num1, num2, '-');} else {res = numStack.cal(num1, num2, oper);}numStack.push(res); //入栈//如果括号中的数计算完毕if (operStack.peek(0) == 0) {operStack.pop(); //把标志位给弹出来operStack.push(1); //因为()的结果是一个整数 所以把1送进去作为()整体的数的个数break;}operStack.pop(); //把前一个运算符后面的数字位数去掉 因为此时已经变成res了operStack.push(1); //更新前一个运算符后面的数字位数}} else {//如果是数 则直接入数栈count++; //数字数加一numStack.push(ch - 48); //转换为数字}//让index + 1 ,并判断是否扫描到expression最后index++;if (index >= expression.length() ) { //扫描结束//扫描结束最后一个肯定是数字 需要把此数字的位数压入到符号栈if( ch != ')'){ //但是如果最后是以)结束 则由于括号计算中已经把1插进去了 不需要了operStack.push(count);}break;}}while (true) {//下面num1、oper、num2弹出的顺序不能变num1 = numStack.popN(operStack.pop()); //得到符号位前面的整数 并弹出符号栈中对应的数字标志oper = operStack.pop(); //出栈num2 = numStack.popN(operStack.pop());if (!operStack.isEmpty() && oper == '-' && operStack.peek(1) == '-') { //如果此时的操作符和上一个操作符都是负号//那么说明此时不是相减 而是相加res = numStack.cal(num1, num2, '+');} else if (!operStack.isEmpty() && oper == '+' && operStack.peek(1) == '-') { //则应是num2-num1res = numStack.cal(num1, num2, '-');} else {res = numStack.cal(num1, num2, oper);}numStack.push(res); //入栈//如果符号栈为空 则计算到最后的结果,数栈中只有一个数字if (operStack.isEmpty()) {break;}operStack.pop(); //把前一个运算符后面的数字位数去掉 因为此时已经变成res了operStack.push(1); //更新前一个运算符后面的数字位数}System.out.println(expression + "表达式的结果是:" + numStack.pop());}
}//先定义一个栈 直接使用前面创建好
//定义一个ArrayStack表示栈class ArrayStack2 {private int maxSize; //栈的大小private int[] stack; //数组 数组模拟栈 数据就放在该数组private int top = -1; //top表示栈顶 初始化为-1 arr[top] 是栈的最后一个有效数据public ArrayStack2(int maxSize) {this.maxSize = maxSize;stack = new int[maxSize];}//栈满public boolean isFull() {return top == maxSize - 1;}//栈空public boolean isEmpty() {return top == -1;}//入栈-pushpublic void push(int value) {//先判断是否满if (isFull()) {System.out.println("栈满");return;}stack[++top] = value;}//出栈 连续出栈几个并组成数字 为数栈准备public int popN(int n) {int res = 0;for (int i = 0; i < n; i++) {if (i == 0) {res = res + pop();} else {res = res + pop() * (int) Math.pow(10, i); //从个位、十位等依次入手}}return res;}//出栈-pop 将栈顶的数据返回public int pop() {//先判断栈是否空if (isEmpty()) {//抛出异常处理throw new RuntimeException("栈为空");}return stack[top--];}//显示栈的情况 遍历时 需要从栈顶开始显示public void list() {//先判断栈是否空if (isEmpty()) {//抛出异常处理throw new RuntimeException("栈为空");}for (int i = top; i >= 0; i--) {System.out.println(stack[i]);}}//返回运算符的优先级 优先级是程序员确定的 优先级使用数组表示//数字越大 则优先级越高public int priority(int oper) {if (oper == '*' || oper == '/') {return 1;} else if (oper == '+' || oper == '-') {return 0;} else {return -1; //假定目前表达式只有加减乘除}}//增加一个方法 可以返回当前栈顶的第n个值 但是不是真正的poppublic int peek(int n) {return stack[top - n];}//判断是不是一个运算符public boolean isOper(char val) {return val == '+' || val == '-' || val == '*' || val == '/';}//计算方法public int cal(int num1, int num2, int oper) {int res = 0; //res用于存放计算的结果switch (oper) {case '+':res = num1 + num2;break;case '-':res = num2 - num1; //注意顺序break;case '*':res = num1 * num2;break;case '/':res = num2 / num1;break;default:break;}return res;}}
相关文章:

数据结构和算法-栈
数据结构和算法-栈 1. 栈的介绍 栈的介绍: 栈的英文为(stack)栈是一个先入后出的有序列表栈是限制线性表中元素的插入和删除只能在线性表的同一端进行的一种特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶,另一端为固…...

C#基础与进阶扩展合集-进阶篇(持续更新)
目录 本文分两篇,基础篇点击:C#基础与进阶扩展合集-基础篇 一、进阶 1、Predicate 2、设置C#语言版本 3、ListCollectionView过滤集合 4、值类型与引用类型 5、程序设置当前项目工作目录 6、获取App.config配置文件中的值 7、Linq常用语句 8、…...

快速入门GitHub 之超简单的注册方法和超好用的使用技巧
最近几天发现有些人对Github网站很好奇,但是无奈自己不会用,因为是外国人的网站,首先自己的英文就不过关。对于这个,其实可以用谷歌浏览器去浏览Github,它有一键翻译的功能。但还是有必要介绍一下关于Github的一些功能和具体操作,初学编程语言的小伙伴们一定对 GitHub 有…...

ESP32-Web-Server编程- 在 Web 上开发动态纪念册
ESP32-Web-Server编程- 在 Web 上开发动态纪念册 概述 Web 有很多有趣的玩法,在打开网页的同时送她一个惊喜。 需求及功能解析 本节演示在 ESP32 上部署一个 Web,当打开对应的网页时,将运行动态的网页内容,显示炫酷的纪念贺词…...

双向ESD保护 汽车级TVS二极管 ESD9B3.3ST5G工作原理、特性参数、封装形式
什么是汽车级TVS二极管? TVS二极管是一种用于保护电子电路的电子元件。它主要用于电路中的过电压保护,防止电压过高而损坏其他部件。TVS二极管通常被称为“汽车级”是因为它们能够满足汽车电子系统的特殊要求。 在汽车电子系统中,由于车辆启…...

Ribbon-IRule 修改负载均衡的规则
1、负载均衡规则描述 (1)整体关系 (2)规则描述 内置负载均衡规则类规则描述RoundRobinRule简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。AvailabilityFilteringRule对以下两种服务器进行忽略: (1)在默认情况下&…...

双十二电视盒子哪个牌子最好?自费3000+测评整理电视盒子推荐
双十二不知道电视盒子哪个牌子最好的新手很多,想要我分享电视盒子推荐,为结果更客观我花费三千多购入了十几款热销电视盒子,通过一个月时间的全面对比测评后整理了电视盒子推荐,给双十二不知道怎么选电视盒子的朋友们提供参考。 一…...

排序:直接选择排序
直接选择排序: 本质: 直接选择排序的本质就是在数组中进行遍历挑选出最大的元素,讲最大的元素放到对应的位置后,再次选出次大的位置,而后又放到对应的位置..........................直到数组成为一个有序序列。 优…...

Nacos多数据源插件
Nacos从2.2.0版本开始,可通过SPI机制注入多数据源实现插件,并在引入对应数据源实现后,便可在Nacos启动时通过读取application.properties配置文件中spring.datasource.platform配置项选择加载对应多数据源插件.本文档详细介绍一个多数据源插件如何实现以及如何使其生效。 注意:…...

【Java基础篇 | 面向对象】—— 聊聊什么是接口(上篇)
个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得,欢迎大家在评论区交流讨论💌 关于接口的简单的介绍…...

golang实现函数yamlToStruct(infile,outFile)
问: golang实现函数yamlToStruct(infile,outFile),将yaml文件格式化成golang的结构体 gpt: 要实现一个将YAML文件格式化成Golang结构体的函数,你可以使用 yaml 和 reflect 包来处理。首先,你需要使用 yaml.Unmarshal 函数将YAML文件解析为一…...

产品成本收集器流程演示
感谢大佬的文章,我只是一个翻译搬运工,原文地址:产品成本收集器 概述 SAP 令人兴奋的部分之一是它在不同操作模块之间的集成程度。使用产品成本收集器来跟踪生产就是一个很好的例子。在本博客中,我计划遵循产品成本收集器流程&a…...

【微服务】springboot整合quartz使用详解
目录 一、前言 二、quartz介绍 2.1 quartz概述 2.2 quartz优缺点 2.3 quartz核心概念 2.3.1 Scheduler 2.3.2 Trigger 2.3.3 Job 2.3.4 JobDetail 2.4 Quartz作业存储类型 2.5 适用场景 三、Cron表达式 3.1 Cron表达式语法 3.2 Cron表达式各元素说明 3.3 Cron表达…...

Electron+Ts+Vue+Vite桌面应用系列:TypeScript常用时间处理工具
文章目录 1️⃣ 时间处理工具1.1 格式化时间1.2 把时间戳改成日期格式1.3 Day.js 工具类使用1.4 date-fns 工具类使用 优质资源分享 作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_43151418/article/details/134712978 ElectronTsVueVite桌面应用…...

记录 | centos源码编译bazel
tensorflow的源码编译依赖于 bazel 这里进行 bazel 的源码编译 1、安装依赖 sudo yum install -y java-11-openjdk sudo yum install -y java-11-openjdk-devel sudo yum install -y protobuf-compiler zip unzip2、知悉要安装的 bazel 的版本 务必安装受支持的 Bazel 版本…...

常见的Bean工厂后置处理器
此代码在jdk11上测试通过,SpringBoot版本为2.7.14 1.上代码 导入坐标 <dependencies><!-- spring数据坐标 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-rest</art…...

代码随想录算法训练营第四十二天| 416 分割等和子集
目录 416 分割等和子集 416 分割等和子集 class Solution { public:const int N 210;bool canPartition(vector<int>& nums) {vector<int>f(N);int sum 0;for(auto num : nums)sum num;if(sum % 2 1)return false;//如果int target sum / 2;for(int i …...

memmove 和 memcpy的区别
函数原型及作用 memcpy 和 memmove 都是C语言中的库函数,在头文件string.h中,作用是拷贝一定长度的内存的内容,原型分别如下: void* memcpy(void *dst, const void *src, size_t count); void* memmove(void *dst, const void *…...

C实现的双向链表队列
如下代码所示,一个头文件实现的双向链表,用c代码实现: #ifndef _LINUX_LIST_H #define _LINUX_LIST_H#include "stddef.h" #include "poison.h"#ifndef ARCH_HAS_PREFETCH #define ARCH_HAS_PREFETCH static inline voi…...

自适应中值滤波器的python代码实现-----冈萨雷斯数字图像处理
基本原理: 自适应中值滤波器是一种图像处理技术,用于去除图像中的噪声。其原理是根据像素周围邻域内像素值的特性,动态地选择滤波器的大小和中值滤波的程度。 **邻域选择:**对于每个像素点,选取一个窗口或者邻域&…...

Python作业答疑_6.22~6.25
一、Python 一班 1. 基数分割列表 1.1 问题描述 给定一无序数列,把数列的第一个数字当成基数,让数列中基数小的数字排在数列前面,比基数大的数字排在数列的后面。 1.2 问题示例 如数列:num[4,1,8,3,9,2,10,7]。基数为 4&…...

Uber Go 语言编码规范
uber-go/guide 的中文翻译 English 文档链接 Uber Go 语言编码规范 Uber 是一家美国硅谷的科技公司,也是 Go 语言的早期 adopter。其开源了很多 golang 项目,诸如被 Gopher 圈熟知的 zap、jaeger 等。2018 年年末 Uber 将内部的 Go 风格规范 开源到 G…...

UniRepLKNet:用于音频、视频、点云、时间序列和图像识别的通用感知大内核ConvNet
摘要 https://arxiv.org/abs/2311.15599 大核卷积神经网络(ConvNets)最近受到了广泛的研究关注,但存在两个未解决的关键问题需要进一步研究。(1)现有大核ConvNets的架构在很大程度上遵循传统ConvNets或Transformers的设计原则,而大核ConvNets的架构设计仍未得到充分解决。(2…...

Http协议与Tomcat
HTTP协议 HTTP协议(HyperText Transfer Protocol)即超文本传输协议 ,是TCP/IC网络体系结构应用层的一个客户端-服务端协议,是所有客户端,服务端数据传输的基石(数据传输规则) 特点 ⭐基于TCP协…...

Spring AOP从入门到精通
目录 1. AOP的演化过程 1. 代理模式 2. 动态代理 2.1 JDK动态代理 2.2 Cglib动态代理 3. Spring模式 3.1 ProxyFactory 3.2 ProxyFactoryBean 3.3 AbstractAutoProxyCreator 2. Spring AOP抽象 1. 核心术语 1.1 连接点(JoinPoint) 1.2 切点(Pointcut) 1.3 增强(Ad…...

Tap虚拟网卡
1 概述 Tap设备通常用于虚拟化场景下,其驱动代码位于drivers/net/tun.c,tap与tun复用大部分代码, 注:drivers/net/tap.c并不是tap设备的代码,而是macvtap和ipvtap; 下文中,我们统一称tap&#…...

【数电笔记】53-与非门构成的基本RS触发器
目录 说明: 1. 电路组成 2. 逻辑功能 3. 特性表 4. 特性方程 5. 状态转换图 6. 驱动表 7. 例题 例1 例2 说明: 笔记配套视频来源:B站;本系列笔记并未记录所有章节,只对个人认为重要章节做了笔记;…...

kubernetes(k8s)容器内无法连接同所绑定的Service ClusterIP问题记录
kubernetes(k8s)容器内无法连接同所绑定的Service ClusterIP问题记录 1. k8s环境 k8s使用kubernetes-server-linux-amd64_1.19.10.tar.gz 二进制bin 的方式手动部署 k8s 版本: [rootmaster ~]# kubectl version Client Version: version.Info{Major:"1", Minor:&…...

Hadoop入门学习笔记
视频课程地址:https://www.bilibili.com/video/BV1WY4y197g7 课程资料链接:https://pan.baidu.com/s/15KpnWeKpvExpKmOC8xjmtQ?pwd5ay8 这里写目录标题 一、VMware准备Linux虚拟机1.1. VMware安装Linux虚拟机1.1.1. 修改虚拟机子网IP和网关1.1.2. 安装…...

堆栈,BSS,DATA,TEXT
一、目标文件 首先目标文件的构成,Linux下就是.o 文件 编译器编译源码后生成的文件叫目标文件(Object File)。 目标文件和可执行文件一般采用同一种格式,这种存储格式为 ELF。 目前文件的内容至少有编译后的机器指令代码和数据&a…...