数据结构和算法-栈
数据结构和算法-栈
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代码实现-----冈萨雷斯数字图像处理
基本原理: 自适应中值滤波器是一种图像处理技术,用于去除图像中的噪声。其原理是根据像素周围邻域内像素值的特性,动态地选择滤波器的大小和中值滤波的程度。 **邻域选择:**对于每个像素点,选取一个窗口或者邻域&…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...

CSS3相关知识点
CSS3相关知识点 CSS3私有前缀私有前缀私有前缀存在的意义常见浏览器的私有前缀 CSS3基本语法CSS3 新增长度单位CSS3 新增颜色设置方式CSS3 新增选择器CSS3 新增盒模型相关属性box-sizing 怪异盒模型resize调整盒子大小box-shadow 盒子阴影opacity 不透明度 CSS3 新增背景属性ba…...

Xcode 16 集成 cocoapods 报错
基于 Xcode 16 新建工程项目,集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...

Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...
StarRocks 全面向量化执行引擎深度解析
StarRocks 全面向量化执行引擎深度解析 StarRocks 的向量化执行引擎是其高性能的核心设计,相比传统行式处理引擎(如MySQL),性能可提升 5-10倍。以下是分层拆解: 1. 向量化 vs 传统行式处理 维度行式处理向量化处理数…...