【數據結構(四)】前綴、中綴、后綴表達式(逆波蘭表達式)和逆波蘭計算器的代碼實現(2)

文章目錄

  • 1. 前綴表達式(波蘭表達式)
    • 1.1. 前綴表達式的計算機求值
  • 2. 中綴表達式
  • 3. 后綴表達式(逆波蘭表達式)
    • 3.1. 后綴表達式的計算機求值
    • 3.2. 逆波蘭計算器的實現
  • 4. 中綴表達式 轉 后綴表達式
    • 4.1. 思路分析
    • 4.2. 代碼實現
  • 5. 逆波蘭計算器的完整版


1. 前綴表達式(波蘭表達式)

????前綴表達式又稱波蘭表達式,前綴表達式的運算符位于操作數之前

舉例說明: (3+4)×5-6 對應的前綴表達式就是 - × + 3 4 5 6

1.1. 前綴表達式的計算機求值

????從右至左掃描表達式,遇到數字時,將數字壓入堆棧;遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(棧頂元素 和 次頂元素),并將結果入棧;重復上述過程直到表達式最左端,最后運算得出的值即為表達式的結果。

例如:
(3+4)×5-6 對應的前綴表達式就是 - × + 3 4 5 6 , 針對前綴表達式求值步驟如下:
????①從右至左掃描,將 6、5、4、3 壓入堆棧
????②遇到 + 運算符,因此彈出 3 和 4(3為棧頂元素,4為次頂元素),計算出 3 + 4 的值,得 7,再將 7 入棧
????③接下來是 × 運算符,因此彈出 7 和 5 ,計算出 7 × 5 = 35,將35入棧
????④最后是 - 運算符,計算出 35 - 6 的值,即 29 ,由此得出最終結果

2. 中綴表達式

????
????中綴表達式就是常見的運算表達式,如(3+4)×5-6

????中綴表達式的求值是我們人最熟悉的,但是對計算機來說卻不好操作(前面我們講的案例就能看的這個問題),因此,在計算結果時,往往會將中綴表達式轉成其它表達式來操作(一般轉成后綴表達式)

3. 后綴表達式(逆波蘭表達式)

????后綴表達式又稱逆波蘭表達式,與前綴表達式相似,只是運算符位于操作數之后

舉例說明:

正常表達式后綴表達式
(3+4)×5-63 4 + 5 × 6 –
a+ba b +
a+(b-c)a b c - +
a+(b-c)*da b c - d * +
a+d*(b-c)a d b c - * +
a=1+3a 1 3 + =

3.1. 后綴表達式的計算機求值

????
????從左至右掃描表達式,遇到數字時,將數字壓入堆棧;遇到運算符時,彈出棧頂的兩個數,用運算符對它們做相應的計算(次頂元素 和 棧頂元素),并將結果入棧;重復上述過程直到表達式最右端,最后運算得出的值即為表達式的結果。

例如:
(3+4)×5-6 對應的后綴表達式就是 3 4 + 5 × 6 - , 針對后綴表達式求值步驟如下:

????①從左至右掃描,將3和4壓入堆棧;
????②遇到 + 運算符,因此彈出 4 和 3(4 為棧頂元素,3 為次頂元素),計算出 3 + 4 的值,得 7 ,再將 7 入棧;
????③將 5 入棧;
????④接下來是 × 運算符,因此彈出 5 和 7 ,計算出 7 × 5 = 35 ,將 35 入棧;
????⑤將 6 入棧;
????⑥最后是-運算符,計算出 35 - 6 的值,即 29 ,由此得出最終結果


3.2. 逆波蘭計算器的實現

????
完成一個逆波蘭計算器,要求完成如下任務:
????輸入一個逆波蘭表達式(后綴表達式),使用(Stack), 計算其結果
????支持小括號多位數整數(因為這里主要講的是數據結構,因此計算器進行簡化,只支持對整數的計算)

????
思路分析: 3.2. 小節已給出
????
代碼實現:

package stack;import java.util.ArrayList;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String[] args) {// 定義一個逆波蘭表達式// (3+4)×5-6 --> "3 4 + 5 × 6 -"// 為了方便,逆波蘭表達式的數字和符號使用 空格 隔開String suffixExpression = "3 4 + 5 * 6 -";// 思路// 1.先將"3 4 + 5 × 6 -"放到ArrayList中// 2.將ArrayList傳遞給一個方法,利用棧,完成計算List<String> rpnList = getListString(suffixExpression);System.out.println("rpnList=" + rpnList);int res = calculate(rpnList);System.out.println("計算的結果是=" + res);}// 將一個逆波蘭表達式,依次將數據和運算符放入到ArrayList中public static List<String> getListString(String suffixExpression) {// 將suffixExpression分割String[] split = suffixExpression.split(" ");List<String> list = new ArrayList<String>();for (String ele : split) {list.add(ele);}return list;}// 完成對逆波蘭表達式的運算/*** 1.從左至右掃描,將3和4壓入堆棧;* 2.到 + 運算符,因此彈出 4 和 3(4 為棧頂元素,3 為次頂元素),計算出 3 + 4 的值,得 7 ,再將 7 入棧;* 3.將 5 入棧;* 4.接下來是 × 運算符,因此彈出 5 和 7 ,計算出 7 × 5 = 35 ,將 35 入棧;* 5.將 6 入棧;* 6.最后是-運算符,計算出 35 - 6 的值,即 29 ,由此得出最終結果*/public static int calculate(List<String> ls) {// 創建一個棧,只需要一個即可Stack<String> stack = new Stack<String>();// 遍歷 lsfor (String item : ls) {// 這里使用正則表達式來取出數if (item.matches("\\d+")) {// 匹配的是多位數// 入棧stack.push(item);} else {// pop出兩個數,并運算int num2 = Integer.parseInt(stack.pop());// 先pop出的數int num1 = Integer.parseInt(stack.pop());// 后pop出的數int res = 0;if (item.equals("+")) {res = num1 + num2;} else if (item.equals("-")) {res = num1 - num2;} else if (item.equals("*")) {res = num1 * num2;} else if (item.equals("/")) {res = num1 / num2;} else {throw new RuntimeException("運算符有誤");}// 把res入棧stack.push("" + res);}}// 最后留在stack中的數據就是運算結果return Integer.parseInt(stack.pop());}}

運行結果:

在這里插入圖片描述

注:也可以計算多位數,讀者可自行測試

4. 中綴表達式 轉 后綴表達式

????從前面講的內容可以看出,后綴表達式適合計算機進行運算,但是人卻不太容易寫出來,尤其是表達式很長的情況下,因此在開發中,我們需要將 中綴表達式 轉成 后綴表達式

4.1. 思路分析

????

具體步驟如下:

????1.初始化兩個棧:運算符棧s1和儲存中間結果的棧s2;
????2.從左至右掃描中綴表達式;
????3.遇到操作數時,將其壓s2;
????4.遇到運算符時,比較其與s1棧頂運算符的優先級:
??????(1)如果s1為空,或棧頂運算符為左括號“ ( ”,則直接將此運算符入棧;
??????(2)否則,若優先級比棧頂運算符的高,也將運算符壓入s1;
??????(3)否則,將s1棧頂的運算符彈出并壓入到s2中,再次轉到 4.(1) 與s1中新的棧頂運算符相比較;

????5.遇到括號時:
??????(1)如果是左括號“ ( ”,則直接壓入s1
??????(2) 如果是右括號“ ) ”,則依次彈出s1棧頂的運算符,并壓入s2,直到遇到左括號為止,此時將這一對括號丟棄
????6.重復步驟2至5,直到表達式的最右邊
????7.將s1中剩余的運算符依次彈出并壓入s2
????8.依次彈出s2中的元素并輸出,結果的逆序即為中綴表達式對應的后綴表達式

????
????


實例分析:
????下面,以中綴表達式:1 + ((2 + 3) * 4) - 5 為例,實現將其轉成后綴表達式。

①初始化兩個棧:運算符棧s1和儲存中間結果的棧s2;從左至右掃描中綴表達式;
②遇到操作數時,將其壓s2(首先掃描到 1

在這里插入圖片描述

③遇到運算符時,比較其與s1棧頂運算符的優先級:
????(1)如果s1為空,或棧頂運算符為左括號“ ( ”,則直接將此運算符入棧(將 + 直接入s1棧,后面連續遇到兩個" ( “,根據步驟5.(1),同理,直接將兩個” ( "入s1棧
????
在這里插入圖片描述

④遇到操作數時,將其壓s2(掃描到 2

在這里插入圖片描述

⑤因為下一個掃描到 + 運算符,而 " ( " 不是運算符,故直接將 + 入s1棧

在這里插入圖片描述

⑥遇到操作數時,將其壓s2(掃描到 3

在這里插入圖片描述

⑦根據5.(2):如果是右括號“ ) ”,則依次彈出s1棧頂的運算符,并壓入s2,直到遇到左括號為止,此時將這一對括號丟棄

在這里插入圖片描述

⑧因為下一個掃描到 * 運算符,而 " ( " 不是運算符,故直接將 * 入s1棧;

在這里插入圖片描述

接著掃描到 4 ,直接入s2棧

在這里插入圖片描述

⑨根據5.(2):如果是右括號“ ) ”,則依次彈出s1棧頂的運算符,并壓入s2,直到遇到左括號為止,此時將這一對括號丟棄

在這里插入圖片描述

⑩下一個掃描到 - 符號,由于 - 的優先級與 + 相同,故執行 4.(3):將s1棧頂的運算符彈出并壓入到s2中,再次轉到 4.(1) 與s1中新的棧頂運算符相比較,由于原來的 + 入了s2棧,即s1棧為空,所以直接將 - 運算符入s1棧。

在這里插入圖片描述

在這里插入圖片描述

?下一個掃描到 5 ,入s2棧。這時已經到了表達式最右邊,掃描完畢

在這里插入圖片描述

?執行步驟7:將s1中剩余的運算符依次彈出并壓入s2

在這里插入圖片描述

?步驟8:依次彈出s2中的元素并輸出,結果的逆序即為中綴表達式對應的后綴表達式

- 5 + * 4 + 3 2 1 – > 1 2 3 + 4 * + 5 -

通過圖表來說明上述步驟:

在這里插入圖片描述

????

4.2. 代碼實現

????

package stack;import java.util.ArrayList;
import java.util.List;
import java.util.Stack;public class PolandNotation {public static void main(String[] args) {// 完成將一個中綴表達式轉成后綴表達式的功能// 說明// 1.將 "1+((2+3)*4)-5" 轉成 "1 2 3 + 4 * + 5 -"// 2.先將 "1+((2+3)*4)-5" -->中綴表達式對應的List// 即 "1+((2+3)*4)-5"-->ArrayList[1,+,(,(,2,+,3,),*,4,),-,5]String expression = "1+((2+3)*4)-5";List<String> infixExpressionList = toInfixExpressionList(expression);System.out.println(infixExpressionList);System.out.println("中綴表達式對應的List" + infixExpressionList);// 3.中綴表達式對應的List --> 后綴表達式對應的List// 即將ArrayList[1,+,(,(,2,+,3,),*,4,),-,5] --> ArrayList[1,2,3,+,4,*,5,-]List<String> suffixExpressionList = parseSuffixExpressionList(infixExpressionList);System.out.println("后綴表達式對應的List" + suffixExpressionList);System.out.printf("expression = %d", calculate(suffixExpressionList));}// 方法:中綴表達式對應的List --> 后綴表達式對應的Listpublic static List<String> parseSuffixExpressionList(List<String> ls) {// 定義兩個棧Stack<String> s1 = new Stack<String>();// 符號棧// 說明:因為s2這個棧,再整個轉換過程中,沒有pop操作,而且后面我們還需要逆序輸出// 此方法比較麻煩,這里就不用Stack<String>,直接使用List<String> s2// Stack<String> s2 = new Stack<String>();//存儲中間結果的棧s2List<String> s2 = new ArrayList<String>();// 存儲中間結果的List2// 遍歷lsfor (String item : ls) {// 如果是一個數,加入s2if (item.matches("\\d+")) {s2.add(item);} else if (item.equals("(")) {s1.push(item);} else if (item.equals(")")) {// 如果是")",則依次彈出s1棧頂的運算符,并壓入s2,直到遇到左括號為止,此時將這一對括號丟棄while (!s1.peek().equals("(")) {s2.add(s1.pop());}s1.pop();// 將"("彈出s1,消除小括號} else {// 當item的優先級小于s1棧頂運算符,將s1棧頂的運算符彈出并加入到s2中,再次轉到(4.1)與s1中新的棧頂運算符相比較// 問題:需要一個比較優先級高低的方法while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {s2.add(s1.pop());}// 將item壓入s1.push(item);}}// 將s1中剩余的運算符依次彈出并加入s2while (s1.size() != 0) {s2.add(s1.pop());}return s2;// 因為是存放到List,因此按順序輸出就是對應的后綴表達式}// 方法:將中綴表達式轉成對應的Listpublic static List<String> toInfixExpressionList(String s) {// 定義一個List,存放中綴表達式 對應內容List<String> ls = new ArrayList<String>();int i = 0;// 這是一個指針,用于遍歷中綴表達式字符串String str;// 對多位數的拼接char c;// 每遍歷到一個字符,就放入到cdo {// 如果c是一個非數字,需要加入到lsif ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {ls.add("" + c);i++;// i需要后移} else {// 如果是一個數,需要考慮多位數str = "";// 先將str置成"";while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57) {str += c;// 拼接i++;}ls.add(str);}} while (i < s.length());return ls;}// 將一個逆波蘭表達式,依次將數據和運算符放入到ArrayList中public static List<String> getListString(String suffixExpression) {// 將suffixExpression分割String[] split = suffixExpression.split(" ");List<String> list = new ArrayList<String>();for (String ele : split) {list.add(ele);}return list;}// 完成對逆波蘭表達式的運算/*** 1.從左至右掃描,將3和4壓入堆棧;* 2.到 + 運算符,因此彈出 4 和 3(4 為棧頂元素,3 為次頂元素),計算出 3 + 4 的值,得 7 ,再將 7 入棧;* 3.將 5 入棧;* 4.接下來是 × 運算符,因此彈出 5 和 7 ,計算出 7 × 5 = 35 ,將 35 入棧;* 5.將 6 入棧;* 6.最后是-運算符,計算出 35 - 6 的值,即 29 ,由此得出最終結果*/public static int calculate(List<String> ls) {// 創建一個棧,只需要一個即可Stack<String> stack = new Stack<String>();// 遍歷 lsfor (String item : ls) {// 這里使用正則表達式來取出數if (item.matches("\\d+")) {// 匹配的是多位數// 入棧stack.push(item);} else {// pop出兩個數,并運算int num2 = Integer.parseInt(stack.pop());// 先pop出的數int num1 = Integer.parseInt(stack.pop());// 后pop出的數int res = 0;if (item.equals("+")) {res = num1 + num2;} else if (item.equals("-")) {res = num1 - num2;} else if (item.equals("*")) {res = num1 * num2;} else if (item.equals("/")) {res = num1 / num2;} else {throw new RuntimeException("運算符有誤");}// 把res入棧stack.push("" + res);}}// 最后留在stack中的數據就是運算結果return Integer.parseInt(stack.pop());}}// 編寫一個類Operation,可以返回一個運算符對應的優先級
class Operation {private static int ADD = 1;private static int SUB = 2;private static int MUL = 3;private static int DIV = 4;// 寫一個方法,返回對應的優先級數字public static int getValue(String operation) {int result = 0;switch (operation) {case "+":result = ADD;case "-":result = SUB;case "*":result = MUL;case "/":result = DIV;break;default:System.out.println("不存在該運算符");break;}return result;}
}

運行結果:

在這里插入圖片描述

5. 逆波蘭計算器的完整版

完整版的逆波蘭計算器,功能包括:
????①支持 + - * / ( )
????②多位數,支持小數,
????③兼容處理, 過濾任何空白字符,包括空格、制表符、換頁符

逆波蘭計算器完整版考慮的因素較多,但基本思路和前面一樣,也是使用到:中綴表達式轉后綴表達式。

代碼實現:

package stack;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;public class ReversePolishMultiCalc {/*** 匹配 + - * / ( ) 運算符*/static final String SYMBOL = "\\+|-|\\*|/|\\(|\\)";static final String LEFT = "(";static final String RIGHT = ")";static final String ADD = "+";static final String MINUS = "-";static final String TIMES = "*";static final String DIVISION = "/";/*** 加減 + -*/static final int LEVEL_01 = 1;/*** 乘除 * /*/static final int LEVEL_02 = 2;/*** 括號*/static final int LEVEL_HIGH = Integer.MAX_VALUE;static Stack<String> stack = new Stack<>();static List<String> data = Collections.synchronizedList(new ArrayList<String>());/*** 去除所有空白符* * @param s* @return*/public static String replaceAllBlank(String s) {// \\s+ 匹配任何空白字符,包括空格、制表符、換頁符等等, 等價于[ \f\n\r\t\v]return s.replaceAll("\\s+", "");}/*** 判斷是不是數字 int double long float* * @param s* @return*/public static boolean isNumber(String s) {Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");return pattern.matcher(s).matches();}/*** 判斷是不是運算符* * @param s* @return*/public static boolean isSymbol(String s) {return s.matches(SYMBOL);}/*** 匹配運算等級* * @param s* @return*/public static int calcLevel(String s) {if ("+".equals(s) || "-".equals(s)) {return LEVEL_01;} else if ("*".equals(s) || "/".equals(s)) {return LEVEL_02;}return LEVEL_HIGH;}/*** 匹配* * @param s* @throws Exception*/public static List<String> doMatch(String s) throws Exception {if (s == null || "".equals(s.trim()))throw new RuntimeException("data is empty");if (!isNumber(s.charAt(0) + ""))throw new RuntimeException("data illeagle,start not with a number");s = replaceAllBlank(s);String each;int start = 0;for (int i = 0; i < s.length(); i++) {if (isSymbol(s.charAt(i) + "")) {each = s.charAt(i) + "";// 棧為空,(操作符,或者 操作符優先級大于棧頂優先級 && 操作符優先級不是( )的優先級 及是 ) 不能直接入棧if (stack.isEmpty() || LEFT.equals(each)|| ((calcLevel(each) > calcLevel(stack.peek())) && calcLevel(each) < LEVEL_HIGH)) {stack.push(each);} else if (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())) {// 棧非空,操作符優先級小于等于棧頂優先級時出棧入列,直到棧為空,或者遇到了(,最后操作符入棧while (!stack.isEmpty() && calcLevel(each) <= calcLevel(stack.peek())) {if (calcLevel(stack.peek()) == LEVEL_HIGH) {break;}data.add(stack.pop());}stack.push(each);} else if (RIGHT.equals(each)) {// ) 操作符,依次出棧入列直到空棧或者遇到了第一個)操作符,此時)出棧while (!stack.isEmpty() && LEVEL_HIGH >= calcLevel(stack.peek())) {if (LEVEL_HIGH == calcLevel(stack.peek())) {stack.pop();break;}data.add(stack.pop());}}start = i; // 前一個運算符的位置} else if (i == s.length() - 1 || isSymbol(s.charAt(i + 1) + "")) {each = start == 0 ? s.substring(start, i + 1) : s.substring(start + 1, i + 1);if (isNumber(each)) {data.add(each);continue;}throw new RuntimeException("data not match number");}}// 如果棧里還有元素,此時元素需要依次出棧入列,可以想象棧里剩下棧頂為/,棧底為+,應該依次出棧入列,可以直接翻轉整個stack 添加到隊列Collections.reverse(stack);data.addAll(new ArrayList<>(stack));System.out.println(data);return data;}/*** 算出結果* * @param list* @return*/public static Double doCalc(List<String> list) {Double d = 0d;if (list == null || list.isEmpty()) {return null;}if (list.size() == 1) {System.out.println(list);d = Double.valueOf(list.get(0));return d;}ArrayList<String> list1 = new ArrayList<>();for (int i = 0; i < list.size(); i++) {list1.add(list.get(i));if (isSymbol(list.get(i))) {Double d1 = doTheMath(list.get(i - 2), list.get(i - 1), list.get(i));list1.remove(i);list1.remove(i - 1);list1.set(i - 2, d1 + "");list1.addAll(list.subList(i + 1, list.size()));break;}}doCalc(list1);return d;}/*** 運算* * @param s1* @param s2* @param symbol* @return*/public static Double doTheMath(String s1, String s2, String symbol) {Double result;switch (symbol) {case ADD:result = Double.valueOf(s1) + Double.valueOf(s2);break;case MINUS:result = Double.valueOf(s1) - Double.valueOf(s2);break;case TIMES:result = Double.valueOf(s1) * Double.valueOf(s2);break;case DIVISION:result = Double.valueOf(s1) / Double.valueOf(s2);break;default:result = null;}return result;}public static void main(String[] args) {// String math = "9+(3-1)*3+10/2";String math = "12.8 + (2 - 3.55)*4+10/5.0";try {doCalc(doMatch(math));} catch (Exception e) {e.printStackTrace();}}}

運行結果:

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165597.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165597.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165597.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

手寫數字可視化_Python數據分析與可視化

手寫數字可視化 手寫數字流形學習 手寫數字 手寫數字無論是在數據可視化還是深度學習都是一個比較實用的案例。 數據在sklearn中&#xff0c;包含近2000份8 x 8的手寫數字縮略圖。 首先需要先下載數據&#xff0c;然后使用plt.imshow()對一些圖形進行可視化&#xff1a; 打開c…

Mysql 鎖機制分析

整體業務代碼精簡邏輯如下&#xff1a; Transaction public void service(Integer id) {delete(id);insert(id); }數據庫實例監控&#xff1a; 當時通過分析上游問題流量限流解決后&#xff0c;后續找時間又重新分析了下問題發生的根本原因&#xff0c;現將其總結如下&#xf…

XDR 網絡安全:技術和最佳實踐

擴展檢測和響應&#xff08;XDR&#xff09;是一種安全方法&#xff0c;它將多種保護工具集成到一個統一的集成解決方案中。它為組織提供了跨網絡、端點、云工作負載和用戶的廣泛可見性&#xff0c;從而實現更快的威脅檢測和響應。 XDR的目標是提高威脅檢測的速度和準確性&…

Arduino驅動防水型SHT20溫濕傳感器(溫濕度傳感器)

目錄 1、傳感器特性 2、控制器和傳感器連線圖 3、驅動程序 SHT20防水型溫濕傳感器,采用新一代Sensirion濕度和溫度傳感器,配有4代CMOSens芯片。除了配有電容式相對濕度傳感器和能隙溫度傳感器外,該芯片還包含一個放大器、A/D轉換器、OTP內存和數字處理單元,可精確測量周…

Linux系統介紹及文件類型和權限

終端:CtrlAltT 或者桌面/文件夾右鍵,打開終端 切換為管理員:sudo su 退出:exit 查看內核版本號:uname -a 內核版本號含義:5 代表主版本號;13代表次版本號;0代表修訂版本號;30代表修訂版本的第幾次微調;數字越大表示內核越新. 目錄結構 /bin:存放常用命令(即二進制可執行程序…

C/C++內存管理(2):`new`和`delete`的實現原理

new和delete操作自定義類型 class Stack { public:Stack(int capacity 3):_top(0), _capacity(capacity){cout << "Stack(int capacity 3)" << endl;_a new int[capacity];}~Stack(){cout << "~Stack()" << endl;delete _a;_to…

openssl+ RSA + linux 簽名開發實例(C++)

文章目錄 一、opensslRSA理論基礎二、openssl RSA 簽名開發實例 一、opensslRSA理論基礎 RSA簽名是一種非對稱加密算法&#xff0c;用于在信息傳輸過程中驗證消息的完整性和真實性。以下是RSA簽名的理論基礎的主要知識點&#xff1a; RSA密鑰對&#xff1a; RSA使用一對公鑰和…

pcie-2-rj45速度優化

背景: 目前用iperf3打流傳輸速率達不到要求,千兆實際要求跑到800M以上: 優化方案: 1.優化defconfig: 首先編譯user版本驗證看是否正常 debug版本關閉CONFIG_SLUB_DEBUG_ON宏控。 2.找FAE ,通過更換驅動,或者更新驅動來優化 3.綁定大核: 以8125網卡為例,udp…

【Unity】IBeginDragHandler、IDragHandler 和 IEndDragHandler 介紹

IBeginDragHandler、IDragHandler 和 IEndDragHandler 介紹 IBeginDragHandler、IDragHandler 和 IEndDragHandler 是 Unity 引擎中的三個接口&#xff0c;用于處理 UI 元素的拖放事件。這些接口通常結合使用&#xff0c;構成了 Unity 引擎的拖放事件系統。 IBeginDragHandler…

java--權限修飾符

1.什么是權限修飾符 就是是用來限制類中的成員(成員變量、成員方法、構造器、代碼塊...)能夠被訪問的范圍。 2.權限修飾符有幾種&#xff1f;各自的作用是什么&#xff1f; private<缺省<protected<public(范圍由小到大)

什么年代了,還不會 CI/CD 么?

目錄 什么是 CI/CD&#xff1f; CI/CD 對業務有哪些好處&#xff1f; 一&#xff1a;確保卓越的代碼質量 二&#xff1a;更快的發布速度 → 更快的交付 三&#xff1a;自動化降低成本 四&#xff1a;故障隔離 五&#xff1a;簡化回滾 六&#xff1a;持續反饋 七&#…

設計模式——行為型模式(二)

6.8 迭代器模式 6.8.1 概述 定義:提供一個對象來順序訪問聚合對象中的一系列數據,而不暴露聚合對象的內部表示。 6.8.2 結構 迭代器模式主要包含以下角色: 抽象聚合(Aggregate)角色:定義存儲、添加、刪除聚合元素以及創建迭代器對象的接口。具體聚合(ConcreteAggreg…

C# Onnx PP-Vehicle 車輛分析(包含:車輛檢測,識別車型和車輛顏色)

目錄 效果 模型信息 mot_ppyoloe_s_36e_ppvehicle.onnx vehicle_attribute_model.onnx 項目 代碼 下載 其他 C# Onnx PP-Vehicle 車輛分析&#xff08;包含&#xff1a;車輛檢測&#xff0c;識別車型和車輛顏色&#xff09; 效果 模型信息 mot_ppyoloe_s_36e_ppvehi…

009 OpenCV 二值化 threshold

一、環境 本文使用環境為&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、二值化算法 2.1、概述 在機器視覺應用中&#xff0c;OpenCV的二值化函數threshold具有不可忽視的作用。主要的功能是將一幅灰度圖進行二值化處理&#xff0c;以此大幅降低圖像的數…

ASP.NET Core 啟用CORS

瀏覽器的安全阻止一個域的本地頁面請求另外不同域的本地頁面&#xff0c;這個限制叫同源策略&#xff0c;這個安全特性用來阻止惡意站點從別的網站讀取數據 例如假如我有一個頁面叫A.html https://foo.example/A.html 現在頁面A.html有一個ajax代碼嘗試讀取B.html的HTML的源…

【PyQt】(自定義類)陰影遮罩

寫了一個感覺有些用的小玩具。 用于給控件添加陰影遮罩(強調主控件的同時屏蔽其余控件的點擊) 自定義陰影遮罩Mask&#xff1a; from PyQt5.QtCore import QPoint,QRect,Qt,QPoint,QSize from PyQt5.QtWidgets import QWidget,QLabel,QPushButton,QVBoxLayout from PyQt5.QtGu…

leetcode:合并兩個有序鏈表

題目描述 題目鏈接&#xff1a;21. 合并兩個有序鏈表 - 力扣&#xff08;LeetCode&#xff09; 題目分析 這個算法思路很簡單&#xff1a;就是直接找小尾插 定義一個tail和head&#xff0c;對比兩個鏈表結點的val&#xff0c;小的尾插到tail->next&#xff0c;如果一個鏈表…

每日一題:LeetCode-589.N叉樹的前序遍歷序列構造二叉樹

每日一題系列&#xff08;day 01&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

企業微信身份驗證

本篇主要是在上一篇獲取第三方憑證基礎上&#xff0c;用戶通過三方網站自定義授權登錄后獲取用戶信息&#xff0c;以實現用戶綁定登錄功能。 構造第三方應用授權鏈接 如果第三方應用需要在打開的網頁里面攜帶用戶的身份信息&#xff0c; 第一步需要構造如下的鏈接來獲取授權c…

馬養殖場建設VR模擬實訓教學平臺具有靈活性和復用性

為保障養殖場生物安全&#xff0c;避免疫病傳播&#xff0c;學生出入養殖場受時間和地域的限制&#xff0c; 生產實習多以參觀為主&#xff0c;通過畜牧企業技術人員的講解&#xff0c;學生被動了解生產過程。為了解決畜牧養殖實訓難的問題&#xff0c;借助VR技術開展畜牧養殖虛…