소스 검색

添加场站列表,添加缺少的类

shilin 5 달 전
부모
커밋
14430134da
100개의 변경된 파일14056개의 추가작업 그리고 0개의 파일을 삭제
  1. 93 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/audiofilters/IIRFilter.java
  2. 104 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/AllPathsFromSourceToTarget.java
  3. 33 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/ArrayCombination.java
  4. 118 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/Combination.java
  5. 122 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/FloodFill.java
  6. 301 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/KnightsTour.java
  7. 155 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/MColoring.java
  8. 298 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/MazeRecursion.java
  9. 217 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/NQueens.java
  10. 97 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/ParenthesesGenerator.java
  11. 110 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/Permutation.java
  12. 87 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/PowerSum.java
  13. 106 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/SubsequenceFinder.java
  14. 162 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/WordSearch.java
  15. 34 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/BitSwap.java
  16. 68 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/HighestSetBit.java
  17. 65 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java
  18. 30 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/IsEven.java
  19. 39 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/IsPowerTwo.java
  20. 42 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java
  21. 32 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/NumbersDifferentSigns.java
  22. 46 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/ReverseBits.java
  23. 68 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/SingleBitOperations.java
  24. 2783 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/AES.java
  25. 104 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/AESEncryption.java
  26. 69 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/AffineCipher.java
  27. 1244 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/Blowfish.java
  28. 96 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/Caesar.java
  29. 207 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/ColumnarTranspositionCipher.java
  30. 250 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/DES.java
  31. 178 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/HillCipher.java
  32. 128 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/PlayfairCipher.java
  33. 62 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/Polybius.java
  34. 73 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/ProductCipher.java
  35. 66 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/RSA.java
  36. 85 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/SimpleSubCipher.java
  37. 51 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/Vigenere.java
  38. 30 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/A5Cipher.java
  39. 56 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java
  40. 10 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/BaseLFSR.java
  41. 37 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/CompositeLFSR.java
  42. 79 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/LFSR.java
  43. 25 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/Utils.java
  44. 355 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/AnyBaseToAnyBase.java
  45. 126 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/AnyBaseToDecimal.java
  46. 35 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/AnytoAny.java
  47. 37 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/BinaryToDecimal.java
  48. 60 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/BinaryToHexadecimal.java
  49. 50 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/BinaryToOctal.java
  50. 69 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/DecimalToAnyBase.java
  51. 63 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/DecimalToBinary.java
  52. 51 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/DecimalToHexaDecimal.java
  53. 38 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/DecimalToOctal.java
  54. 75 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/HexToOct.java
  55. 43 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/HexaDecimalToBinary.java
  56. 39 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/HexaDecimalToDecimal.java
  57. 68 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/IntegerToRoman.java
  58. 43 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/OctalToBinary.java
  59. 47 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/OctalToDecimal.java
  60. 65 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/OctalToHexadecimal.java
  61. 168 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/RgbHsvConversion.java
  62. 65 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/RomanToInteger.java
  63. 67 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/TurkishToLatinConversion.java
  64. 32 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/Node.java
  65. 128 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/bags/Bag.java
  66. 61 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/bloomfilter/BloomFilter.java
  67. 64 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/buffers/CircularBuffer.java
  68. 143 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/caches/LFUCache.java
  69. 171 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/caches/LRUCache.java
  70. 169 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/caches/MRUCache.java
  71. 84 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/GCounter.java
  72. 65 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/GSet.java
  73. 138 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/LWWElementSet.java
  74. 191 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/ORSet.java
  75. 100 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/PNCounter.java
  76. 84 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/TwoPSet.java
  77. 53 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java
  78. 25 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/disjointsetunion/Node.java
  79. 227 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/dynamicarray/DynamicArray.java
  80. 198 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/AStar.java
  81. 184 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/BellmanFord.java
  82. 81 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/BipartiteGrapfDFS.java
  83. 217 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/BoruvkaAlgorithm.java
  84. 146 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/ConnectedComponent.java
  85. 92 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/Cycles.java
  86. 86 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/DIJSKSTRAS_ALGORITHM.java
  87. 72 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/FloydWarshall.java
  88. 140 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/Graphs.java
  89. 107 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/HamiltonianCycle.java
  90. 141 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/KahnsAlgorithm.java
  91. 147 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/Kosaraju.java
  92. 103 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/Kruskal.java
  93. 345 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/MatrixGraphs.java
  94. 110 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/PrimMST.java
  95. 91 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/README.md
  96. 131 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/TarjansAlgorithm.java
  97. 113 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/WelshPowell.java
  98. 65 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/hashmap/Readme.md
  99. 128 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java
  100. 0 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java

+ 93 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/audiofilters/IIRFilter.java

@@ -0,0 +1,93 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.audiofilters;
+
+
+/**
+ * N阶IIR滤波器,假设输入已经归一化至[-1, 1]
+ *
+ * 基于
+ * <a href="https://en.wikipedia.org/wiki/Infinite_impulse_response">Wikipedia链接</a>
+ * 中的差分方程
+ */
+public class IIRFilter {
+
+    private final int order;  // 滤波器阶数
+    private final double[] coeffsA;  // 分母系数
+    private final double[] coeffsB;  // 分子系数
+    private final double[] historyX;  // 输入历史记录
+    private final double[] historyY;  // 输出历史记录
+
+    /**
+     * 构造一个IIR滤波器
+     *
+     * @param order 滤波器的阶数
+     * @throws IllegalArgumentException 如果阶数为零或小于零
+     */
+    public IIRFilter(int order) throws IllegalArgumentException {
+        if (order < 1) {
+            throw new IllegalArgumentException("阶数必须大于零");
+        }
+        this.order = order;  // 设置阶数
+        coeffsA = new double[order + 1];  // 初始化分母系数数组
+        coeffsB = new double[order + 1];  // 初始化分子系数数组
+
+        // 设置默认值
+        coeffsA[0] = 1.0;
+        coeffsB[0] = 1.0;
+
+        historyX = new double[order];  // 初始化输入历史记录数组
+        historyY = new double[order];  // 初始化输出历史记录数组
+    }
+
+    /**
+     * 设置系数
+     *
+     * @param aCoeffs 分母系数
+     * @param bCoeffs 分子系数
+     * @throws IllegalArgumentException 如果aCoeffs或bCeffs的大小不为order,或者aCoeffs[0]为0.0
+     */
+    public void setCoeffs(double[] aCoeffs, double[] bCoeffs) throws IllegalArgumentException {
+        if (aCoeffs.length != order) {
+            throw new IllegalArgumentException("aCoeffs的大小必须为" + order + ",当前为" + aCoeffs.length);
+        }
+
+        if (aCoeffs[0] == 0.0) {
+            throw new IllegalArgumentException("aCoeffs的第一个元素不能为零");
+        }
+
+        if (bCoeffs.length != order) {
+            throw new IllegalArgumentException("bCoeffs的大小必须为" + order + ",当前为" + bCoeffs.length);
+        }
+
+        for (int i = 0; i <= order; i++) {  // 设置分母和分子系数
+            coeffsA[i] = aCoeffs[i];
+            coeffsB[i] = bCoeffs[i];
+        }
+    }
+
+    /**
+     * 处理单个样本
+     *
+     * @param sample 要处理的样本
+     * @return 处理后的样本
+     */
+    public double process(double sample) {
+        double result = 0.0;
+
+        // 处理
+        for (int i = 1; i <= order; i++) {
+            result += (coeffsB[i] * historyX[i - 1] - coeffsA[i] * historyY[i - 1]);
+        }
+        result = (result + coeffsB[0] * sample) / coeffsA[0];
+
+        // 反馈
+        for (int i = order - 1; i > 0; i--) {
+            historyX[i] = historyX[i - 1];
+            historyY[i] = historyY[i - 1];
+        }
+
+        historyX[0] = sample;
+        historyY[0] = result;
+
+        return result;
+    }
+}

+ 104 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/AllPathsFromSourceToTarget.java

@@ -0,0 +1,104 @@
+/**
+ * 作者 : Siddhant Swarup Mallick
+ * Github : https://github.com/siddhant2002
+ */
+
+/** 程序描述 - 查找从源点到目的地的所有可能路径 */
+
+/** 维基百科链接 -> https://en.wikipedia.org/wiki/Shortest_path_problem */
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AllPathsFromSourceToTarget {
+
+    // 图中的顶点数量
+    private final int v;
+
+    // 存储从源点到目的地的路径
+    static List<List<Integer>> nm = new ArrayList<>();
+    // 邻接表
+    private ArrayList<Integer>[] adjList;
+
+    // 构造函数
+    public AllPathsFromSourceToTarget(int vertices) {
+
+        // 初始化顶点数量
+        this.v = vertices;
+
+        // 初始化邻接表
+        initAdjList();
+    }
+
+    // 初始化邻接表的工具方法
+    private void initAdjList() {
+        adjList = new ArrayList[v];
+
+        for (int i = 0; i < v; i++) {
+            adjList[i] = new ArrayList<>();
+        }
+    }
+
+    // 添加从 u 到 v 的边
+    public void addEdge(int u, int v) {
+        // 将 v 添加到 u 的列表中。
+        adjList[u].add(v);
+    }
+
+    // 存储所有路径
+    public void storeAllPaths(int s, int d) {
+        boolean[] isVisited = new boolean[v];
+        ArrayList<Integer> pathList = new ArrayList<>();
+
+        // 将源点添加到路径中
+        pathList.add(s);
+        // 调用递归工具
+        storeAllPathsUtil(s, d, isVisited, pathList);
+    }
+
+    // 一个递归函数,用于打印从 'u' 到 'd' 的所有路径。
+    // isVisited[] 跟踪当前路径中的顶点。
+    // localPathList<> 存储当前路径中的实际顶点
+    private void storeAllPathsUtil(Integer u, Integer d, boolean[] isVisited, List<Integer> localPathList) {
+
+        // 如果到达目的地
+        if (u.equals(d)) {
+            nm.add(new ArrayList<>(localPathList));
+            return;
+        }
+
+        // 标记当前节点
+        isVisited[u] = true;
+
+        // 对当前顶点相邻的所有顶点进行递归
+
+        for (Integer i : adjList[u]) {
+            if (!isVisited[i]) {
+                // 将当前节点存储在路径中
+                localPathList.add(i);
+                storeAllPathsUtil(i, d, isVisited, localPathList);
+
+                // 从路径中移除当前节点
+                localPathList.remove(i);
+            }
+        }
+
+        // 取消标记当前节点
+        isVisited[u] = false;
+    }
+
+    // 驱动程序
+    public static List<List<Integer>> allPathsFromSourceToTarget(int vertices, int[][] a, int source, int destination) {
+        // 创建一个示例图
+        AllPathsFromSourceToTarget g = new AllPathsFromSourceToTarget(vertices);
+        for (int[] i : a) {
+            g.addEdge(i[0], i[1]);
+            // 添加边
+        }
+        g.storeAllPaths(source, destination);
+        // 调用方法存储所有可能的路径
+        return nm;
+        // 返回从源点到目的地的所有可能路径
+    }
+}

+ 33 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/ArrayCombination.java

@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.List;
+import java.util.TreeSet;
+
+
+/**
+ * 查找 1...n 的所有长度为 k 的排列组合
+ * 作者 TheClerici (<a href="https://github.com/TheClerici">git-TheClerici</a>)
+ */
+public final class ArrayCombination {
+    private ArrayCombination() {
+    }
+    private static int length;
+
+    /**
+     * 通过创建一个数组并在 Combination.java 中使用回溯算法来查找 1..n 的所有组合
+     * @param n 数组的最大值。
+     * @param k 组合的长度
+     * @return 长度为 k 的所有组合的列表。如果 k == 0,则返回 null。
+     */
+    public static List<TreeSet<Integer>> combination(int n, int k) {
+        if (n <= 0) {
+            return null;
+        }
+        length = k;
+        Integer[] arr = new Integer[n];
+        for (int i = 1; i <= n; i++) {
+            arr[i - 1] = i;
+        }
+        return Combination.combination(arr, length);
+    }
+}

+ 118 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/Combination.java

@@ -0,0 +1,118 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+
+///**
+// * Finds all permutations of given array
+// * @author Alan Piao (<a href="https://github.com/cpiao3">git-Alan Piao</a>)
+// */
+//public final class Combination {
+//    private Combination() {
+//    }
+//
+//    private static int length;
+//
+//    /**
+//     * Find all combinations of given array using backtracking
+//     * @param arr the array.
+//     * @param n length of combination
+//     * @param <T> the type of elements in the array.
+//     * @return a list of all combinations of length n. If n == 0, return null.
+//     */
+//    public static <T> List<TreeSet<T>> combination(T[] arr, int n) {
+//        if (n == 0) {
+//            return null;
+//        }
+//        length = n;
+//        T[] array = arr.clone();
+//        Arrays.sort(array);
+//        List<TreeSet<T>> result = new LinkedList<>();
+//        backtracking(array, 0, new TreeSet<T>(), result);
+//        return result;
+//    }
+//
+//    /**
+//     * Backtrack all possible combinations of a given array
+//     * @param arr the array.
+//     * @param index the starting index.
+//     * @param currSet set that tracks current combination
+//     * @param result the list contains all combination.
+//     * @param <T> the type of elements in the array.
+//     */
+//    private static <T> void backtracking(T[] arr, int index, TreeSet<T> currSet, List<TreeSet<T>> result) {
+//        if (index + length - currSet.size() > arr.length) {
+//            return;
+//        }
+//        if (length - 1 == currSet.size()) {
+//            for (int i = index; i < arr.length; i++) {
+//                currSet.add(arr[i]);
+//                result.add((TreeSet<T>) currSet.clone());
+//                currSet.remove(arr[i]);
+//            }
+//        }
+//        for (int i = index; i < arr.length; i++) {
+//            currSet.add(arr[i]);
+//            backtracking(arr, i + 1, currSet, result);
+//            currSet.remove(arr[i]);
+//        }
+//    }
+//}
+
+/**
+ * 查找给定数组的所有排列组合
+ * @author Alan Piao (<a href="https://github.com/cpiao3">git-Alan Piao</a>)
+ */
+public final class Combination {
+    private Combination() {
+    }
+
+    private static int length;
+
+    /**
+     * 使用回溯法找出给定数组的所有组合
+     * @param arr 数组
+     * @param n 组合的长度
+     * @param <T> 数组中元素的类型
+     * @return 长度为n的所有组合的列表。如果n为0,则返回null。
+     */
+    public static <T> List<TreeSet<T>> combination(T[] arr, int n) {
+        if (n == 0) {
+            return null;
+        }
+        length = n;
+        T[] array = arr.clone();
+        Arrays.sort(array);
+        List<TreeSet<T>> result = new LinkedList<>();
+        backtracking(array, 0, new TreeSet<T>(), result);
+        return result;
+    }
+
+    /**
+     * 回溯给定数组的所有可能组合
+     * @param arr 数组
+     * @param index 起始索引
+     * @param currSet 跟踪当前组合的集合
+     * @param result 包含所有组合的列表
+     * @param <T> 数组中元素的类型
+     */
+    private static <T> void backtracking(T[] arr, int index, TreeSet<T> currSet, List<TreeSet<T>> result) {
+        if (index + length - currSet.size() > arr.length) {
+            return;
+        }
+        if (length - 1 == currSet.size()) {
+            for (int i = index; i < arr.length; i++) {
+                currSet.add(arr[i]);
+                result.add((TreeSet<T>) currSet.clone());
+                currSet.remove(arr[i]);
+            }
+        }
+        for (int i = index; i < arr.length; i++) {
+            currSet.add(arr[i]);
+            backtracking(arr, i + 1, currSet, result);
+            currSet.remove(arr[i]);
+        }
+    }
+}

+ 122 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/FloodFill.java

@@ -0,0 +1,122 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+///**
+// * Java program for Flood fill algorithm.
+// * @author Akshay Dubey (<a href="https://github.com/itsAkshayDubey">Git-Akshay Dubey</a>)
+// */
+//public final class FloodFill {
+//    private FloodFill() {
+//    }
+//
+//    /**
+//     * Get the color at the given coordinates of a 2D image
+//     *
+//     * @param image The image to be filled
+//     * @param x The x co-ordinate of which color is to be obtained
+//     * @param y The y co-ordinate of which color is to be obtained
+//     */
+//
+//    public static int getPixel(final int[][] image, final int x, final int y) {
+//        return image[x][y];
+//    }
+//
+//    /**
+//     * Put the color at the given coordinates of a 2D image
+//     *
+//     * @param image The image to be filled
+//     * @param x The x co-ordinate at which color is to be filled
+//     * @param y The y co-ordinate at which color is to be filled
+//     */
+//    public static void putPixel(final int[][] image, final int x, final int y, final int newColor) {
+//        image[x][y] = newColor;
+//    }
+//
+//    /**
+//     * Fill the 2D image with new color
+//     *
+//     * @param image The image to be filled
+//     * @param x The x co-ordinate at which color is to be filled
+//     * @param y The y co-ordinate at which color is to be filled
+//     * @param newColor The new color which to be filled in the image
+//     * @param oldColor The old color which is to be replaced in the image
+//     */
+//    public static void floodFill(final int[][] image, final int x, final int y, final int newColor, final int oldColor) {
+//        if (newColor == oldColor || x < 0 || x >= image.length || y < 0 || y >= image[x].length || getPixel(image, x, y) != oldColor) {
+//            return;
+//        }
+//
+//        putPixel(image, x, y, newColor);
+//
+//        /* Recursively check for horizontally & vertically adjacent coordinates */
+//        floodFill(image, x + 1, y, newColor, oldColor);
+//        floodFill(image, x - 1, y, newColor, oldColor);
+//        floodFill(image, x, y + 1, newColor, oldColor);
+//        floodFill(image, x, y - 1, newColor, oldColor);
+//
+//        /* Recursively check for diagonally adjacent coordinates  */
+//        floodFill(image, x + 1, y - 1, newColor, oldColor);
+//        floodFill(image, x - 1, y + 1, newColor, oldColor);
+//        floodFill(image, x + 1, y + 1, newColor, oldColor);
+//        floodFill(image, x - 1, y - 1, newColor, oldColor);
+//    }
+//}
+
+/**
+ * Java程序实现泛洪填充算法。
+ * @author Akshay Dubey (<a href="https://github.com/itsAkshayDubey">Git-Akshay Dubey</a>)
+ */
+public final class FloodFill {
+    private FloodFill() {
+    }
+
+    /**
+     * 获取2D图像给定坐标的颜色
+     *
+     * @param image 要填充的图像
+     * @param x 要获取颜色的x坐标
+     * @param y 要获取颜色的y坐标
+     */
+    public static int getPixel(final int[][] image, final int x, final int y) {
+        return image[x][y];
+    }
+
+    /**
+     * 在2D图像的给定坐标处填充颜色
+     *
+     * @param image 要填充的图像
+     * @param x 要填充颜色的x坐标
+     * @param y 要填充颜色的y坐标
+     */
+    public static void putPixel(final int[][] image, final int x, final int y, final int newColor) {
+        image[x][y] = newColor;
+    }
+
+    /**
+     * 用新颜色填充2D图像
+     *
+     * @param image 要填充的图像
+     * @param x 要填充颜色的x坐标
+     * @param y 要填充颜色的y坐标
+     * @param newColor 要在图像中填充的新颜色
+     * @param oldColor 要在图像中替换的旧颜色
+     */
+    public static void floodFill(final int[][] image, final int x, final int y, final int newColor, final int oldColor) {
+        if (newColor == oldColor || x < 0 || x >= image.length || y < 0 || y >= image[x].length || getPixel(image, x, y) != oldColor) {
+            return;
+        }
+
+        putPixel(image, x, y, newColor);
+
+        /* 递归检查水平和垂直相邻坐标 */
+        floodFill(image, x + 1, y, newColor, oldColor);
+        floodFill(image, x - 1, y, newColor, oldColor);
+        floodFill(image, x, y + 1, newColor, oldColor);
+        floodFill(image, x, y - 1, newColor, oldColor);
+
+        /* 递归检查对角线相邻坐标 */
+        floodFill(image, x + 1, y - 1, newColor, oldColor);
+        floodFill(image, x - 1, y + 1, newColor, oldColor);
+        floodFill(image, x + 1, y + 1, newColor, oldColor);
+        floodFill(image, x - 1, y - 1, newColor, oldColor);
+    }
+}

+ 301 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/KnightsTour.java

@@ -0,0 +1,301 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+///*
+//    * Problem Statement: -
+//
+//    Given a N*N board with the Knight placed on the first block of an empty board. Moving according
+//   to the rules of chess knight must visit each square exactly once. Print the order of each cell in
+//   which they are visited.
+//
+//    Example: -
+//
+//    Input : N = 8
+//
+//    Output:
+//        0  59  38  33  30  17   8  63
+//        37  34  31  60   9  62  29  16
+//        58   1  36  39  32  27  18   7
+//        35  48  41  26  61  10  15  28
+//        42  57   2  49  40  23   6  19
+//        47  50  45  54  25  20  11  14
+//        56  43  52   3  22  13  24   5
+//        51  46  55  44  53   4  21  12
+//
+// */
+//public final class KnightsTour {
+//    private KnightsTour() {
+//    }
+//
+//    private static final int BASE = 12;
+//    private static final int[][] MOVES = {
+//        {1, -2},
+//        {2, -1},
+//        {2, 1},
+//        {1, 2},
+//        {-1, 2},
+//        {-2, 1},
+//        {-2, -1},
+//        {-1, -2},
+//    }; // Possible moves by knight on chess
+//    private static int[][] grid; // chess grid
+//    private static int total; // total squares in chess
+//
+//    public static void main(String[] args) {
+//        grid = new int[BASE][BASE];
+//        total = (BASE - 4) * (BASE - 4);
+//
+//        for (int r = 0; r < BASE; r++) {
+//            for (int c = 0; c < BASE; c++) {
+//                if (r < 2 || r > BASE - 3 || c < 2 || c > BASE - 3) {
+//                    grid[r][c] = -1;
+//                }
+//            }
+//        }
+//
+//        int row = 2 + (int) (Math.random() * (BASE - 4));
+//        int col = 2 + (int) (Math.random() * (BASE - 4));
+//
+//        grid[row][col] = 1;
+//
+//        if (solve(row, col, 2)) {
+//            printResult();
+//        } else {
+//            System.out.println("no result");
+//        }
+//    }
+//
+//    // Return True when solvable
+//    private static boolean solve(int row, int column, int count) {
+//        if (count > total) {
+//            return true;
+//        }
+//
+//        List<int[]> neighbor = neighbors(row, column);
+//
+//        if (neighbor.isEmpty() && count != total) {
+//            return false;
+//        }
+//
+//        neighbor.sort(Comparator.comparingInt(a -> a[2]));
+//
+//        for (int[] nb : neighbor) {
+//            row = nb[0];
+//            column = nb[1];
+//            grid[row][column] = count;
+//            if (!orphanDetected(count, row, column) && solve(row, column, count + 1)) {
+//                return true;
+//            }
+//            grid[row][column] = 0;
+//        }
+//
+//        return false;
+//    }
+//
+//    // Returns List of neighbours
+//    private static List<int[]> neighbors(int row, int column) {
+//        List<int[]> neighbour = new ArrayList<>();
+//
+//        for (int[] m : MOVES) {
+//            int x = m[0];
+//            int y = m[1];
+//            if (grid[row + y][column + x] == 0) {
+//                int num = countNeighbors(row + y, column + x);
+//                neighbour.add(new int[] {row + y, column + x, num});
+//            }
+//        }
+//        return neighbour;
+//    }
+//
+//    // Returns the total count of neighbors
+//    private static int countNeighbors(int row, int column) {
+//        int num = 0;
+//        for (int[] m : MOVES) {
+//            if (grid[row + m[1]][column + m[0]] == 0) {
+//                num++;
+//            }
+//        }
+//        return num;
+//    }
+//
+//    // Returns true if it is orphan
+//    private static boolean orphanDetected(int count, int row, int column) {
+//        if (count < total - 1) {
+//            List<int[]> neighbor = neighbors(row, column);
+//            for (int[] nb : neighbor) {
+//                if (countNeighbors(nb[0], nb[1]) == 0) {
+//                    return true;
+//                }
+//            }
+//        }
+//        return false;
+//    }
+//
+//    // Prints the result grid
+//    private static void printResult() {
+//        for (int[] row : grid) {
+//            for (int i : row) {
+//                if (i == -1) {
+//                    continue;
+//                }
+//                System.out.printf("%2d ", i);
+//            }
+//            System.out.println();
+//        }
+//    }
+//}
+//
+
+/*
+ * 问题陈述:-
+ *
+ * 给定一个N*N的棋盘,骑士放在空棋盘的第一个方块上。根据国际象棋骑士的规则移动,
+ * 必须恰好访问每个方格一次。打印每个单元格被访问的顺序。
+ *
+ * 示例:-
+ *
+ * 输入:N = 8
+ *
+ * 输出:
+ *     0  59  38  33  30  17   8  63
+ *     37  34  31  60   9  62  29  16
+ *     58   1  36  39  32  27  18   7
+ *     35  48  41  26  61  10  15  28
+ *     42  57   2  49  40  23   6  19
+ *     47  50  45  54  25  20  11  14
+ *     56  43  52   3  22  13  24   5
+ *     51  46  55  44  53   4  21  12
+ *
+ */
+public final class KnightsTour {
+    private KnightsTour() {
+    }
+
+    private static final int BASE = 12; // 基础大小
+    private static final int[][] MOVES = { // 骑士在棋盘上可能的移动
+            {1, -2},
+            {2, -1},
+            {2, 1},
+            {1, 2},
+            {-1, 2},
+            {-2, 1},
+            {-2, -1},
+            {-1, -2},
+    };
+    private static int[][] grid; // 棋盘网格
+    private static int total; // 棋盘上的总方格数
+
+    public static void main(String[] args) {
+        grid = new int[BASE][BASE];
+        total = (BASE - 4) * (BASE - 4); // 计算总方格数
+
+        // 初始化棋盘边界
+        for (int r = 0; r < BASE; r++) {
+            for (int c = 0; c < BASE; c++) {
+                if (r < 2 || r > BASE - 3 || c < 2 || c > BASE - 3) {
+                    grid[r][c] = -1;
+                }
+            }
+        }
+
+        // 随机选择起始位置
+        int row = 2 + (int) (Math.random() * (BASE - 4));
+        int col = 2 + (int) (Math.random() * (BASE - 4));
+
+        grid[row][col] = 1; // 设置起始位置
+
+        // 如果找到解决方案,则打印结果
+        if (solve(row, col, 2)) {
+            printResult();
+        } else {
+            System.out.println("无结果");
+        }
+    }
+
+    // 当找到解决方案时返回True
+    private static boolean solve(int row, int column, int count) {
+        if (count > total) {
+            return true;
+        }
+
+        List<int[]> neighbor = neighbors(row, column);
+
+        // 如果没有邻居且计数不等于总数,则返回false
+        if (neighbor.isEmpty() && count != total) {
+            return false;
+        }
+
+        // 根据邻居数量排序
+        neighbor.sort(Comparator.comparingInt(a -> a[2]));
+
+        // 遍历所有邻居
+        for (int[] nb : neighbor) {
+            row = nb[0];
+            column = nb[1];
+            grid[row][column] = count;
+            // 如果没有孤立点且递归求解成功,则返回true
+            if (!orphanDetected(count, row, column) && solve(row, column, count + 1)) {
+                return true;
+            }
+            grid[row][column] = 0; // 回溯
+        }
+
+        return false;
+    }
+
+    // 返回邻居列表
+    private static List<int[]> neighbors(int row, int column) {
+        List<int[]> neighbour = new ArrayList<>();
+
+        // 检查所有可能的移动
+        for (int[] m : MOVES) {
+            int x = m[0];
+            int y = m[1];
+            if (grid[row + y][column + x] == 0) {
+                int num = countNeighbors(row + y, column + x);
+                neighbour.add(new int[] {row + y, column + x, num});
+            }
+        }
+        return neighbour;
+    }
+
+    // 返回邻居的总数
+    private static int countNeighbors(int row, int column) {
+        int num = 0;
+        for (int[] m : MOVES) {
+            if (grid[row + m[1]][column + m[0]] == 0) {
+                num++;
+            }
+        }
+        return num;
+    }
+
+    // 如果是孤立点则返回true
+    private static boolean orphanDetected(int count, int row, int column) {
+        if (count < total - 1) {
+            List<int[]> neighbor = neighbors(row, column);
+            for (int[] nb : neighbor) {
+                if (countNeighbors(nb[0], nb[1]) == 0) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    // 打印结果网格
+    private static void printResult() {
+        for (int[] row : grid) {
+            for (int i : row) {
+                if (i == -1) {
+                    continue;
+                }
+                System.out.printf("%2d ", i);
+            }
+            System.out.println();
+        }
+    }
+}

+ 155 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/MColoring.java

@@ -0,0 +1,155 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+
+///**
+// * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+// */
+//class Node {
+//    int color = 1;
+//    Set<Integer> edges = new HashSet<Integer>();
+//}
+//
+//public final class MColoring {
+//    private MColoring() {
+//    }
+//    static int possiblePaint(ArrayList<Node> nodes, int n, int m) {
+//
+//        // Create a visited array of n nodes
+//        ArrayList<Integer> visited = new ArrayList<Integer>();
+//        for (int i = 0; i < n + 1; i++) {
+//            visited.add(0);
+//        }
+//
+//        // maxColors used till now are 1 as
+//        // all nodes are painted color 1
+//        int maxColors = 1;
+//
+//        for (int sv = 1; sv <= n; sv++) {
+//            if (visited.get(sv) > 0) {
+//                continue;
+//            }
+//
+//            // If the starting point is unvisited,
+//            // mark it visited and push it in queue
+//            visited.set(sv, 1);
+//            Queue<Integer> q = new LinkedList<>();
+//            q.add(sv);
+//
+//            // BFS
+//            while (q.size() != 0) {
+//                int top = q.peek();
+//                q.remove();
+//
+//                // Checking all adjacent nodes
+//                // to "top" edge in our queue
+//                for (int it : nodes.get(top).edges) {
+//
+//                    // If the color of the
+//                    // adjacent node is same, increase it by
+//                    // 1
+//                    if (nodes.get(top).color == nodes.get(it).color) {
+//                        nodes.get(it).color += 1;
+//                    }
+//
+//                    // If number of colors used exceeds m,
+//                    // return 0
+//                    maxColors = Math.max(maxColors, Math.max(nodes.get(top).color, nodes.get(it).color));
+//                    if (maxColors > m) {
+//                        return 0;
+//                    }
+//
+//                    // If the adjacent node is not visited,
+//                    // mark it visited and push it in queue
+//                    if (visited.get(it) == 0) {
+//                        visited.set(it, 1);
+//                        q.add(it);
+//                    }
+//                }
+//            }
+//        }
+//        return 1;
+//    }
+//}
+
+
+
+/**
+ * 节点类,表示图中的一个节点及其边
+ */
+class Node {
+    int color = 1; // 默认颜色为1
+    Set<Integer> edges = new HashSet<Integer>(); // 存储与该节点相连的边
+}
+
+/**
+ * MColoring类包含解决M着色问题的方法
+ */
+public final class MColoring {
+    private MColoring() {
+    }
+
+    /**
+     * 判断是否可能用m种颜色为图的所有节点着色,使得相邻节点颜色不同
+     * @param nodes 图的节点列表
+     * @param n 节点数量
+     * @param m 颜色数量
+     * @return 如果可以用m种颜色着色,则返回1;否则返回0
+     */
+    static int possiblePaint(ArrayList<Node> nodes, int n, int m) {
+
+        // 创建一个访问数组,记录n个节点的访问状态
+        ArrayList<Integer> visited = new ArrayList<Integer>();
+        for (int i = 0; i < n + 1; i++) {
+            visited.add(0);
+        }
+
+        // 目前使用的最大颜色数为1,因为所有节点初始都涂上颜色1
+        int maxColors = 1;
+
+        // 遍历所有节点
+        for (int sv = 1; sv <= n; sv++) {
+            if (visited.get(sv) > 0) {
+                continue; // 如果已访问,跳过
+            }
+
+            // 如果起始点未被访问,标记为已访问并加入队列
+            visited.set(sv, 1);
+            Queue<Integer> q = new LinkedList<>();
+            q.add(sv);
+
+            // 广度优先搜索(BFS)
+            while (q.size() != 0) {
+                int top = q.peek();
+                q.remove();
+
+                // 检查队列顶部节点的所有相邻节点
+                for (int it : nodes.get(top).edges) {
+
+                    // 如果相邻节点的颜色相同,则增加1
+                    if (nodes.get(top).color == nodes.get(it).color) {
+                        nodes.get(it).color += 1;
+                    }
+
+                    // 如果使用的颜色数超过m,返回0
+                    maxColors = Math.max(maxColors, Math.max(nodes.get(top).color, nodes.get(it).color));
+                    if (maxColors > m) {
+                        return 0;
+                    }
+
+                    // 如果相邻节点未被访问,标记为已访问并加入队列
+                    if (visited.get(it) == 0) {
+                        visited.set(it, 1);
+                        q.add(it);
+                    }
+                }
+            }
+        }
+        return 1; // 如果所有节点都能正确着色,返回1
+    }
+}
+

+ 298 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/MazeRecursion.java

@@ -0,0 +1,298 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+//public final class MazeRecursion {
+//    private MazeRecursion() {
+//    }
+//
+//    public static void mazeRecursion() {
+//        // First create a 2 dimensions array to mimic a maze map
+//        int[][] map = new int[8][7];
+//        int[][] map2 = new int[8][7];
+//
+//        // We use 1 to indicate wall
+//        // Set the ceiling and floor to 1
+//        for (int i = 0; i < 7; i++) {
+//            map[0][i] = 1;
+//            map[7][i] = 1;
+//        }
+//
+//        // Then we set the left and right wall to 1
+//        for (int i = 0; i < 8; i++) {
+//            map[i][0] = 1;
+//            map[i][6] = 1;
+//        }
+//
+//        // Now we have created a maze with its wall initialized
+//
+//        // Here we set the obstacle
+//        map[3][1] = 1;
+//        map[3][2] = 1;
+//
+//        // Print the current map
+//        System.out.println("The condition of the map: ");
+//        for (int i = 0; i < 8; i++) {
+//            for (int j = 0; j < 7; j++) {
+//                System.out.print(map[i][j] + " ");
+//            }
+//            System.out.println();
+//        }
+//
+//        // clone another map for setWay2 method
+//        for (int i = 0; i < map.length; i++) {
+//            System.arraycopy(map[i], 0, map2[i], 0, map[i].length);
+//        }
+//
+//        // By using recursive backtracking to let your ball(target) find its way in the
+//        // maze
+//        // The first parameter is the map
+//        // Second parameter is x coordinate of your target
+//        // Third parameter is the y coordinate of your target
+//        setWay(map, 1, 1);
+//        setWay2(map2, 1, 1);
+//
+//        // Print out the new map1, with the ball footprint
+//        System.out.println("After the ball goes through the map1,show the current map1 condition");
+//        for (int i = 0; i < 8; i++) {
+//            for (int j = 0; j < 7; j++) {
+//                System.out.print(map[i][j] + " ");
+//            }
+//            System.out.println();
+//        }
+//
+//        // Print out the new map2, with the ball footprint
+//        System.out.println("After the ball goes through the map2,show the current map2 condition");
+//        for (int i = 0; i < 8; i++) {
+//            for (int j = 0; j < 7; j++) {
+//                System.out.print(map2[i][j] + " ");
+//            }
+//            System.out.println();
+//        }
+//    }
+//
+//    /**
+//     * Using recursive path finding to help the ball find its way in the maze
+//     * Description:
+//     * 1. map (means the maze)
+//     * 2. i, j (means the initial coordinate of the ball in the maze)
+//     * 3. if the ball can reach the end of maze, that is position of map[6][5],
+//     * means the we have found a path for the ball
+//     * 4. Additional Information: 0 in the map[i][j] means the ball has not gone
+//     * through this position, 1 means the wall, 2 means the path is feasible, 3
+//     * means the ball has gone through the path but this path is dead end
+//     * 5. We will need strategy for the ball to pass through the maze for example:
+//     * Down -> Right -> Up -> Left, if the path doesn't work, then backtrack
+//     *
+//     * @author OngLipWei
+//     * @version Jun 23, 2021 11:36:14 AM
+//     * @param map The maze
+//     * @param i   x coordinate of your ball(target)
+//     * @param j   y coordinate of your ball(target)
+//     * @return If we did find a path for the ball,return true,else false
+//     */
+//    public static boolean setWay(int[][] map, int i, int j) {
+//        if (map[6][5] == 2) { // means the ball find its path, ending condition
+//            return true;
+//        }
+//        if (map[i][j] == 0) { // if the ball haven't gone through this point
+//            // then the ball follows the move strategy : down -> right -> up -> left
+//            map[i][j] = 2; // we assume that this path is feasible first, set the current point to 2
+//                           // first。
+//            if (setWay(map, i + 1, j)) { // go down
+//                return true;
+//            } else if (setWay(map, i, j + 1)) { // go right
+//                return true;
+//            } else if (setWay(map, i - 1, j)) { // go up
+//                return true;
+//            } else if (setWay(map, i, j - 1)) { // go left
+//                return true;
+//            } else {
+//                // means that the current point is the dead end, the ball cannot proceed, set
+//                // the current point to 3 and return false, the backtracking will start, it will
+//                // go to the previous step and check for feasible path again
+//                map[i][j] = 3;
+//                return false;
+//            }
+//        } else { // if the map[i][j] != 0 , it will probably be 1,2,3, return false because the
+//            // ball cannot hit the wall, cannot go to the path that has gone though before,
+//            // and cannot head to deadened.
+//            return false;
+//        }
+//    }
+//
+//    // Here is another move strategy for the ball: up->right->down->left
+//    public static boolean setWay2(int[][] map, int i, int j) {
+//        if (map[6][5] == 2) { // means the ball find its path, ending condition
+//            return true;
+//        }
+//        if (map[i][j] == 0) { // if the ball haven't gone through this point
+//            // then the ball follows the move strategy : up->right->down->left
+//            map[i][j] = 2; // we assume that this path is feasible first, set the current point to 2
+//                           // first。
+//            if (setWay2(map, i - 1, j)) { // go up
+//                return true;
+//            } else if (setWay2(map, i, j + 1)) { // go right
+//                return true;
+//            } else if (setWay2(map, i + 1, j)) { // go down
+//                return true;
+//            } else if (setWay2(map, i, j - 1)) { // go left
+//                return true;
+//            } else {
+//                // means that the current point is the dead end, the ball cannot proceed, set
+//                // the current point to 3 and return false, the backtracking will start, it will
+//                // go to the previous step and check for feasible path again
+//                map[i][j] = 3;
+//                return false;
+//            }
+//        } else { // if the map[i][j] != 0 , it will probably be 1,2,3, return false because the
+//            // ball cannot hit the wall, cannot go to the path that has gone through before,
+//            // and cannot head to deadend.
+//            return false;
+//        }
+//    }
+//}
+
+
+public final class MazeRecursion {
+
+    private MazeRecursion() {
+    }
+
+    // 使用递归解决迷宫问题
+    public static void mazeRecursion() {
+        // 首先创建一个二维数组来模拟迷宫地图
+        int[][] map = new int[8][7];
+        int[][] map2 = new int[8][7];
+
+        // 使用1表示墙壁
+        // 设置顶部和底部为1
+        for (int i = 0; i < 7; i++) {
+            map[0][i] = 1;
+            map[7][i] = 1;
+        }
+
+        // 然后设置左右墙壁为1
+        for (int i = 0; i < 8; i++) {
+            map[i][0] = 1;
+            map[i][6] = 1;
+        }
+
+        // 现在我们已经创建了一个初始化墙壁的迷宫
+
+        // 这里我们设置障碍物
+        map[3][1] = 1;
+        map[3][2] = 1;
+
+        // 打印当前地图的状态
+        System.out.println("地图的当前状态:");
+        for (int i = 0; i < 8; i++) {
+            for (int j = 0; j < 7; j++) {
+                System.out.print(map[i][j] + " ");
+            }
+            System.out.println();
+        }
+
+        // 克隆另一个地图用于setWay2方法
+        for (int i = 0; i < map.length; i++) {
+            System.arraycopy(map[i], 0, map2[i], 0, map[i].length);
+        }
+
+        // 使用递归回溯让你的球(目标)在迷宫中找到出路
+        // 第一个参数是地图
+        // 第二个参数是目标的x坐标
+        // 第三个参数是目标的y坐标
+        setWay(map, 1, 1);
+        setWay2(map2, 1, 1);
+
+        // 打印新的map1,显示球的足迹
+        System.out.println("球穿过map1后,显示当前map1的状态");
+        for (int i = 0; i < 8; i++) {
+            for (int j = 0; j < 7; j++) {
+                System.out.print(map[i][j] + " ");
+            }
+            System.out.println();
+        }
+
+        // 打印新的map2,显示球的足迹
+        System.out.println("球穿过map2后,显示当前map2的状态");
+        for (int i = 0; i < 8; i++) {
+            for (int j = 0; j < 7; j++) {
+                System.out.print(map2[i][j] + " ");
+            }
+            System.out.println();
+        }
+    }
+
+    /**
+     * 使用递归寻路帮助球在迷宫中找到出路
+     * 描述:
+     * 1. map(表示迷宫)
+     * 2. i, j(表示球在迷宫中的初始坐标)
+     * 3. 如果球能到达迷宫的终点,即map[6][5]的位置,
+     * 表示我们为球找到了一条路径
+     * 4. 额外信息:map[i][j]中的0表示球还没有经过这个位置,1表示墙壁,2表示路径可行,3
+     * 表示球已经经过这条路径但这条路径是死路
+     * 5. 我们需要为球通过迷宫制定策略,例如:
+     * 下 -> 右 -> 上 -> 左,如果路径不通,则回溯
+     *
+     * @param map 迷宫
+     * @param i   球的x坐标
+     * @param j   球的y坐标
+     * @return 如果我们为球找到了一条路径,返回true,否则返回false
+     */
+    public static boolean setWay(int[][] map, int i, int j) {
+        if (map[6][5] == 2) { // 表示球找到了路径,结束条件
+            return true;
+        }
+        if (map[i][j] == 0) { // 如果球还没有经过这个点
+            // 球按照移动策略:下 -> 右 -> 上 -> 左
+            map[i][j] = 2; // 我们先假设这条路径是可行的,将当前点设置为2。
+            if (setWay(map, i + 1, j)) { // 向下走
+                return true;
+            } else if (setWay(map, i, j + 1)) { // 向右走
+                return true;
+            } else if (setWay(map, i - 1, j)) { // 向上走
+                return true;
+            } else if (setWay(map, i, j - 1)) { // 向左走
+                return true;
+            } else {
+                // 表示当前点是死路,球无法继续前进,将当前点设置为3并返回false,
+                // 开始回溯,它将返回到上一步并再次检查可行路径
+                map[i][j] = 3;
+                return false;
+            }
+        } else { // 如果map[i][j] != 0,可能是1,2,3,返回false因为
+            // 球不能撞墙,不能走已经走过的路径,
+            // 也不能走向死路。
+            return false;
+        }
+    }
+
+    // 这里是另一个球的移动策略:上->右->下->左
+    public static boolean setWay2(int[][] map, int i, int j) {
+        if (map[6][5] == 2) { // 表示球找到了路径,结束条件
+            return true;
+        }
+        if (map[i][j] == 0) { // 如果球还没有经过这个点
+            // 球按照移动策略:上->右->下->左
+            map[i][j] = 2; // 我们先假设这条路径是可行的,将当前点设置为2。
+            if (setWay2(map, i - 1, j)) { // 向上走
+                return true;
+            } else if (setWay2(map, i, j + 1)) { // 向右走
+                return true;
+            } else if (setWay2(map, i + 1, j)) { // 向下走
+                return true;
+            } else if (setWay2(map, i, j - 1)) { // 向左走
+                return true;
+            } else {
+                // 表示当前点是死路,球无法继续前进,将当前点设置为3并返回false,
+                // 开始回溯,它将返回到上一步并再次检查可行路径
+                map[i][j] = 3;
+                return false;
+            }
+        } else { // 如果map[i][j] != 0,可能是1,2,3,返回false因为
+            // 球不能撞墙,不能走已经走过的路径,
+            // 也不能走向死路。
+            return false;
+        }
+    }
+}

+ 217 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/NQueens.java

@@ -0,0 +1,217 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+///**
+// * Problem statement: Given a N x N chess board. Return all arrangements in
+// * which N queens can be placed on the board such no two queens attack each
+// * other. Ex. N = 6 Solution= There are 4 possible ways Arrangement: 1 ".Q....",
+// * "...Q..", ".....Q", "Q.....", "..Q...", "....Q."
+// *
+// * Arrangement: 2 "..Q...", ".....Q", ".Q....", "....Q.", "Q.....", "...Q.."
+// *
+// * Arrangement: 3 "...Q..", "Q.....", "....Q.", ".Q....", ".....Q", "..Q..."
+// *
+// * Arrangement: 4 "....Q.", "..Q...", "Q.....", ".....Q", "...Q..", ".Q...."
+// *
+// * Solution: Brute Force approach:
+// *
+// * Generate all possible arrangement to place N queens on N*N board. Check each
+// * board if queens are placed safely. If it is safe, include arrangement in
+// * solution set. Otherwise, ignore it
+// *
+// * Optimized solution: This can be solved using backtracking in below steps
+// *
+// * Start with first column and place queen on first row Try placing queen in a
+// * row on second column If placing second queen in second column attacks any of
+// * the previous queens, change the row in second column otherwise move to next
+// * column and try to place next queen In case if there is no rows where a queen
+// * can be placed such that it doesn't attack previous queens, then go back to
+// * previous column and change row of previous queen. Keep doing this until last
+// * queen is not placed safely. If there is no such way then return an empty list
+// * as solution
+// */
+//public final class NQueens {
+//    private NQueens() {
+//    }
+//
+//    public static void main(String[] args) {
+//        placeQueens(1);
+//        placeQueens(2);
+//        placeQueens(3);
+//        placeQueens(4);
+//        placeQueens(5);
+//        placeQueens(6);
+//    }
+//
+//    public static void placeQueens(final int queens) {
+//        List<List<String>> arrangements = new ArrayList<List<String>>();
+//        getSolution(queens, arrangements, new int[queens], 0);
+//        if (arrangements.isEmpty()) {
+//            System.out.println("There is no way to place " + queens + " queens on board of size " + queens + "x" + queens);
+//        } else {
+//            System.out.println("Arrangement for placing " + queens + " queens");
+//        }
+//        for (List<String> arrangement : arrangements) {
+//            arrangement.forEach(System.out::println);
+//            System.out.println();
+//        }
+//    }
+//
+//    /**
+//     * This is backtracking function which tries to place queen recursively
+//     *
+//     * @param boardSize: size of chess board
+//     * @param solutions: this holds all possible arrangements
+//     * @param columns: columns[i] = rowId where queen is placed in ith column.
+//     * @param columnIndex: This is the column in which queen is being placed
+//     */
+//    private static void getSolution(int boardSize, List<List<String>> solutions, int[] columns, int columnIndex) {
+//        if (columnIndex == boardSize) {
+//            // this means that all queens have been placed
+//            List<String> sol = new ArrayList<String>();
+//            for (int i = 0; i < boardSize; i++) {
+//                StringBuilder sb = new StringBuilder();
+//                for (int j = 0; j < boardSize; j++) {
+//                    sb.append(j == columns[i] ? "Q" : ".");
+//                }
+//                sol.add(sb.toString());
+//            }
+//            solutions.add(sol);
+//            return;
+//        }
+//
+//        // This loop tries to place queen in a row one by one
+//        for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+//            columns[columnIndex] = rowIndex;
+//            if (isPlacedCorrectly(columns, rowIndex, columnIndex)) {
+//                // If queen is placed successfully at rowIndex in column=columnIndex then try
+//                // placing queen in next column
+//                getSolution(boardSize, solutions, columns, columnIndex + 1);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * This function checks if queen can be placed at row = rowIndex in column =
+//     * columnIndex safely
+//     *
+//     * @param columns: columns[i] = rowId where queen is placed in ith column.
+//     * @param rowIndex: row in which queen has to be placed
+//     * @param columnIndex: column in which queen is being placed
+//     * @return true: if queen can be placed safely false: otherwise
+//     */
+//    private static boolean isPlacedCorrectly(int[] columns, int rowIndex, int columnIndex) {
+//        for (int i = 0; i < columnIndex; i++) {
+//            int diff = Math.abs(columns[i] - rowIndex);
+//            if (diff == 0 || columnIndex - i == diff) {
+//                return false;
+//            }
+//        }
+//        return true;
+//    }
+//}
+
+/**
+ * 问题陈述:给定一个N x N的棋盘。返回所有可能的排列方式,
+ * 使得N个皇后可以放在棋盘上而不相互攻击。例如,N = 6时,
+ * 解决方案=有4种可能的方式。
+ *
+ * 解决方案:暴力方法:
+ * 生成所有可能的排列来放置N个皇后在N*N棋盘上。检查每个
+ * 棋盘是否安全放置了皇后。如果安全,则包括排列在解决方案集中。
+ * 否则,忽略它。
+ *
+ * 优化解决方案:可以使用以下步骤的回溯法解决此问题:
+ * 从第一列开始,在第一行放置皇后
+ * 尝试在第二列的一行放置皇后
+ * 如果放置在第二列的第二个皇后攻击任何先前的皇后,
+ * 则更改第二列的行,否则移动到下一列并尝试放置下一个皇后
+ * 如果没有行可以放置皇后以至于它不攻击先前的皇后,
+ * 则返回到前一列并更改前一个皇后的行。
+ * 继续这样做,直到最后一个皇后安全放置。
+ * 如果没有这样的方法,则返回一个空列表作为解决方案。
+ */
+public final class NQueens {
+    private NQueens() {
+    }
+
+    public static void main(String[] args) {
+        // 在这里调用placeQueens方法来放置不同数量的皇后
+        placeQueens(1);
+        placeQueens(2);
+        placeQueens(3);
+        placeQueens(4);
+        placeQueens(5);
+        placeQueens(6);
+    }
+
+    /**
+     * 放置皇后的方法
+     * @param queens 皇后的数量
+     */
+    public static void placeQueens(final int queens) {
+        List<List<String>> arrangements = new ArrayList<List<String>>();
+        getSolution(queens, arrangements, new int[queens], 0);
+        if (arrangements.isEmpty()) {
+            System.out.println("没有办法在 " + queens + "x" + queens + " 的棋盘上放置 " + queens + " 个皇后");
+        } else {
+            System.out.println("放置 " + queens + " 个皇后的排列方式");
+        }
+        for (List<String> arrangement : arrangements) {
+            arrangement.forEach(System.out::println);
+            System.out.println();
+        }
+    }
+
+    /**
+     * 这是一个回溯函数,尝试递归地放置皇后
+     * @param boardSize 棋盘大小
+     * @param solutions 这保存了所有可能的排列
+     * @param columns columns[i] 表示在第i列放置皇后的行号
+     * @param columnIndex 正在放置皇后的列
+     */
+    private static void getSolution(int boardSize, List<List<String>> solutions, int[] columns, int columnIndex) {
+        if (columnIndex == boardSize) {
+            // 这意味着所有的皇后都已经放置
+            List<String> sol = new ArrayList<String>();
+            for (int i = 0; i < boardSize; i++) {
+                StringBuilder sb = new StringBuilder();
+                for (int j = 0; j < boardSize; j++) {
+                    sb.append(j == columns[i] ? "Q" : ".");
+                }
+                sol.add(sb.toString());
+            }
+            solutions.add(sol);
+            return;
+        }
+
+        // 这个循环尝试逐行放置皇后
+        for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+            columns[columnIndex] = rowIndex;
+            if (isPlacedCorrectly(columns, rowIndex, columnIndex)) {
+                // 如果在columnIndex列的rowIndex行成功放置了皇后,则尝试在下一列放置皇后
+                getSolution(boardSize, solutions, columns, columnIndex + 1);
+            }
+        }
+    }
+
+    /**
+     * 这个函数检查皇后是否可以安全地放置在columnIndex列的rowIndex行
+     * @param columns columns[i] 表示在第i列放置皇后的行号
+     * @param rowIndex 要放置皇后的行
+     * @param columnIndex 正在放置皇后的列
+     * @return true: 如果皇后可以安全放置 false: 否则
+     */
+    private static boolean isPlacedCorrectly(int[] columns, int rowIndex, int columnIndex) {
+        for (int i = 0; i < columnIndex; i++) {
+            int diff = Math.abs(columns[i] - rowIndex);
+            if (diff == 0 || columnIndex - i == diff) {
+                // 如果在同一行或在对角线上,则返回false
+                return false;
+            }
+        }
+        return true;
+    }
+}

+ 97 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/ParenthesesGenerator.java

@@ -0,0 +1,97 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+///**
+// * This class generates all valid combinations of parentheses for a given number of pairs using backtracking.
+// */
+//public final class ParenthesesGenerator {
+//    private ParenthesesGenerator() {
+//    }
+//
+//    /**
+//     * Generates all valid combinations of parentheses for a given number of pairs.
+//     *
+//     * @param n The number of pairs of parentheses.
+//     * @return A list of strings representing valid combinations of parentheses.
+//     * @throws IllegalArgumentException if n is less than 0.
+//     */
+//    public static List<String> generateParentheses(final int n) {
+//        if (n < 0) {
+//            throw new IllegalArgumentException("The number of pairs of parentheses cannot be nagative");
+//        }
+//        List<String> result = new ArrayList<>();
+//        generateParenthesesHelper(result, "", 0, 0, n);
+//        return result;
+//    }
+//
+//    /**
+//     * Helper function for generating all valid combinations of parentheses recursively.
+//     *
+//     * @param result  The list to store valid combinations.
+//     * @param current The current combination being formed.
+//     * @param open    The number of open parentheses.
+//     * @param close   The number of closed parentheses.
+//     * @param n       The total number of pairs of parentheses.
+//     */
+//    private static void generateParenthesesHelper(List<String> result, final String current, final int open, final int close, final int n) {
+//        if (current.length() == n * 2) {
+//            result.add(current);
+//            return;
+//        }
+//        if (open < n) {
+//            generateParenthesesHelper(result, current + "(", open + 1, close, n);
+//        }
+//        if (close < open) {
+//            generateParenthesesHelper(result, current + ")", open, close + 1, n);
+//        }
+//    }
+//}
+//
+
+/**
+ * 这个类使用回溯法为给定数量的括号对生成所有有效的括号组合。
+ */
+public final class ParenthesesGenerator {
+    private ParenthesesGenerator() {
+    }
+
+    /**
+     * 为给定数量的括号对生成所有有效的括号组合。
+     *
+     * @param n 括号对的数量。
+     * @return 表示有效括号组合的字符串列表。
+     * @throws IllegalArgumentException 如果n小于0。
+     */
+    public static List<String> generateParentheses(final int n) {
+        if (n < 0) {
+            throw new IllegalArgumentException("括号对的数量不能为负数");
+        }
+        List<String> result = new ArrayList<>();
+        generateParenthesesHelper(result, "", 0, 0, n);
+        return result;
+    }
+
+    /**
+     * 递归生成所有有效括号组合的辅助函数。
+     *
+     * @param result  用于存储有效组合的列表。
+     * @param current 正在形成的当前组合。
+     * @param open    开括号的数量。
+     * @param close   闭括号的数量。
+     * @param n       括号对的总数。
+     */
+    private static void generateParenthesesHelper(List<String> result, final String current, final int open, final int close, final int n) {
+        if (current.length() == n * 2) {
+            result.add(current);
+            return;
+        }
+        if (open < n) {
+            generateParenthesesHelper(result, current + "(", open + 1, close, n);
+        }
+        if (close < open) {
+            generateParenthesesHelper(result, current + ")", open, close + 1, n);
+        }
+    }
+}

+ 110 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/Permutation.java

@@ -0,0 +1,110 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.LinkedList;
+import java.util.List;
+
+///**
+// * Finds all permutations of given array
+// * @author Alan Piao (<a href="https://github.com/cpiao3">Git-Alan Piao</a>)
+// */
+//public final class Permutation {
+//    private Permutation() {
+//    }
+//
+//    /**
+//     * Find all permutations of given array using backtracking
+//     * @param arr the array.
+//     * @param <T> the type of elements in the array.
+//     * @return a list of all permutations.
+//     */
+//    public static <T> List<T[]> permutation(T[] arr) {
+//        T[] array = arr.clone();
+//        List<T[]> result = new LinkedList<>();
+//        backtracking(array, 0, result);
+//        return result;
+//    }
+//
+//    /**
+//     * Backtrack all possible orders of a given array
+//     * @param arr the array.
+//     * @param index the starting index.
+//     * @param result the list contains all permutations.
+//     * @param <T> the type of elements in the array.
+//     */
+//    private static <T> void backtracking(T[] arr, int index, List<T[]> result) {
+//        if (index == arr.length) {
+//            result.add(arr.clone());
+//        }
+//        for (int i = index; i < arr.length; i++) {
+//            swap(index, i, arr);
+//            backtracking(arr, index + 1, result);
+//            swap(index, i, arr);
+//        }
+//    }
+//
+//    /**
+//     * Swap two element for a given array
+//     * @param a first index
+//     * @param b second index
+//     * @param arr the array.
+//     * @param <T> the type of elements in the array.
+//     */
+//    private static <T> void swap(int a, int b, T[] arr) {
+//        T temp = arr[a];
+//        arr[a] = arr[b];
+//        arr[b] = temp;
+//    }
+//}
+
+/**
+ * 查找给定数组的所有排列
+ * @author Alan Piao (Git-Alan Piao)
+ */
+public final class Permutation {
+    private Permutation() {
+    }
+
+    /**
+     * 使用回溯法找到给定数组的所有排列
+     * @param arr 数组。
+     * @param <T> 数组中元素的类型。
+     * @return 所有排列的列表。
+     */
+    public static <T> List<T[]> permutation(T[] arr) {
+        T[] array = arr.clone();
+        List<T[]> result = new LinkedList<>();
+        backtracking(array, 0, result);
+        return result;
+    }
+
+    /**
+     * 回溯给定数组的所有可能顺序
+     * @param arr 数组。
+     * @param index 起始索引。
+     * @param result 包含所有排列的列表。
+     * @param <T> 数组中元素的类型。
+     */
+    private static <T> void backtracking(T[] arr, int index, List<T[]> result) {
+        if (index == arr.length) {
+            result.add(arr.clone());
+        }
+        for (int i = index; i < arr.length; i++) {
+            swap(index, i, arr);
+            backtracking(arr, index + 1, result);
+            swap(index, i, arr);
+        }
+    }
+
+    /**
+     * 交换给定数组的两个元素
+     * @param a 第一个索引
+     * @param b 第二个索引
+     * @param arr 数组。
+     * @param <T> 数组中元素的类型。
+     */
+    private static <T> void swap(int a, int b, T[] arr) {
+        T temp = arr[a];
+        arr[a] = arr[b];
+        arr[b] = temp;
+    }
+}

+ 87 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/PowerSum.java

@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+///*
+// * Problem Statement :
+// * Find the number of ways that a given integer, N , can be expressed as the sum of the Xth powers
+// * of unique, natural numbers. For example, if N=100 and X=3, we have to find all combinations of
+// * unique cubes adding up to 100. The only solution is 1^3+2^3+3^3+4^3. Therefore output will be 1.
+// */
+//public class PowerSum {
+//
+//    private int count = 0;
+//    private int sum = 0;
+//
+//    public int powSum(int n, int x) {
+//        sum(n, x, 1);
+//        return count;
+//    }
+//
+//    // here i is the natural number which will be raised by X and added in sum.
+//    public void sum(int n, int x, int i) {
+//        // if sum is equal to N that is one of our answer and count is increased.
+//        if (sum == n) {
+//            count++;
+//            return;
+//        } // we will be adding next natural number raised to X only if on adding it in sum the
+//          // result is less than N.
+//        else if (sum + power(i, x) <= n) {
+//            sum += power(i, x);
+//            sum(n, x, i + 1);
+//            // backtracking and removing the number added last since no possible combination is
+//            // there with it.
+//            sum -= power(i, x);
+//        }
+//        if (power(i, x) < n) {
+//            // calling the sum function with next natural number after backtracking if when it is
+//            // raised to X is still less than X.
+//            sum(n, x, i + 1);
+//        }
+//    }
+//
+//    // creating a separate power function so that it can be used again and again when required.
+//    private int power(int a, int b) {
+//        return (int) Math.pow(a, b);
+//    }
+//}
+
+/*
+ * 问题描述:
+ * 找出一个给定整数 N 可以被表示为唯一自然数的 X 次幂之和的方法数。
+ * 例如,如果 N=100 且 X=3,我们需要找到所有唯一立方数相加等于 100 的组合。
+ * 唯一的解决方案是 1^3+2^3+3^3+4^3。因此输出将为 1。
+ */
+public class PowerSum {
+
+    private int count = 0; // 解决方案的数量
+    private int sum = 0; // 当前的和
+
+    // 计算 N 可以被表示为唯一自然数的 X 次幂之和的方法数
+    public int powSum(int n, int x) {
+        sum(n, x, 1);
+        return count;
+    }
+
+    // 这里的 i 是将被提升 X 次幂并加入和中的自然数
+    public void sum(int n, int x, int i) {
+        // 如果和等于 N,那么这是我们的一个答案,并且计数增加
+        if (sum == n) {
+            count++;
+            return;
+        } // 我们将添加下一个自然数提升到 X 次幂,只有在加上它后和小于 N 的情况下
+        else if (sum + power(i, x) <= n) {
+            sum += power(i, x);
+            sum(n, x, i + 1);
+            // 回溯并移除最后添加的数字,因为没有可能的组合包含它
+            sum -= power(i, x);
+        }
+        // 如果 i 的 X 次幂小于 N,则在回溯后调用 sum 函数,使用下一个自然数
+        if (power(i, x) < n) {
+            sum(n, x, i + 1);
+        }
+    }
+
+    // 创建一个单独的 power 函数,以便在需要时反复使用
+    private int power(int a, int b) {
+        return (int) Math.pow(a, b);
+    }
+}

+ 106 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/SubsequenceFinder.java

@@ -0,0 +1,106 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+///**
+// * Class generates all subsequences for a given list of elements using backtracking
+// */
+//public final class SubsequenceFinder {
+//    private SubsequenceFinder() {
+//    }
+//
+//    /**
+//     * Find all subsequences of given list using backtracking
+//     *
+//     * @param sequence a list of items on the basis of which we need to generate all subsequences
+//     * @param <T> the type of elements in the array
+//     * @return a list of all subsequences
+//     */
+//    public static <T> List<List<T>> generateAll(List<T> sequence) {
+//        List<List<T>> allSubSequences = new ArrayList<>();
+//        if (sequence.isEmpty()) {
+//            allSubSequences.add(new ArrayList<>());
+//            return allSubSequences;
+//        }
+//        List<T> currentSubsequence = new ArrayList<>();
+//        backtrack(sequence, currentSubsequence, 0, allSubSequences);
+//        return allSubSequences;
+//    }
+//
+//    /**
+//     * Iterate through each branch of states
+//     * We know that each state has exactly two branching
+//     * It terminates when it reaches the end of the given sequence
+//     *
+//     * @param sequence all elements
+//     * @param currentSubsequence current subsequence
+//     * @param index current index
+//     * @param allSubSequences contains all sequences
+//     * @param <T> the type of elements which we generate
+//     */
+//    private static <T> void backtrack(List<T> sequence, List<T> currentSubsequence, final int index, List<List<T>> allSubSequences) {
+//        assert index <= sequence.size();
+//        if (index == sequence.size()) {
+//            allSubSequences.add(new ArrayList<>(currentSubsequence));
+//            return;
+//        }
+//
+//        backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
+//        currentSubsequence.add(sequence.get(index));
+//        backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
+//        currentSubsequence.removeLast();
+//    }
+//}
+
+/**
+ * 类使用回溯算法为给定元素列表生成所有子序列
+ */
+public final class SubsequenceFinder {
+    private SubsequenceFinder() {
+    }
+
+    /**
+     * 使用回溯算法找出给定列表的所有子序列
+     *
+     * @param sequence 我们需要基于此生成所有子序列的元素列表
+     * @param <T> 数组中元素的类型
+     * @return 所有子序列的列表
+     */
+    public static <T> List<List<T>> generateAll(List<T> sequence) {
+        List<List<T>> allSubSequences = new ArrayList<>();
+        if (sequence.isEmpty()) {
+            allSubSequences.add(new ArrayList<>());
+            return allSubSequences;
+        }
+        List<T> currentSubsequence = new ArrayList<>();
+        backtrack(sequence, currentSubsequence, 0, allSubSequences);
+        return allSubSequences;
+    }
+
+    /**
+     * 遍历每个状态的分支
+     * 我们知道每个状态正好有两个分支
+     * 当到达给定序列的末尾时终止
+     *
+     * @param sequence 所有元素
+     * @param currentSubsequence 当前子序列
+     * @param index 当前索引
+     * @param allSubSequences 包含所有序列的列表
+     * @param <T> 我们生成的元素的类型
+     */
+    private static <T> void backtrack(List<T> sequence, List<T> currentSubsequence, final int index, List<List<T>> allSubSequences) {
+        assert index <= sequence.size();
+        if (index == sequence.size()) {
+            allSubSequences.add(new LinkedList<>(currentSubsequence));
+            return;
+        }
+
+        backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
+        currentSubsequence.add(sequence.get(index));
+        backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
+        currentSubsequence.remove(currentSubsequence.size() - 1);
+    }
+}
+

+ 162 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/backtracking/WordSearch.java

@@ -0,0 +1,162 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.backtracking;
+
+///*
+//Word Search Problem (https://en.wikipedia.org/wiki/Word_search)
+//
+//Given an m x n grid of characters board and a string word, return true if word exists in the grid.
+//
+//The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are
+//those horizontally or vertically neighboring. The same letter cell may not be used more than once.
+//
+//For example,
+//Given board =
+//
+//[
+// ['A','B','C','E'],
+// ['S','F','C','S'],
+// ['A','D','E','E']
+//]
+//word = "ABCCED", -> returns true,
+//word = "SEE", -> returns true,
+//word = "ABCB", -> returns false.
+//*/
+//
+///*
+//   Solution
+//   Depth First Search in matrix (as multiple sources possible) with backtracking
+//   like finding cycle in a directed graph. Maintain a record of path
+//
+//   Tx = O(m * n * 3^L): for each cell, we look at 3 options (not 4 as that one will be visited), we
+//   do it L times Sx = O(L) : stack size is max L
+//*/
+//
+//public class WordSearch {
+//    private final int[] dx = {0, 0, 1, -1};
+//    private final int[] dy = {1, -1, 0, 0};
+//    private boolean[][] visited;
+//    private char[][] board;
+//    private String word;
+//
+//    private boolean isValid(int x, int y) {
+//        return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
+//    }
+//
+//    private boolean doDFS(int x, int y, int nextIdx) {
+//        visited[x][y] = true;
+//        if (nextIdx == word.length()) {
+//            return true;
+//        }
+//        for (int i = 0; i < 4; ++i) {
+//            int xi = x + dx[i];
+//            int yi = y + dy[i];
+//            if (isValid(xi, yi) && board[xi][yi] == word.charAt(nextIdx) && !visited[xi][yi]) {
+//                boolean exists = doDFS(xi, yi, nextIdx + 1);
+//                if (exists) {
+//                    return true;
+//                }
+//            }
+//        }
+//        visited[x][y] = false;
+//        return false;
+//    }
+//
+//    public boolean exist(char[][] board, String word) {
+//        this.board = board;
+//        this.word = word;
+//        for (int i = 0; i < board.length; ++i) {
+//            for (int j = 0; j < board[0].length; ++j) {
+//                if (board[i][j] == word.charAt(0)) {
+//                    visited = new boolean[board.length][board[0].length];
+//                    boolean exists = doDFS(i, j, 1);
+//                    if (exists) {
+//                        return true;
+//                    }
+//                }
+//            }
+//        }
+//        return false;
+//    }
+//}
+
+
+
+/*
+单词搜索问题 (https://en.wikipedia.org/wiki/Word_search)
+
+给定一个 m x n 的字符网格 board 和一个字符串 word,如果 word 在网格中存在,则返回 true。
+
+单词可以由顺序相邻单元格的字母构成,其中“相邻”单元格是水平或垂直相邻的单元格。
+同一个字母单元格不得使用超过一次。
+
+例如,
+给定 board =
+
+[
+ ['A','B','C','E'],
+ ['S','F','C','S'],
+ ['A','D','E','E']
+]
+word = "ABCCED", -> 返回 true,
+word = "SEE", -> 返回 true,
+word = "ABCB", -> 返回 false.
+*/
+
+/*
+   解决方案
+   在矩阵中进行深度优先搜索(因为可能有多个源)并回溯
+   类似于在有向图中寻找循环。保持路径记录
+
+   时间复杂度 Tx = O(m * n * 3^L): 对于每个单元格,我们查看 3 个选项(不是 4 个,因为那个已经被访问过了),我们
+   做 L 次 空间复杂度 Sx = O(L) : 栈的大小最大为 L
+*/
+
+public class WordSearch {
+    private final int[] dx = {0, 0, 1, -1}; // x 方向的移动
+    private final int[] dy = {1, -1, 0, 0}; // y 方向的移动
+    private boolean[][] visited; // 访问标记数组
+    private char[][] board; // 字符网格
+    private String word; // 要搜索的单词
+
+    // 检查坐标 (x, y) 是否有效
+    private boolean isValid(int x, int y) {
+        return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
+    }
+
+    // 执行深度优先搜索
+    private boolean doDFS(int x, int y, int nextIdx) {
+        visited[x][y] = true;
+        if (nextIdx == word.length()) {
+            return true;
+        }
+        for (int i = 0; i < 4; ++i) {
+            int xi = x + dx[i];
+            int yi = y + dy[i];
+            if (isValid(xi, yi) && board[xi][yi] == word.charAt(nextIdx) && !visited[xi][yi]) {
+                boolean exists = doDFS(xi, yi, nextIdx + 1);
+                if (exists) {
+                    return true;
+                }
+            }
+        }
+        visited[x][y] = false; // 回溯
+        return false;
+    }
+
+    // 判断单词是否存在于网格中
+    public boolean exist(char[][] board, String word) {
+        this.board = board;
+        this.word = word;
+        for (int i = 0; i < board.length; ++i) {
+            for (int j = 0; j < board[0].length; ++j) {
+                if (board[i][j] == word.charAt(0)) {
+                    visited = new boolean[board.length][board[0].length];
+                    boolean exists = doDFS(i, j, 1);
+                    if (exists) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+}

+ 34 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/BitSwap.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+
+//public final class BitSwap {
+//    private BitSwap() {
+//    }
+//    /*
+//     * @brief Swaps the bits at the position posA and posB from data
+//     */
+//    public static int bitSwap(int data, final int posA, final int posB) {
+//        if (SingleBitOperations.getBit(data, posA) != SingleBitOperations.getBit(data, posB)) {
+//            data ^= (1 << posA) ^ (1 << posB);
+//        }
+//        return data;
+//    }
+//}
+
+
+
+public final class BitSwap {
+    private BitSwap() {
+    }
+
+    /*
+     * @brief 交换数据中位置 posA 和 posB 的位
+     */
+    public static int bitSwap(int data, final int posA, final int posB) {
+        // 如果 posA 和 posB 位置的位不同,则进行交换
+        if (SingleBitOperations.getBit(data, posA) != SingleBitOperations.getBit(data, posB)) {
+            // 通过异或操作交换位
+            data ^= (1 << posA) ^ (1 << posB);
+        }
+        return data;
+    }
+}

+ 68 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/HighestSetBit.java

@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+import java.util.Optional;
+
+///**
+// * Find Highest Set Bit
+// * This class provides a function calculating the position (or index)
+// * of the most significant bit being set to 1 in a given integer.
+// * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+// */
+//
+//public final class HighestSetBit {
+//    private HighestSetBit() {
+//    }
+//
+//    public static Optional<Integer> findHighestSetBit(int num) {
+//        if (num < 0) {
+//            throw new IllegalArgumentException("Input cannot be negative");
+//        }
+//
+//        if (num == 0) {
+//            return Optional.empty();
+//        }
+//
+//        int position = 0;
+//        while (num > 0) {
+//            num >>= 1;
+//            position++;
+//        }
+//
+//        return Optional.of(position - 1);
+//    }
+//}
+
+
+/**
+ * 查找最高设置位
+ * 这个类提供了一个函数,用于计算给定整数中被设置为 1 的最高有效位的位置(或索引)。
+ * @作者 Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+
+public final class HighestSetBit {
+    private HighestSetBit() {
+    }
+
+    // 查找最高设置位的位置
+    public static Optional<Integer> findHighestSetBit(int num) {
+        // 输入不能为负
+        if (num < 0) {
+            throw new IllegalArgumentException("输入不能为负");
+        }
+
+        // 如果数字为 0,则返回空
+        if (num == 0) {
+            return Optional.empty();
+        }
+
+        // 初始化位置
+        int position = 0;
+        // 当数字大于 0 时,右移并增加位置
+        while (num > 0) {
+            num >>= 1;
+            position++;
+        }
+
+        // 返回最高设置位的位置
+        return Optional.of(position - 1);
+    }
+}

+ 65 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+
+///**
+// * Find The Index Of Right Most SetBit
+// * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+// */
+//
+//public final class IndexOfRightMostSetBit {
+//    private IndexOfRightMostSetBit() {
+//    }
+//    public static int indexOfRightMostSetBit(int n) {
+//        if (n == 0) {
+//            return -1; // No set bits
+//        }
+//
+//        // Handle negative numbers by finding the two's complement
+//        if (n < 0) {
+//            n = -n;
+//            n = n & (~n + 1); // Get the rightmost set bit in positive form
+//        }
+//
+//        int index = 0;
+//        while ((n & 1) == 0) {
+//            n = n >> 1;
+//            index++;
+//        }
+//
+//        return index;
+//    }
+//}
+
+/**
+ * 查找最右边设置位的索引
+ * @作者 Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+
+public final class IndexOfRightMostSetBit {
+    private IndexOfRightMostSetBit() {
+    }
+
+    // 查找最右边设置位的索引
+    public static int indexOfRightMostSetBit(int n) {
+        // 如果 n 为 0,则没有设置位
+        if (n == 0) {
+            return -1;
+        }
+
+        // 处理负数,通过找到二进制补码
+        if (n < 0) {
+            n = -n;
+            n = n & (~n + 1); // 获取正数形式的最右边设置位
+        }
+
+        // 初始化索引
+        int index = 0;
+        // 当 n 的最右边位不是 1 时,右移 n 并增加索引
+        while ((n & 1) == 0) {
+            n = n >> 1;
+            index++;
+        }
+
+        // 返回最右边设置位的索引
+        return index;
+    }
+}

+ 30 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/IsEven.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+
+///**
+// * Checks whether a number is even
+// * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+// */
+//
+//public final class IsEven {
+//    private IsEven() {
+//    }
+//    public static boolean isEven(int number) {
+//        return (number & 1) == 0;
+//    }
+//}
+
+/**
+ * 检查一个数字是否为偶数
+ * @作者 Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+
+public final class IsEven {
+    private IsEven() {
+    }
+    // 判断数字是否为偶数
+    public static boolean isEven(int number) {
+        // 如果数字与 1 的位与运算结果为 0,则为偶数
+        return (number & 1) == 0;
+    }
+}
+

+ 39 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/IsPowerTwo.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+
+///**
+// * Is number power of 2
+// * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+// */
+//
+//public final class IsPowerTwo {
+//    private IsPowerTwo() {
+//    }
+//    public static boolean isPowerTwo(int number) {
+//        if (number <= 0) {
+//            return false;
+//        }
+//        int ans = number & (number - 1);
+//        return ans == 0;
+//    }
+//}
+
+/**
+ * 判断数字是否是 2 的幂
+ * @作者 Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+
+public final class IsPowerTwo {
+    private IsPowerTwo() {
+    }
+    // 判断数字是否是 2 的幂
+    public static boolean isPowerTwo(int number) {
+        // 如果数字小于等于 0,则不是 2 的幂
+        if (number <= 0) {
+            return false;
+        }
+        // 使用位运算来判断,如果 number 和 number-1 的位与运算结果为 0,则说明是 2 的幂
+        int ans = number & (number - 1);
+        return ans == 0;
+    }
+}
+

+ 42 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java

@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+
+///**
+// * Find Non Repeating Number
+// * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+// */
+//
+//public final class NonRepeatingNumberFinder {
+//    private NonRepeatingNumberFinder() {
+//    }
+//
+//    public static int findNonRepeatingNumber(int[] arr) {
+//        int result = 0;
+//        for (int num : arr) {
+//            result ^= num;
+//        }
+//        return result;
+//    }
+//}
+
+
+/**
+ * 查找不重复的数字
+ * @作者 Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+
+public final class NonRepeatingNumberFinder {
+    private NonRepeatingNumberFinder() {
+    }
+
+    // 查找数组中不重复的数字
+    public static int findNonRepeatingNumber(int[] arr) {
+        int result = 0;
+        // 遍历数组中的每个数字
+        for (int num : arr) {
+            // 对每个数字进行异或运算,最终结果即为不重复的数字
+            result ^= num;
+        }
+        // 返回结果
+        return result;
+    }
+}

+ 32 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/NumbersDifferentSigns.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+
+///**
+// * Numbers Different Signs
+// * @author Bama Charan Chhandogi
+// */
+//
+//public final class NumbersDifferentSigns {
+//    private NumbersDifferentSigns() {
+//    }
+//
+//    public static boolean differentSigns(int num1, int num2) {
+//        return (num1 ^ num2) < 0;
+//    }
+//}
+
+/**
+ * 判断两个数字是否符号不同
+ * @作者 Bama Charan Chhandogi
+ */
+
+public final class NumbersDifferentSigns {
+    private NumbersDifferentSigns() {
+    }
+
+    // 判断两个数字是否符号不同
+    public static boolean differentSigns(int num1, int num2) {
+        // 通过对两个数字进行异或操作,然后检查结果是否小于 0 来判断它们的符号是否不同
+        return (num1 ^ num2) < 0;
+    }
+}
+

+ 46 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/ReverseBits.java

@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+
+///**
+// * Converts any Octal Number to a Binary Number
+// * @author Bama Charan Chhandogi
+// */
+//
+//public final class ReverseBits {
+//    private ReverseBits() {
+//    }
+//
+//    public static int reverseBits(int n) {
+//        int result = 0;
+//        int bitCount = 32;
+//        for (int i = 0; i < bitCount; i++) {
+//            result <<= 1; // Left shift the result to make space for the next bit
+//            result |= (n & 1); // OR operation to set the least significant bit of result with the current bit of n
+//            n >>= 1; // Right shift n to move on to the next bit
+//        }
+//        return result;
+//    }
+//}
+
+
+/**
+ * 将任何八进制数转换为二进制数
+ * @作者 Bama Charan Chhandogi
+ */
+
+public final class ReverseBits {
+    private ReverseBits() {
+    }
+
+    // 反转整数 n 的位
+    public static int reverseBits(int n) {
+        int result = 0;
+        int bitCount = 32; // 整数的位数
+        for (int i = 0; i < bitCount; i++) {
+            result <<= 1; // 左移结果,为下一个位制造空间
+            result |= (n & 1); // 使用 OR 操作将 n 的当前位设置为结果的最低有效位
+            n >>= 1; // 右移 n,移动到下一个位
+        }
+        return result;
+    }
+}
+

+ 68 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/bitmanipulation/SingleBitOperations.java

@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.bitmanipulation;
+
+///*
+// * Author: lukasb1b (https://github.com/lukasb1b)
+// */
+//
+//public final class SingleBitOperations {
+//    private SingleBitOperations() {
+//    }
+//    /**
+//     * Flip the bit at position 'bit' in 'num'
+//     */
+//    public static int flipBit(final int num, final int bit) {
+//        return num ^ (1 << bit);
+//    }
+//    /**
+//     * Set the bit at position 'bit' to 1 in the 'num' variable
+//     */
+//    public static int setBit(final int num, final int bit) {
+//        return num | (1 << bit);
+//    }
+//    /**
+//     * Clears the bit located at 'bit' from 'num'
+//     */
+//    public static int clearBit(final int num, final int bit) {
+//        return num & ~(1 << bit);
+//    }
+//    /**
+//     * Get the bit located at 'bit' from 'num'
+//     */
+//    public static int getBit(final int num, final int bit) {
+//        return ((num >> bit) & 1);
+//    }
+//}
+
+
+/*
+ * 作者: lukasb1b (https://github.com/lukasb1b)
+ */
+
+public final class SingleBitOperations {
+    private SingleBitOperations() {
+    }
+    /**
+     * 在 'num' 中翻转位于 'bit' 位置的位
+     */
+    public static int flipBit(final int num, final int bit) {
+        return num ^ (1 << bit);
+    }
+    /**
+     * 将 'num' 变量中位于 'bit' 位置的位设置为 1
+     */
+    public static int setBit(final int num, final int bit) {
+        return num | (1 << bit);
+    }
+    /**
+     * 清除 'num' 中位于 'bit' 的位
+     */
+    public static int clearBit(final int num, final int bit) {
+        return num & ~(1 << bit);
+    }
+    /**
+     * 从 'num' 获取位于 'bit' 的位
+     */
+    public static int getBit(final int num, final int bit) {
+        return ((num >> bit) & 1);
+    }
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2783 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/AES.java


+ 104 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/AESEncryption.java

@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+/**
+ * This example program shows how AES encryption and decryption can be done in
+ * Java. Please note that secret key and encrypted text is unreadable binary and
+ * hence in the following program we display it in hexadecimal format of the
+ * underlying bytes.
+ */
+public final class AESEncryption {
+    private AESEncryption() {
+    }
+
+    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+    private static Cipher aesCipher;
+
+    /**
+     * 1. Generate a plain text for encryption 2. Get a secret key (printed in
+     * hexadecimal form). In actual use this must be encrypted and kept safe.
+     * The same key is required for decryption.
+     */
+    public static void main(String[] args) throws Exception {
+        String plainText = "Hello World";
+        SecretKey secKey = getSecretEncryptionKey();
+        byte[] cipherText = encryptText(plainText, secKey);
+        String decryptedText = decryptText(cipherText, secKey);
+
+        System.out.println("Original Text:" + plainText);
+        System.out.println("AES Key (Hex Form):" + bytesToHex(secKey.getEncoded()));
+        System.out.println("Encrypted Text (Hex Form):" + bytesToHex(cipherText));
+        System.out.println("Descrypted Text:" + decryptedText);
+    }
+
+    /**
+     * gets the AES encryption key. In your actual programs, this should be
+     * safely stored.
+     *
+     * @return secKey (Secret key that we encrypt using it)
+     * @throws NoSuchAlgorithmException (from KeyGenrator)
+     */
+    public static SecretKey getSecretEncryptionKey() throws NoSuchAlgorithmException {
+        KeyGenerator aesKeyGenerator = KeyGenerator.getInstance("AES");
+        aesKeyGenerator.init(128); // The AES key size in number of bits
+        return aesKeyGenerator.generateKey();
+    }
+
+    /**
+     * Encrypts plainText in AES using the secret key
+     *
+     * @return byteCipherText (The encrypted text)
+     * @throws NoSuchPaddingException (from Cipher)
+     * @throws NoSuchAlgorithmException (from Cipher)
+     * @throws InvalidKeyException (from Cipher)
+     * @throws BadPaddingException (from Cipher)
+     * @throws IllegalBlockSizeException (from Cipher)
+     */
+    public static byte[] encryptText(String plainText, SecretKey secKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+        // AES defaults to AES/ECB/PKCS5Padding in Java 7
+        aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
+        aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
+        return aesCipher.doFinal(plainText.getBytes());
+    }
+
+    /**
+     * Decrypts encrypted byte array using the key used for encryption.
+     *
+     * @return plainText
+     */
+    public static String decryptText(byte[] byteCipherText, SecretKey secKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
+        // AES defaults to AES/ECB/PKCS5Padding in Java 7
+        Cipher decryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
+        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, aesCipher.getIV());
+        decryptionCipher.init(Cipher.DECRYPT_MODE, secKey, gcmParameterSpec);
+        byte[] bytePlainText = decryptionCipher.doFinal(byteCipherText);
+        return new String(bytePlainText);
+    }
+
+    /**
+     * Convert a binary byte array into readable hex form Old library is
+     * deprecated on OpenJdk 11 and this is faster regarding other solution is
+     * using StringBuilder
+     *
+     * @return hexHash
+     */
+    public static String bytesToHex(byte[] bytes) {
+        char[] hexChars = new char[bytes.length * 2];
+        for (int j = 0; j < bytes.length; j++) {
+            int v = bytes[j] & 0xFF;
+            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
+            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
+        }
+        return new String(hexChars);
+    }
+}

+ 69 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/AffineCipher.java

@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+final class AffineCipher {
+    private AffineCipher() {
+    }
+
+    // Key values of a and b
+    static int a = 17;
+    static int b = 20;
+
+    static String encryptMessage(char[] msg) {
+        /// Cipher Text initially empty
+        String cipher = "";
+        for (int i = 0; i < msg.length; i++) {
+            // Avoid space to be encrypted
+            /* applying encryption formula ( a x + b ) mod m
+            {here x is msg[i] and m is 26} and added 'A' to
+            bring it in range of ascii alphabet[ 65-90 | A-Z ] */
+            if (msg[i] != ' ') {
+                cipher = cipher + (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A');
+            } else { // else simply append space character
+                cipher += msg[i];
+            }
+        }
+        return cipher;
+    }
+
+    static String decryptCipher(String cipher) {
+        String msg = "";
+        int aInv = 0;
+        int flag = 0;
+
+        // Find a^-1 (the multiplicative inverse of a
+        // in the group of integers modulo m.)
+        for (int i = 0; i < 26; i++) {
+            flag = (a * i) % 26;
+
+            // Check if (a*i)%26 == 1,
+            // then i will be the multiplicative inverse of a
+            if (flag == 1) {
+                aInv = i;
+            }
+        }
+        for (int i = 0; i < cipher.length(); i++) {
+            /*Applying decryption formula a^-1 ( x - b ) mod m
+            {here x is cipher[i] and m is 26} and added 'A'
+            to bring it in range of ASCII alphabet[ 65-90 | A-Z ] */
+            if (cipher.charAt(i) != ' ') {
+                msg = msg + (char) (((aInv * ((cipher.charAt(i) + 'A' - b)) % 26)) + 'A');
+            } else { // else simply append space character
+                msg += cipher.charAt(i);
+            }
+        }
+
+        return msg;
+    }
+
+    // Driver code
+    public static void main(String[] args) {
+        String msg = "AFFINE CIPHER";
+
+        // Calling encryption function
+        String cipherText = encryptMessage(msg.toCharArray());
+        System.out.println("Encrypted Message is : " + cipherText);
+
+        // Calling Decryption function
+        System.out.println("Decrypted Message is: " + decryptCipher(cipherText));
+    }
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1244 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/Blowfish.java


+ 96 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/Caesar.java

@@ -0,0 +1,96 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+/**
+ * A Java implementation of Caesar Cipher. /It is a type of substitution cipher
+ * in which each letter in the plaintext is replaced by a letter some fixed
+ * number of positions down the alphabet. /
+ *
+ * @author FAHRI YARDIMCI
+ * @author khalil2535
+ */
+public class Caesar {
+
+    /**
+     * Encrypt text by shifting every Latin char by add number shift for ASCII
+     * Example : A + 1 -> B
+     *
+     * @return Encrypted message
+     */
+    public String encode(String message, int shift) {
+        StringBuilder encoded = new StringBuilder();
+
+        shift %= 26;
+
+        final int length = message.length();
+        for (int i = 0; i < length; i++) {
+            //            int current = message.charAt(i); //using char to shift characters because
+            //            ascii
+            // is in-order latin alphabet
+            char current = message.charAt(i); // Java law : char + int = char
+
+            if (isCapitalLatinLetter(current)) {
+                current += shift;
+                encoded.append((char) (current > 'Z' ? current - 26 : current)); // 26 = number of latin letters
+            } else if (isSmallLatinLetter(current)) {
+                current += shift;
+                encoded.append((char) (current > 'z' ? current - 26 : current)); // 26 = number of latin letters
+            } else {
+                encoded.append(current);
+            }
+        }
+        return encoded.toString();
+    }
+
+    /**
+     * Decrypt message by shifting back every Latin char to previous the ASCII
+     * Example : B - 1 -> A
+     *
+     * @return message
+     */
+    public String decode(String encryptedMessage, int shift) {
+        StringBuilder decoded = new StringBuilder();
+
+        shift %= 26;
+
+        final int length = encryptedMessage.length();
+        for (int i = 0; i < length; i++) {
+            char current = encryptedMessage.charAt(i);
+            if (isCapitalLatinLetter(current)) {
+                current -= shift;
+                decoded.append((char) (current < 'A' ? current + 26 : current)); // 26 = number of latin letters
+            } else if (isSmallLatinLetter(current)) {
+                current -= shift;
+                decoded.append((char) (current < 'a' ? current + 26 : current)); // 26 = number of latin letters
+            } else {
+                decoded.append(current);
+            }
+        }
+        return decoded.toString();
+    }
+
+    /**
+     * @return true if character is capital Latin letter or false for others
+     */
+    private static boolean isCapitalLatinLetter(char c) {
+        return c >= 'A' && c <= 'Z';
+    }
+
+    /**
+     * @return true if character is small Latin letter or false for others
+     */
+    private static boolean isSmallLatinLetter(char c) {
+        return c >= 'a' && c <= 'z';
+    }
+
+    /**
+     *  @return string array which contains all the possible decoded combination.
+     */
+    public String[] bruteforce(String encryptedMessage) {
+        String[] listOfAllTheAnswers = new String[27];
+        for (int i = 0; i <= 26; i++) {
+            listOfAllTheAnswers[i] = decode(encryptedMessage, i);
+        }
+
+        return listOfAllTheAnswers;
+    }
+}

+ 207 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/ColumnarTranspositionCipher.java

@@ -0,0 +1,207 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+import java.util.Objects;
+
+/**
+ * Columnar Transposition Cipher Encryption and Decryption.
+ *
+ * @author <a href="https://github.com/freitzzz">freitzzz</a>
+ */
+public final class ColumnarTranspositionCipher {
+    private ColumnarTranspositionCipher() {
+    }
+
+    private static String keyword;
+    private static Object[][] table;
+    private static String abecedarium;
+    public static final String ABECEDARIUM = "abcdefghijklmnopqrstuvwxyzABCDEFG"
+        + "HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@";
+    private static final String ENCRYPTION_FIELD = "≈";
+    private static final char ENCRYPTION_FIELD_CHAR = '≈';
+
+    /**
+     * Encrypts a certain String with the Columnar Transposition Cipher Rule
+     *
+     * @param word Word being encrypted
+     * @param keyword String with keyword being used
+     * @return a String with the word encrypted by the Columnar Transposition
+     * Cipher Rule
+     */
+    public static String encrpyter(String word, String keyword) {
+        ColumnarTranspositionCipher.keyword = keyword;
+        abecedariumBuilder(500);
+        table = tableBuilder(word);
+        Object[][] sortedTable = sortTable(table);
+        StringBuilder wordEncrypted = new StringBuilder();
+        for (int i = 0; i < sortedTable[i].length; i++) {
+            for (int j = 1; j < sortedTable.length; j++) {
+                wordEncrypted.append(sortedTable[j][i]);
+            }
+        }
+        return wordEncrypted.toString();
+    }
+
+    /**
+     * Encrypts a certain String with the Columnar Transposition Cipher Rule
+     *
+     * @param word Word being encrypted
+     * @param keyword String with keyword being used
+     * @param abecedarium String with the abecedarium being used. null for
+     * default one
+     * @return a String with the word encrypted by the Columnar Transposition
+     * Cipher Rule
+     */
+    public static String encrpyter(String word, String keyword, String abecedarium) {
+        ColumnarTranspositionCipher.keyword = keyword;
+        ColumnarTranspositionCipher.abecedarium = Objects.requireNonNullElse(abecedarium, ABECEDARIUM);
+        table = tableBuilder(word);
+        Object[][] sortedTable = sortTable(table);
+        StringBuilder wordEncrypted = new StringBuilder();
+        for (int i = 0; i < sortedTable[0].length; i++) {
+            for (int j = 1; j < sortedTable.length; j++) {
+                wordEncrypted.append(sortedTable[j][i]);
+            }
+        }
+        return wordEncrypted.toString();
+    }
+
+    /**
+     * Decrypts a certain encrypted String with the Columnar Transposition
+     * Cipher Rule
+     *
+     * @return a String decrypted with the word encrypted by the Columnar
+     * Transposition Cipher Rule
+     */
+    public static String decrypter() {
+        StringBuilder wordDecrypted = new StringBuilder();
+        for (int i = 1; i < table.length; i++) {
+            for (Object item : table[i]) {
+                wordDecrypted.append(item);
+            }
+        }
+        return wordDecrypted.toString().replaceAll(ENCRYPTION_FIELD, "");
+    }
+
+    /**
+     * Builds a table with the word to be encrypted in rows by the Columnar
+     * Transposition Cipher Rule
+     *
+     * @return An Object[][] with the word to be encrypted filled in rows and
+     * columns
+     */
+    private static Object[][] tableBuilder(String word) {
+        Object[][] table = new Object[numberOfRows(word) + 1][keyword.length()];
+        char[] wordInChards = word.toCharArray();
+        // Fils in the respective numbers
+        table[0] = findElements();
+        int charElement = 0;
+        for (int i = 1; i < table.length; i++) {
+            for (int j = 0; j < table[i].length; j++) {
+                if (charElement < wordInChards.length) {
+                    table[i][j] = wordInChards[charElement];
+                    charElement++;
+                } else {
+                    table[i][j] = ENCRYPTION_FIELD_CHAR;
+                }
+            }
+        }
+        return table;
+    }
+
+    /**
+     * Determines the number of rows the table should have regarding the
+     * Columnar Transposition Cipher Rule
+     *
+     * @return an int with the number of rows that the table should have in
+     * order to respect the Columnar Transposition Cipher Rule.
+     */
+    private static int numberOfRows(String word) {
+        if (word.length() / keyword.length() > word.length() / keyword.length()) {
+            return (word.length() / keyword.length()) + 1;
+        } else {
+            return word.length() / keyword.length();
+        }
+    }
+
+    /**
+     * @return charValues
+     */
+    private static Object[] findElements() {
+        Object[] charValues = new Object[keyword.length()];
+        for (int i = 0; i < charValues.length; i++) {
+            int charValueIndex = abecedarium.indexOf(keyword.charAt(i));
+            charValues[i] = charValueIndex > -1 ? charValueIndex : null;
+        }
+        return charValues;
+    }
+
+    /**
+     * @return tableSorted
+     */
+    private static Object[][] sortTable(Object[][] table) {
+        Object[][] tableSorted = new Object[table.length][table[0].length];
+        for (int i = 0; i < tableSorted.length; i++) {
+            System.arraycopy(table[i], 0, tableSorted[i], 0, tableSorted[i].length);
+        }
+        for (int i = 0; i < tableSorted[0].length; i++) {
+            for (int j = i + 1; j < tableSorted[0].length; j++) {
+                if ((int) tableSorted[0][i] > (int) table[0][j]) {
+                    Object[] column = getColumn(tableSorted, tableSorted.length, i);
+                    switchColumns(tableSorted, j, i, column);
+                }
+            }
+        }
+        return tableSorted;
+    }
+
+    /**
+     * @return columnArray
+     */
+    private static Object[] getColumn(Object[][] table, int rows, int column) {
+        Object[] columnArray = new Object[rows];
+        for (int i = 0; i < rows; i++) {
+            columnArray[i] = table[i][column];
+        }
+        return columnArray;
+    }
+
+    private static void switchColumns(Object[][] table, int firstColumnIndex, int secondColumnIndex, Object[] columnToSwitch) {
+        for (int i = 0; i < table.length; i++) {
+            table[i][secondColumnIndex] = table[i][firstColumnIndex];
+            table[i][firstColumnIndex] = columnToSwitch[i];
+        }
+    }
+
+    /**
+     * Creates an abecedarium with a specified ascii inded
+     *
+     * @param value Number of characters being used based on the ASCII Table
+     */
+    private static void abecedariumBuilder(int value) {
+        StringBuilder t = new StringBuilder();
+        for (int i = 0; i < value; i++) {
+            t.append((char) i);
+        }
+        abecedarium = t.toString();
+    }
+
+    private static void showTable() {
+        for (Object[] table1 : table) {
+            for (Object item : table1) {
+                System.out.print(item + " ");
+            }
+            System.out.println();
+        }
+    }
+
+    public static void main(String[] args) {
+        String keywordForExample = "asd215";
+        String wordBeingEncrypted = "This is a test of the Columnar Transposition Cipher";
+        System.out.println("### Example of Columnar Transposition Cipher ###\n");
+        System.out.println("Word being encryped ->>> " + wordBeingEncrypted);
+        System.out.println("Word encrypted ->>> " + ColumnarTranspositionCipher.encrpyter(wordBeingEncrypted, keywordForExample));
+        System.out.println("Word decryped ->>> " + ColumnarTranspositionCipher.decrypter());
+        System.out.println("\n### Encrypted Table ###");
+        showTable();
+    }
+}

+ 250 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/DES.java

@@ -0,0 +1,250 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+/**
+ * This class is build to demonstrate the application of the DES-algorithm
+ * (https://en.wikipedia.org/wiki/Data_Encryption_Standard) on a plain English message. The supplied
+ * key must be in form of a 64 bit binary String.
+ */
+public class DES {
+
+    private String key;
+    private final String[] subKeys;
+
+    private void sanitize(String key) {
+        int length = key.length();
+        if (length != 64) {
+            throw new IllegalArgumentException("DES key must be supplied as a 64 character binary string");
+        }
+    }
+
+    DES(String key) {
+        sanitize(key);
+        this.key = key;
+        subKeys = getSubkeys(key);
+    }
+
+    public String getKey() {
+        return this.key;
+    }
+
+    public void setKey(String key) {
+        sanitize(key);
+        this.key = key;
+    }
+
+    // Permutation table to convert initial 64-bit key to 56 bit key
+    private static final int[] PC1 = {57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4};
+
+    // Lookup table used to shift the initial key, in order to generate the subkeys
+    private static final int[] KEY_SHIFTS = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
+
+    // Table to convert the 56 bit subkeys to 48 bit subkeys
+    private static final int[] PC2 = {14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32};
+
+    // Initial permutation of each 64 but message block
+    private static final int[] IP = {58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7};
+
+    // Expansion table to convert right half of message blocks from 32 bits to 48 bits
+    private static final int[] EXPANSION = {32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1};
+
+    // The eight substitution boxes are defined below
+    private static final int[][] S1 = {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}};
+
+    private static final int[][] S2 = {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}};
+
+    private static final int[][] S3 = {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}};
+
+    private static final int[][] S4 = {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}};
+
+    private static final int[][] S5 = {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}};
+
+    private static final int[][] S6 = {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}};
+
+    private static final int[][] S7 = {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}};
+
+    private static final int[][] S8 = {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}};
+
+    private static final int[][][] S = {S1, S2, S3, S4, S5, S6, S7, S8};
+
+    // Permutation table, used in the Feistel function post s-box usage
+    static final int[] PERMUTATION = {16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25};
+
+    // Table used for final inversion of the message box after 16 rounds of Feistel Function
+    static final int[] IP_INVERSE = {40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25};
+
+    private String[] getSubkeys(String originalKey) {
+        StringBuilder permutedKey = new StringBuilder(); // Initial permutation of keys via pc1
+        int i;
+        int j;
+        for (i = 0; i < 56; i++) {
+            permutedKey.append(originalKey.charAt(PC1[i] - 1));
+        }
+        String[] subKeys = new String[16];
+        String initialPermutedKey = permutedKey.toString();
+        String c0 = initialPermutedKey.substring(0, 28);
+        String d0 = initialPermutedKey.substring(28);
+
+        // We will now operate on the left and right halves of the permutedKey
+        for (i = 0; i < 16; i++) {
+            String cN = c0.substring(KEY_SHIFTS[i]) + c0.substring(0, KEY_SHIFTS[i]);
+            String dN = d0.substring(KEY_SHIFTS[i]) + d0.substring(0, KEY_SHIFTS[i]);
+            subKeys[i] = cN + dN;
+            c0 = cN; // Re-assign the values to create running permutation
+            d0 = dN;
+        }
+
+        // Let us shrink the keys to 48 bits (well, characters here) using pc2
+        for (i = 0; i < 16; i++) {
+            String key = subKeys[i];
+            permutedKey.setLength(0);
+            for (j = 0; j < 48; j++) {
+                permutedKey.append(key.charAt(PC2[j] - 1));
+            }
+            subKeys[i] = permutedKey.toString();
+        }
+
+        return subKeys;
+    }
+
+    private String xOR(String a, String b) {
+        int i;
+        int l = a.length();
+        StringBuilder xor = new StringBuilder();
+        for (i = 0; i < l; i++) {
+            int firstBit = a.charAt(i) - 48; // 48 is '0' in ascii
+            int secondBit = b.charAt(i) - 48;
+            xor.append((firstBit ^ secondBit));
+        }
+        return xor.toString();
+    }
+
+    private String createPaddedString(String s, int desiredLength, char pad) {
+        int i;
+        int l = s.length();
+        StringBuilder paddedString = new StringBuilder();
+        int diff = desiredLength - l;
+        for (i = 0; i < diff; i++) {
+            paddedString.append(pad);
+        }
+        return paddedString.toString();
+    }
+
+    private String pad(String s, int desiredLength) {
+        return createPaddedString(s, desiredLength, '0') + s;
+    }
+
+    private String padLast(String s, int desiredLength) {
+        return s + createPaddedString(s, desiredLength, '\u0000');
+    }
+
+    private String feistel(String messageBlock, String key) {
+        int i;
+        StringBuilder expandedKey = new StringBuilder();
+        for (i = 0; i < 48; i++) {
+            expandedKey.append(messageBlock.charAt(EXPANSION[i] - 1));
+        }
+        String mixedKey = xOR(expandedKey.toString(), key);
+        StringBuilder substitutedString = new StringBuilder();
+
+        // Let us now use the s-boxes to transform each 6 bit (length here) block to 4 bits
+        for (i = 0; i < 48; i += 6) {
+            String block = mixedKey.substring(i, i + 6);
+            int row = (block.charAt(0) - 48) * 2 + (block.charAt(5) - 48);
+            int col = (block.charAt(1) - 48) * 8 + (block.charAt(2) - 48) * 4 + (block.charAt(3) - 48) * 2 + (block.charAt(4) - 48);
+            String substitutedBlock = pad(Integer.toBinaryString(S[i / 6][row][col]), 4);
+            substitutedString.append(substitutedBlock);
+        }
+
+        StringBuilder permutedString = new StringBuilder();
+        for (i = 0; i < 32; i++) {
+            permutedString.append(substitutedString.charAt(PERMUTATION[i] - 1));
+        }
+
+        return permutedString.toString();
+    }
+
+    private String encryptBlock(String message, String[] keys) {
+        StringBuilder permutedMessage = new StringBuilder();
+        int i;
+        for (i = 0; i < 64; i++) {
+            permutedMessage.append(message.charAt(IP[i] - 1));
+        }
+        String e0 = permutedMessage.substring(0, 32);
+        String f0 = permutedMessage.substring(32);
+
+        // Iterate 16 times
+        for (i = 0; i < 16; i++) {
+            String eN = f0; // Previous Right block
+            String fN = xOR(e0, feistel(f0, keys[i]));
+            e0 = eN;
+            f0 = fN;
+        }
+
+        String combinedBlock = f0 + e0; // Reverse the 16th block
+        permutedMessage.setLength(0);
+        for (i = 0; i < 64; i++) {
+            permutedMessage.append(combinedBlock.charAt(IP_INVERSE[i] - 1));
+        }
+        return permutedMessage.toString();
+    }
+
+    // To decode, we follow the same process as encoding, but with reversed keys
+    private String decryptBlock(String message, String[] keys) {
+        String[] reversedKeys = new String[keys.length];
+        for (int i = 0; i < keys.length; i++) {
+            reversedKeys[i] = keys[keys.length - i - 1];
+        }
+        return encryptBlock(message, reversedKeys);
+    }
+
+    /**
+     * @param message Message to be encrypted
+     * @return The encrypted message, as a binary string
+     */
+    public String encrypt(String message) {
+        StringBuilder encryptedMessage = new StringBuilder();
+        int l = message.length();
+        int i;
+        int j;
+        if (l % 8 != 0) {
+            int desiredLength = (l / 8 + 1) * 8;
+            l = desiredLength;
+            message = padLast(message, desiredLength);
+        }
+
+        for (i = 0; i < l; i += 8) {
+            String block = message.substring(i, i + 8);
+            StringBuilder bitBlock = new StringBuilder();
+            byte[] bytes = block.getBytes();
+            for (j = 0; j < 8; j++) {
+                bitBlock.append(pad(Integer.toBinaryString(bytes[j]), 8));
+            }
+            encryptedMessage.append(encryptBlock(bitBlock.toString(), subKeys));
+        }
+        return encryptedMessage.toString();
+    }
+
+    /**
+     * @param message The encrypted string. Expects it to be a multiple of 64 bits, in binary format
+     * @return The decrypted String, in plain English
+     */
+    public String decrypt(String message) {
+        StringBuilder decryptedMessage = new StringBuilder();
+        int l = message.length();
+        int i;
+        int j;
+        if (l % 64 != 0) {
+            throw new IllegalArgumentException("Encrypted message should be a multiple of 64 characters in length");
+        }
+        for (i = 0; i < l; i += 64) {
+            String block = message.substring(i, i + 64);
+            String result = decryptBlock(block, subKeys);
+            byte[] res = new byte[8];
+            for (j = 0; j < 64; j += 8) {
+                res[j / 8] = (byte) Integer.parseInt(result.substring(j, j + 8), 2);
+            }
+            decryptedMessage.append(new String(res));
+        }
+        return decryptedMessage.toString().replace("\0", ""); // Get rid of the null bytes used for padding
+    }
+}

+ 178 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/HillCipher.java

@@ -0,0 +1,178 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+import java.util.Scanner;
+
+/*
+ * Java Implementation of Hill Cipher
+ * Hill cipher is a polyalphabetic substitution cipher. Each letter is represented by a number
+ * belonging to the set Z26 where A=0 , B=1, ..... Z=25. To encrypt a message, each block of n
+ * letters (since matrix size is n x n) is multiplied by an invertible n × n matrix, against
+ * modulus 26. To decrypt the message, each block is multiplied by the inverse of the matrix used
+ * for encryption. The cipher key and plaintext/ciphertext are user inputs.
+ * @author Ojasva Jain
+ */
+public final class HillCipher {
+    private HillCipher() {
+    }
+
+    static Scanner userInput = new Scanner(System.in);
+
+    /* Following function encrypts the message
+     */
+    static void encrypt(String message) {
+        message = message.toUpperCase();
+        // Get key matrix
+        System.out.println("Enter key matrix size");
+        int matrixSize = userInput.nextInt();
+        System.out.println("Enter Key/encryptionKey matrix ");
+        int[][] keyMatrix = new int[matrixSize][matrixSize];
+        for (int i = 0; i < matrixSize; i++) {
+            for (int j = 0; j < matrixSize; j++) {
+                keyMatrix[i][j] = userInput.nextInt();
+            }
+        }
+        // check if det = 0
+        validateDeterminant(keyMatrix, matrixSize);
+
+        int[][] messageVector = new int[matrixSize][1];
+        String cipherText = "";
+        int[][] cipherMatrix = new int[matrixSize][1];
+        int j = 0;
+        while (j < message.length()) {
+            for (int i = 0; i < matrixSize; i++) {
+                if (j >= message.length()) {
+                    messageVector[i][0] = 23;
+                } else {
+                    messageVector[i][0] = (message.charAt(j)) % 65;
+                }
+                System.out.println(messageVector[i][0]);
+                j++;
+            }
+            int x;
+            int i;
+            for (i = 0; i < matrixSize; i++) {
+                cipherMatrix[i][0] = 0;
+
+                for (x = 0; x < matrixSize; x++) {
+                    cipherMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0];
+                }
+                System.out.println(cipherMatrix[i][0]);
+                cipherMatrix[i][0] = cipherMatrix[i][0] % 26;
+            }
+            for (i = 0; i < matrixSize; i++) {
+                cipherText += (char) (cipherMatrix[i][0] + 65);
+            }
+        }
+        System.out.println("Ciphertext: " + cipherText);
+    }
+
+    // Following function decrypts a message
+    static void decrypt(String message) {
+        message = message.toUpperCase();
+        // Get key matrix
+        System.out.println("Enter key matrix size");
+        int n = userInput.nextInt();
+        System.out.println("Enter inverseKey/decryptionKey matrix ");
+        int[][] keyMatrix = new int[n][n];
+        for (int i = 0; i < n; i++) {
+            for (int j = 0; j < n; j++) {
+                keyMatrix[i][j] = userInput.nextInt();
+            }
+        }
+        // check if det = 0
+        validateDeterminant(keyMatrix, n);
+
+        // solving for the required plaintext message
+        int[][] messageVector = new int[n][1];
+        String plainText = "";
+        int[][] plainMatrix = new int[n][1];
+        int j = 0;
+        while (j < message.length()) {
+            for (int i = 0; i < n; i++) {
+                if (j >= message.length()) {
+                    messageVector[i][0] = 23;
+                } else {
+                    messageVector[i][0] = (message.charAt(j)) % 65;
+                }
+                System.out.println(messageVector[i][0]);
+                j++;
+            }
+            int x;
+            int i;
+            for (i = 0; i < n; i++) {
+                plainMatrix[i][0] = 0;
+
+                for (x = 0; x < n; x++) {
+                    plainMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0];
+                }
+
+                plainMatrix[i][0] = plainMatrix[i][0] % 26;
+            }
+            for (i = 0; i < n; i++) {
+                plainText += (char) (plainMatrix[i][0] + 65);
+            }
+        }
+        System.out.println("Plaintext: " + plainText);
+    }
+
+    // Determinant calculator
+    public static int determinant(int[][] a, int n) {
+        int det = 0;
+        int sign = 1;
+        int p = 0;
+        int q = 0;
+
+        if (n == 1) {
+            det = a[0][0];
+        } else {
+            int[][] b = new int[n - 1][n - 1];
+            for (int x = 0; x < n; x++) {
+                p = 0;
+                q = 0;
+                for (int i = 1; i < n; i++) {
+                    for (int j = 0; j < n; j++) {
+                        if (j != x) {
+                            b[p][q++] = a[i][j];
+                            if (q % (n - 1) == 0) {
+                                p++;
+                                q = 0;
+                            }
+                        }
+                    }
+                }
+                det = det + a[0][x] * determinant(b, n - 1) * sign;
+                sign = -sign;
+            }
+        }
+        return det;
+    }
+
+    // Function to implement Hill Cipher
+    static void hillCipher(String message) {
+        System.out.println("What do you want to process from the message?");
+        System.out.println("Press 1: To Encrypt");
+        System.out.println("Press 2: To Decrypt");
+        short sc = userInput.nextShort();
+        if (sc == 1) {
+            encrypt(message);
+        } else if (sc == 2) {
+            decrypt(message);
+        } else {
+            System.out.println("Invalid input, program terminated.");
+        }
+    }
+
+    static void validateDeterminant(int[][] keyMatrix, int n) {
+        if (determinant(keyMatrix, n) % 26 == 0) {
+            System.out.println("Invalid key, as determinant = 0. Program Terminated");
+        }
+    }
+
+    // Driver code
+    public static void main(String[] args) {
+        // Get the message to be encrypted
+        System.out.println("Enter message");
+        String message = userInput.nextLine();
+        hillCipher(message);
+    }
+}

+ 128 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/PlayfairCipher.java

@@ -0,0 +1,128 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+public class PlayfairCipher {
+
+    private char[][] matrix;
+    private String key;
+
+    public PlayfairCipher(String key) {
+        this.key = key;
+        generateMatrix();
+    }
+
+    public String encrypt(String plaintext) {
+        plaintext = prepareText(plaintext.replace("J", "I"));
+        StringBuilder ciphertext = new StringBuilder();
+        for (int i = 0; i < plaintext.length(); i += 2) {
+            char char1 = plaintext.charAt(i);
+            char char2 = plaintext.charAt(i + 1);
+            int[] pos1 = findPosition(char1);
+            int[] pos2 = findPosition(char2);
+            int row1 = pos1[0];
+            int col1 = pos1[1];
+            int row2 = pos2[0];
+            int col2 = pos2[1];
+            if (row1 == row2) {
+                ciphertext.append(matrix[row1][(col1 + 1) % 5]);
+                ciphertext.append(matrix[row2][(col2 + 1) % 5]);
+            } else if (col1 == col2) {
+                ciphertext.append(matrix[(row1 + 1) % 5][col1]);
+                ciphertext.append(matrix[(row2 + 1) % 5][col2]);
+            } else {
+                ciphertext.append(matrix[row1][col2]);
+                ciphertext.append(matrix[row2][col1]);
+            }
+        }
+        return ciphertext.toString();
+    }
+
+    public String decrypt(String ciphertext) {
+        StringBuilder plaintext = new StringBuilder();
+        for (int i = 0; i < ciphertext.length(); i += 2) {
+            char char1 = ciphertext.charAt(i);
+            char char2 = ciphertext.charAt(i + 1);
+            int[] pos1 = findPosition(char1);
+            int[] pos2 = findPosition(char2);
+            int row1 = pos1[0];
+            int col1 = pos1[1];
+            int row2 = pos2[0];
+            int col2 = pos2[1];
+            if (row1 == row2) {
+                plaintext.append(matrix[row1][(col1 + 4) % 5]);
+                plaintext.append(matrix[row2][(col2 + 4) % 5]);
+            } else if (col1 == col2) {
+                plaintext.append(matrix[(row1 + 4) % 5][col1]);
+                plaintext.append(matrix[(row2 + 4) % 5][col2]);
+            } else {
+                plaintext.append(matrix[row1][col2]);
+                plaintext.append(matrix[row2][col1]);
+            }
+        }
+        return plaintext.toString();
+    }
+
+    private void generateMatrix() {
+        String keyWithoutDuplicates = removeDuplicateChars(key + "ABCDEFGHIKLMNOPQRSTUVWXYZ");
+        matrix = new char[5][5];
+        int index = 0;
+        for (int i = 0; i < 5; i++) {
+            for (int j = 0; j < 5; j++) {
+                matrix[i][j] = keyWithoutDuplicates.charAt(index);
+                index++;
+            }
+        }
+    }
+
+    private String removeDuplicateChars(String str) {
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i < str.length(); i++) {
+            if (result.indexOf(String.valueOf(str.charAt(i))) == -1) {
+                result.append(str.charAt(i));
+            }
+        }
+        return result.toString();
+    }
+
+    private String prepareText(String text) {
+        text = text.toUpperCase().replaceAll("[^A-Z]", "");
+        StringBuilder preparedText = new StringBuilder();
+        char prevChar = '\0';
+        for (char c : text.toCharArray()) {
+            if (c != prevChar) {
+                preparedText.append(c);
+                prevChar = c;
+            } else {
+                preparedText.append('X').append(c);
+                prevChar = '\0';
+            }
+        }
+        if (preparedText.length() % 2 != 0) {
+            preparedText.append('X');
+        }
+        return preparedText.toString();
+    }
+
+    private int[] findPosition(char c) {
+        int[] pos = new int[2];
+        for (int i = 0; i < 5; i++) {
+            for (int j = 0; j < 5; j++) {
+                if (matrix[i][j] == c) {
+                    pos[0] = i;
+                    pos[1] = j;
+                    return pos;
+                }
+            }
+        }
+        return pos;
+    }
+
+    public void printMatrix() {
+        System.out.println("\nPlayfair Cipher Matrix:");
+        for (int i = 0; i < 5; i++) {
+            for (int j = 0; j < 5; j++) {
+                System.out.print(matrix[i][j] + " ");
+            }
+            System.out.println();
+        }
+    }
+}

+ 62 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/Polybius.java

@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+/**
+ * A Java implementation of Polybius Cipher
+ * Polybius is a substitution cipher method
+ * It was invented by a greek philosopher that name is Polybius
+ * Letters in alphabet takes place to two dimension table.
+ * Encrypted text is created according to row and column in two dimension table
+ * Decrypted text is generated by looking at the row and column respectively
+ * Additionally, some letters in english alphabet deliberately throws such as U because U is very
+ * similar with V
+ *
+ * @author Hikmet ÇAKIR
+ * @since 08-07-2022+03:00
+ */
+public final class Polybius {
+    private Polybius() {
+    }
+
+    private static final char[][] KEY = {
+        //         0    1    2    3    4
+        /* 0 */ {'A', 'B', 'C', 'D', 'E'},
+        /* 1 */ {'F', 'G', 'H', 'I', 'J'},
+        /* 2 */ {'K', 'L', 'M', 'N', 'O'},
+        /* 3 */ {'P', 'Q', 'R', 'S', 'T'},
+        /* 4 */ {'V', 'W', 'X', 'Y', 'Z'},
+    };
+
+    private static String findLocationByCharacter(final char character) {
+        final StringBuilder location = new StringBuilder();
+        for (int i = 0; i < KEY.length; i++) {
+            for (int j = 0; j < KEY[i].length; j++) {
+                if (character == KEY[i][j]) {
+                    location.append(i).append(j);
+                    break;
+                }
+            }
+        }
+        return location.toString();
+    }
+
+    public static String encrypt(final String plaintext) {
+        final char[] chars = plaintext.toUpperCase().toCharArray();
+        final StringBuilder ciphertext = new StringBuilder();
+        for (char aChar : chars) {
+            String location = findLocationByCharacter(aChar);
+            ciphertext.append(location);
+        }
+        return ciphertext.toString();
+    }
+
+    public static String decrypt(final String ciphertext) {
+        final char[] chars = ciphertext.toCharArray();
+        final StringBuilder plaintext = new StringBuilder();
+        for (int i = 0; i < chars.length; i += 2) {
+            int pozitionX = Character.getNumericValue(chars[i]);
+            int pozitionY = Character.getNumericValue(chars[i + 1]);
+            plaintext.append(KEY[pozitionX][pozitionY]);
+        }
+        return plaintext.toString();
+    }
+}

+ 73 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/ProductCipher.java

@@ -0,0 +1,73 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+import java.util.Scanner;
+
+final class ProductCipher {
+    private ProductCipher() {
+    }
+
+    public static void main(String[] args) {
+        try (Scanner sc = new Scanner(System.in)) {
+            System.out.println("Enter the input to be encrypted: ");
+            String substitutionInput = sc.nextLine();
+            System.out.println(" ");
+            System.out.println("Enter a number: ");
+            int n = sc.nextInt();
+
+            // Substitution encryption
+            StringBuffer substitutionOutput = new StringBuffer();
+            for (int i = 0; i < substitutionInput.length(); i++) {
+                char c = substitutionInput.charAt(i);
+                substitutionOutput.append((char) (c + 5));
+            }
+            System.out.println(" ");
+            System.out.println("Substituted text: ");
+            System.out.println(substitutionOutput);
+
+            // Transposition encryption
+            String transpositionInput = substitutionOutput.toString();
+            int modulus = transpositionInput.length() % n;
+            if (modulus != 0) {
+                modulus = n - modulus;
+
+                for (; modulus != 0; modulus--) {
+                    transpositionInput += "/";
+                }
+            }
+            StringBuffer transpositionOutput = new StringBuffer();
+            System.out.println(" ");
+            System.out.println("Transposition Matrix: ");
+            for (int i = 0; i < n; i++) {
+                for (int j = 0; j < transpositionInput.length() / n; j++) {
+                    char c = transpositionInput.charAt(i + (j * n));
+                    System.out.print(c);
+                    transpositionOutput.append(c);
+                }
+                System.out.println();
+            }
+            System.out.println(" ");
+            System.out.println("Final encrypted text: ");
+            System.out.println(transpositionOutput);
+
+            // Transposition decryption
+            n = transpositionOutput.length() / n;
+            StringBuffer transpositionPlaintext = new StringBuffer();
+            for (int i = 0; i < n; i++) {
+                for (int j = 0; j < transpositionOutput.length() / n; j++) {
+                    char c = transpositionOutput.charAt(i + (j * n));
+                    transpositionPlaintext.append(c);
+                }
+            }
+
+            // Substitution decryption
+            StringBuffer plaintext = new StringBuffer();
+            for (int i = 0; i < transpositionPlaintext.length(); i++) {
+                char c = transpositionPlaintext.charAt(i);
+                plaintext.append((char) (c - 5));
+            }
+
+            System.out.println("Plaintext: ");
+            System.out.println(plaintext);
+        }
+    }
+}

+ 66 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/RSA.java

@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * @author Nguyen Duy Tiep on 23-Oct-17.
+ */
+public class RSA {
+
+    private BigInteger modulus;
+    private BigInteger privateKey;
+    private BigInteger publicKey;
+
+    public RSA(int bits) {
+        generateKeys(bits);
+    }
+
+    /**
+     * @return encrypted message
+     */
+    public synchronized String encrypt(String message) {
+        return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString();
+    }
+
+    /**
+     * @return encrypted message as big integer
+     */
+    public synchronized BigInteger encrypt(BigInteger message) {
+        return message.modPow(publicKey, modulus);
+    }
+
+    /**
+     * @return plain message
+     */
+    public synchronized String decrypt(String encryptedMessage) {
+        return new String((new BigInteger(encryptedMessage)).modPow(privateKey, modulus).toByteArray());
+    }
+
+    /**
+     * @return plain message as big integer
+     */
+    public synchronized BigInteger decrypt(BigInteger encryptedMessage) {
+        return encryptedMessage.modPow(privateKey, modulus);
+    }
+
+    /**
+     * Generate a new public and private key set.
+     */
+    public final synchronized void generateKeys(int bits) {
+        SecureRandom r = new SecureRandom();
+        BigInteger p = new BigInteger(bits / 2, 100, r);
+        BigInteger q = new BigInteger(bits / 2, 100, r);
+        modulus = p.multiply(q);
+
+        BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
+
+        publicKey = BigInteger.valueOf(3L);
+
+        while (m.gcd(publicKey).intValue() > 1) {
+            publicKey = publicKey.add(BigInteger.TWO);
+        }
+
+        privateKey = publicKey.modInverse(m);
+    }
+}

+ 85 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/SimpleSubCipher.java

@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The simple substitution cipher is a cipher that has been in use for many
+ * hundreds of years (an excellent history is given in Simon Singhs 'the Code
+ * Book'). It basically consists of substituting every plaintext character for a
+ * different ciphertext character. It differs from the Caesar cipher in that the
+ * cipher alphabet is not simply the alphabet shifted, it is completely jumbled.
+ */
+public class SimpleSubCipher {
+
+    /**
+     * Encrypt text by replacing each element with its opposite character.
+     *
+     * @param message
+     * @param cipherSmall
+     * @return Encrypted message
+     */
+    public String encode(String message, String cipherSmall) {
+        StringBuilder encoded = new StringBuilder();
+
+        // This map is used to encode
+        Map<Character, Character> cipherMap = new HashMap<>();
+
+        char beginSmallLetter = 'a';
+        char beginCapitalLetter = 'A';
+
+        cipherSmall = cipherSmall.toLowerCase();
+        String cipherCapital = cipherSmall.toUpperCase();
+
+        // To handle Small and Capital letters
+        for (int i = 0; i < cipherSmall.length(); i++) {
+            cipherMap.put(beginSmallLetter++, cipherSmall.charAt(i));
+            cipherMap.put(beginCapitalLetter++, cipherCapital.charAt(i));
+        }
+
+        for (int i = 0; i < message.length(); i++) {
+            if (Character.isAlphabetic(message.charAt(i))) {
+                encoded.append(cipherMap.get(message.charAt(i)));
+            } else {
+                encoded.append(message.charAt(i));
+            }
+        }
+
+        return encoded.toString();
+    }
+
+    /**
+     * Decrypt message by replacing each element with its opposite character in
+     * cipher.
+     *
+     * @param encryptedMessage
+     * @param cipherSmall
+     * @return message
+     */
+    public String decode(String encryptedMessage, String cipherSmall) {
+        StringBuilder decoded = new StringBuilder();
+
+        Map<Character, Character> cipherMap = new HashMap<>();
+
+        char beginSmallLetter = 'a';
+        char beginCapitalLetter = 'A';
+
+        cipherSmall = cipherSmall.toLowerCase();
+        String cipherCapital = cipherSmall.toUpperCase();
+
+        for (int i = 0; i < cipherSmall.length(); i++) {
+            cipherMap.put(cipherSmall.charAt(i), beginSmallLetter++);
+            cipherMap.put(cipherCapital.charAt(i), beginCapitalLetter++);
+        }
+
+        for (int i = 0; i < encryptedMessage.length(); i++) {
+            if (Character.isAlphabetic(encryptedMessage.charAt(i))) {
+                decoded.append(cipherMap.get(encryptedMessage.charAt(i)));
+            } else {
+                decoded.append(encryptedMessage.charAt(i));
+            }
+        }
+
+        return decoded.toString();
+    }
+}

+ 51 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/Vigenere.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers;
+
+/**
+ * A Java implementation of Vigenere Cipher.
+ *
+ * @author straiffix
+ * @author beingmartinbmc
+ */
+public class Vigenere {
+
+    public String encrypt(final String message, final String key) {
+        StringBuilder result = new StringBuilder();
+
+        int j = 0;
+        for (int i = 0; i < message.length(); i++) {
+            char c = message.charAt(i);
+            if (Character.isLetter(c)) {
+                if (Character.isUpperCase(c)) {
+                    result.append((char) ((c + key.toUpperCase().charAt(j) - 2 * 'A') % 26 + 'A'));
+                } else {
+                    result.append((char) ((c + key.toLowerCase().charAt(j) - 2 * 'a') % 26 + 'a'));
+                }
+            } else {
+                result.append(c);
+            }
+            j = ++j % key.length();
+        }
+        return result.toString();
+    }
+
+    public String decrypt(final String message, final String key) {
+        StringBuilder result = new StringBuilder();
+
+        int j = 0;
+        for (int i = 0; i < message.length(); i++) {
+            char c = message.charAt(i);
+            if (Character.isLetter(c)) {
+                if (Character.isUpperCase(c)) {
+                    result.append((char) ('Z' - (25 - (c - key.toUpperCase().charAt(j))) % 26));
+                } else {
+                    result.append((char) ('z' - (25 - (c - key.toLowerCase().charAt(j))) % 26));
+                }
+            } else {
+                result.append(c);
+            }
+
+            j = ++j % key.length();
+        }
+        return result.toString();
+    }
+}

+ 30 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/A5Cipher.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers.a5;
+
+import java.util.BitSet;
+
+// https://en.wikipedia.org/wiki/A5/1
+public class A5Cipher {
+
+    private final A5KeyStreamGenerator keyStreamGenerator;
+    private static final int KEY_STREAM_LENGTH = 228; // 28.5 bytes so we need to pad bytes or something
+
+    public A5Cipher(BitSet sessionKey, BitSet frameCounter) {
+        keyStreamGenerator = new A5KeyStreamGenerator();
+        keyStreamGenerator.initialize(sessionKey, frameCounter);
+    }
+
+    public BitSet encrypt(BitSet plainTextBits) {
+        // create a copy
+        var result = new BitSet(KEY_STREAM_LENGTH);
+        result.xor(plainTextBits);
+
+        var key = keyStreamGenerator.getNextKeyStream();
+        result.xor(key);
+
+        return result;
+    }
+
+    public void resetCounter() {
+        keyStreamGenerator.reInitialize();
+    }
+}

+ 56 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java

@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers.a5;
+
+import java.util.BitSet;
+
+// TODO: raise exceptions for improper use
+public class A5KeyStreamGenerator extends CompositeLFSR {
+
+    private BitSet initialFrameCounter;
+    private BitSet frameCounter;
+    private BitSet sessionKey;
+    private static final int INITIAL_CLOCKING_CYCLES = 100;
+    private static final int KEY_STREAM_LENGTH = 228; // 28.5 bytes so we need to pad bytes or something
+
+    @Override
+    public void initialize(BitSet sessionKey, BitSet frameCounter) {
+        this.sessionKey = sessionKey;
+        this.frameCounter = (BitSet) frameCounter.clone();
+        this.initialFrameCounter = (BitSet) frameCounter.clone();
+        registers.clear();
+        LFSR lfsr1 = new LFSR(19, 8, new int[] {13, 16, 17, 18});
+        LFSR lfsr2 = new LFSR(22, 10, new int[] {20, 21});
+        LFSR lfsr3 = new LFSR(23, 10, new int[] {7, 20, 21, 22});
+        registers.add(lfsr1);
+        registers.add(lfsr2);
+        registers.add(lfsr3);
+        registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter));
+    }
+
+    public void reInitialize() {
+        this.initialize(sessionKey, initialFrameCounter);
+    }
+
+    public BitSet getNextKeyStream() {
+        for (int cycle = 1; cycle <= INITIAL_CLOCKING_CYCLES; ++cycle) {
+            this.clock();
+        }
+
+        BitSet result = new BitSet(KEY_STREAM_LENGTH);
+        for (int cycle = 1; cycle <= KEY_STREAM_LENGTH; ++cycle) {
+            boolean outputBit = this.clock();
+            result.set(cycle - 1, outputBit);
+        }
+
+        reInitializeRegisters();
+        return result;
+    }
+
+    private void reInitializeRegisters() {
+        incrementFrameCounter();
+        registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter));
+    }
+
+    private void incrementFrameCounter() {
+        Utils.increment(frameCounter, FRAME_COUNTER_LENGTH);
+    }
+}

+ 10 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/BaseLFSR.java

@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers.a5;
+
+import java.util.BitSet;
+
+public interface BaseLFSR {
+    void initialize(BitSet sessionKey, BitSet frameCounter);
+    boolean clock();
+    int SESSION_KEY_LENGTH = 64;
+    int FRAME_COUNTER_LENGTH = 22;
+}

+ 37 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/CompositeLFSR.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers.a5;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public abstract class CompositeLFSR implements BaseLFSR {
+
+    protected final List<LFSR> registers = new ArrayList<>();
+
+    /**
+     * Implements irregular clocking using the clock bit for each register
+     * @return the registers discarded bit xored value
+     */
+    @Override
+    public boolean clock() {
+        boolean majorityBit = getMajorityBit();
+        boolean result = false;
+        for (var register : registers) {
+            result ^= register.getLastBit();
+            if (register.getClockBit() == majorityBit) {
+                register.clock();
+            }
+        }
+        return result;
+    }
+
+    private boolean getMajorityBit() {
+        Map<Boolean, Integer> bitCount = new TreeMap<>();
+        bitCount.put(Boolean.FALSE, 0);
+        bitCount.put(Boolean.TRUE, 0);
+
+        registers.forEach(lfsr -> bitCount.put(lfsr.getClockBit(), bitCount.get(lfsr.getClockBit()) + 1));
+        return bitCount.get(Boolean.FALSE) <= bitCount.get(Boolean.TRUE);
+    }
+}

+ 79 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/LFSR.java

@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers.a5;
+
+import java.util.BitSet;
+
+public class LFSR implements BaseLFSR {
+
+    private final BitSet register;
+    private final int length;
+    private final int clockBitIndex;
+    private final int[] tappingBitsIndices;
+
+    public LFSR(int length, int clockBitIndex, int[] tappingBitsIndices) {
+        this.length = length;
+        this.clockBitIndex = clockBitIndex;
+        this.tappingBitsIndices = tappingBitsIndices;
+        register = new BitSet(length);
+    }
+
+    @Override
+    public void initialize(BitSet sessionKey, BitSet frameCounter) {
+        register.clear();
+        clock(sessionKey, SESSION_KEY_LENGTH);
+        clock(frameCounter, FRAME_COUNTER_LENGTH);
+    }
+
+    private void clock(BitSet key, int keyLength) {
+        // We start from reverse because LFSR 0 index is the left most bit
+        // while key 0 index is right most bit, so we reverse it
+        for (int i = keyLength - 1; i >= 0; --i) {
+            var newBit = key.get(i) ^ xorTappingBits();
+            pushBit(newBit);
+        }
+    }
+
+    @Override
+    public boolean clock() {
+        return pushBit(xorTappingBits());
+    }
+
+    public boolean getClockBit() {
+        return register.get(clockBitIndex);
+    }
+
+    public boolean get(int bitIndex) {
+        return register.get(bitIndex);
+    }
+
+    public boolean getLastBit() {
+        return register.get(length - 1);
+    }
+
+    private boolean xorTappingBits() {
+        boolean result = false;
+        for (int i : tappingBitsIndices) {
+            result ^= register.get(i);
+        }
+        return result;
+    }
+
+    private boolean pushBit(boolean bit) {
+        boolean discardedBit = rightShift();
+        register.set(0, bit);
+        return discardedBit;
+    }
+
+    private boolean rightShift() {
+        boolean discardedBit = get(length - 1);
+        for (int i = length - 1; i > 0; --i) {
+            register.set(i, get(i - 1));
+        }
+        register.set(0, false);
+        return discardedBit;
+    }
+
+    @Override
+    public String toString() {
+        return register.toString();
+    }
+}

+ 25 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/ciphers/a5/Utils.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.ciphers.a5;
+
+// Source
+// http://www.java2s.com/example/java-utility-method/bitset/increment-bitset-bits-int-size-9fd84.html
+// package com.java2s;
+// License from project: Open Source License
+
+import java.util.BitSet;
+
+public final class Utils {
+    private Utils() {
+    }
+
+    public static boolean increment(BitSet bits, int size) {
+        int i = size - 1;
+        while (i >= 0 && bits.get(i)) {
+            bits.set(i--, false); /*from w w w  . j a  v a  2s  .c o  m*/
+        }
+        if (i < 0) {
+            return false;
+        }
+        bits.set(i, true);
+        return true;
+    }
+}

+ 355 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/AnyBaseToAnyBase.java

@@ -0,0 +1,355 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.InputMismatchException;
+import java.util.Scanner;
+
+///**
+// * Class for converting from "any" base to "any" other base, when "any" means
+// * from 2-36. Works by going from base 1 to decimal to base 2. Includes
+// * auxiliary method for determining whether a number is valid for a given base.
+// *
+// * @author Michael Rolland
+// * @version 2017.10.10
+// */
+//public final class AnyBaseToAnyBase {
+//    private AnyBaseToAnyBase() {
+//    }
+//
+//    /**
+//     * Smallest and largest base you want to accept as valid input
+//     */
+//    static final int MINIMUM_BASE = 2;
+//
+//    static final int MAXIMUM_BASE = 36;
+//
+//    public static void main(String[] args) {
+//        Scanner in = new Scanner(System.in);
+//        String n;
+//        int b1;
+//        int b2;
+//        while (true) {
+//            try {
+//                System.out.print("Enter number: ");
+//                n = in.next();
+//                System.out.print("Enter beginning base (between " + MINIMUM_BASE + " and " + MAXIMUM_BASE + "): ");
+//                b1 = in.nextInt();
+//                if (b1 > MAXIMUM_BASE || b1 < MINIMUM_BASE) {
+//                    System.out.println("Invalid base!");
+//                    continue;
+//                }
+//                if (!validForBase(n, b1)) {
+//                    System.out.println("The number is invalid for this base!");
+//                    continue;
+//                }
+//                System.out.print("Enter end base (between " + MINIMUM_BASE + " and " + MAXIMUM_BASE + "): ");
+//                b2 = in.nextInt();
+//                if (b2 > MAXIMUM_BASE || b2 < MINIMUM_BASE) {
+//                    System.out.println("Invalid base!");
+//                    continue;
+//                }
+//                break;
+//            } catch (InputMismatchException e) {
+//                System.out.println("Invalid input.");
+//                in.next();
+//            }
+//        }
+//        System.out.println(base2base(n, b1, b2));
+//        in.close();
+//    }
+//
+//    /**
+//     * Checks if a number (as a String) is valid for a given base.
+//     */
+//    public static boolean validForBase(String n, int base) {
+//        char[] validDigits = {
+//            '0',
+//            '1',
+//            '2',
+//            '3',
+//            '4',
+//            '5',
+//            '6',
+//            '7',
+//            '8',
+//            '9',
+//            'A',
+//            'B',
+//            'C',
+//            'D',
+//            'E',
+//            'F',
+//            'G',
+//            'H',
+//            'I',
+//            'J',
+//            'K',
+//            'L',
+//            'M',
+//            'N',
+//            'O',
+//            'P',
+//            'Q',
+//            'R',
+//            'S',
+//            'T',
+//            'U',
+//            'V',
+//            'W',
+//            'X',
+//            'Y',
+//            'Z',
+//        };
+//        // digitsForBase contains all the valid digits for the base given
+//        char[] digitsForBase = Arrays.copyOfRange(validDigits, 0, base);
+//
+//        // Convert character array into set for convenience of contains() method
+//        HashSet<Character> digitsList = new HashSet<>();
+//        for (int i = 0; i < digitsForBase.length; i++) {
+//            digitsList.add(digitsForBase[i]);
+//        }
+//
+//        // Check that every digit in n is within the list of valid digits for that base.
+//        for (char c : n.toCharArray()) {
+//            if (!digitsList.contains(c)) {
+//                return false;
+//            }
+//        }
+//
+//        return true;
+//    }
+//
+//    /**
+//     * Method to convert any integer from base b1 to base b2. Works by
+//     * converting from b1 to decimal, then decimal to b2.
+//     *
+//     * @param n The integer to be converted.
+//     * @param b1 Beginning base.
+//     * @param b2 End base.
+//     * @return n in base b2.
+//     */
+//    public static String base2base(String n, int b1, int b2) {
+//        // Declare variables: decimal value of n,
+//        // character of base b1, character of base b2,
+//        // and the string that will be returned.
+//        int decimalValue = 0;
+//        int charB2;
+//        char charB1;
+//        String output = "";
+//        // Go through every character of n
+//        for (int i = 0; i < n.length(); i++) {
+//            // store the character in charB1
+//            charB1 = n.charAt(i);
+//            // if it is a non-number, convert it to a decimal value >9 and store it in charB2
+//            if (charB1 >= 'A' && charB1 <= 'Z') {
+//                charB2 = 10 + (charB1 - 'A');
+//            } // Else, store the integer value in charB2
+//            else {
+//                charB2 = charB1 - '0';
+//            }
+//            // Convert the digit to decimal and add it to the
+//            // decimalValue of n
+//            decimalValue = decimalValue * b1 + charB2;
+//        }
+//
+//        // Converting the decimal value to base b2:
+//        // A number is converted from decimal to another base
+//        // by continuously dividing by the base and recording
+//        // the remainder until the quotient is zero. The number in the
+//        // new base is the remainders, with the last remainder
+//        // being the left-most digit.
+//        if (0 == decimalValue) {
+//            return "0";
+//        }
+//        // While the quotient is NOT zero:
+//        while (decimalValue != 0) {
+//            // If the remainder is a digit < 10, simply add it to
+//            // the left side of the new number.
+//            if (decimalValue % b2 < 10) {
+//                output = decimalValue % b2 + output;
+//            } // If the remainder is >= 10, add a character with the
+//            // corresponding value to the new number. (A = 10, B = 11, C = 12, ...)
+//            else {
+//                output = (char) ((decimalValue % b2) + 55) + output;
+//            }
+//            // Divide by the new base again
+//            decimalValue /= b2;
+//        }
+//        return output;
+//    }
+//}
+
+/**
+ * 类用于将“任何”基数转换为“任何”其他基数,其中“任何”意味着从 2 到 36。
+ * 通过从基数 1 转换为十进制再转换为基数 2 来工作。包括用于确定给定基数的数字是否有效的辅助方法。
+ *
+ * @作者 Michael Rolland
+ * @版本 2017.10.10
+ */
+public final class AnyBaseToAnyBase {
+    private AnyBaseToAnyBase() {
+    }
+
+    /**
+     * 您希望接受为有效输入的最小和最大基数
+     */
+    static final int MINIMUM_BASE = 2;
+    static final int MAXIMUM_BASE = 36;
+
+    public static void main(String[] args) {
+        Scanner in = new Scanner(System.in);
+        String n;
+        int b1;
+        int b2;
+        while (true) {
+            try {
+                System.out.print("输入数字:");
+                n = in.next();
+                System.out.print("输入起始基数(在 " + MINIMUM_BASE + " 和 " + MAXIMUM_BASE + " 之间):");
+                b1 = in.nextInt();
+                if (b1 > MAXIMUM_BASE || b1 < MINIMUM_BASE) {
+                    System.out.println("无效的基数!");
+                    continue;
+                }
+                if (!validForBase(n, b1)) {
+                    System.out.println("该数字对此基数无效!");
+                    continue;
+                }
+                System.out.print("输入结束基数(在 " + MINIMUM_BASE + " 和 " + MAXIMUM_BASE + " 之间):");
+                b2 = in.nextInt();
+                if (b2 > MAXIMUM_BASE || b2 < MINIMUM_BASE) {
+                    System.out.println("无效的基数!");
+                    continue;
+                }
+                break;
+            } catch (InputMismatchException e) {
+                System.out.println("无效输入。");
+                in.next();
+            }
+        }
+        System.out.println(base2base(n, b1, b2));
+        in.close();
+    }
+
+
+
+    /**
+     * 检查一个数字(作为字符串)是否适用于给定的基数。
+     */
+    public static boolean validForBase(String n, int base) {
+        char[] validDigits = {
+                '0',
+                '1',
+                '2',
+                '3',
+                '4',
+                '5',
+                '6',
+                '7',
+                '8',
+                '9',
+                'A',
+                'B',
+                'C',
+                'D',
+                'E',
+                'F',
+                'G',
+                'H',
+                'I',
+                'J',
+                'K',
+                'L',
+                'M',
+                'N',
+                'O',
+                'P',
+                'Q',
+                'R',
+                'S',
+                'T',
+                'U',
+                'V',
+                'W',
+                'X',
+                'Y',
+                'Z',
+        };
+        // digitsForBase 包含给定基数的所有有效数字
+        char[] digitsForBase = Arrays.copyOfRange(validDigits, 0, base);
+
+        // 将字符数组转换为集合,以方便使用 contains() 方法
+        HashSet<Character> digitsList = new HashSet<>();
+        for (char c : digitsForBase) {
+            digitsList.add(c);
+        }
+
+        // 检查 n 中的每个数字是否都在该基数的有效数字列表中
+        for (char c : n.toCharArray()) {
+            if (!digitsList.contains(c)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * 将任何整数从基数 b1 转换为基数 b2 的方法。通过将 b1 转换为十进制,然后将十进制转换为 b2 来工作。
+     *
+     * @param n 要转换的整数。
+     * @param b1 起始基数。
+     * @param b2 结束基数。
+     * @return n 的 b2 基数。
+     */
+    public static String base2base(String n, int b1, int b2) {
+        // 声明变量:n 的十进制值,
+        // b1 基数的字符,b2 基数的字符,
+        // 以及将要返回的字符串。
+        int decimalValue = 0;
+        int charB2;
+        char charB1;
+        String output = "";
+        // 遍历 n 的每个字符
+        for (int i = 0; i < n.length(); i++) {
+            // 将字符存储在 charB1 中
+            charB1 = n.charAt(i);
+            // 如果它是一个非数字字符,将其转换为大于 9 的十进制值并存储在 charB2 中
+            if (charB1 >= 'A' && charB1 <= 'Z') {
+                charB2 = 10 + (charB1 - 'A');
+            } // 否则,将整数值存储在 charB2 中
+            else {
+                charB2 = charB1 - '0';
+            }
+            // 将数字转换为十进制并添加到 n 的十进制值中
+            decimalValue = decimalValue * b1 + charB2;
+        }
+
+        // 将十进制值转换为 b2 基数:
+        // 一个数字从十进制转换为另一个基数
+        // 通过不断除以基数并记录
+        // 余数,直到商为零。新基数中的数字是余数,
+        // 最后一个余数是最左边的数字。
+        if (0 == decimalValue) {
+            return "0";
+        }
+        // 当商不为零时:
+        while (decimalValue != 0) {
+            // 如果余数是小于 10 的数字,简单地将其添加到
+            // 新数字的左侧。
+            if (decimalValue % b2 < 10) {
+                output = decimalValue % b2 + output;
+            } // 如果余数大于等于 10,添加一个字符与
+            // 新数字的对应值。(A = 10, B = 11, C = 12, ...)
+            else {
+                output = (char) ((decimalValue % b2) + 55) + output;
+            }
+            // 再次除以新基数
+            decimalValue /= b2;
+        }
+        return output;
+    }
+
+}
+

+ 126 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/AnyBaseToDecimal.java

@@ -0,0 +1,126 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+///**
+// * @author Varun Upadhyay (<a href="https://github.com/varunu28">...</a>)
+// */
+//// Driver program
+//public final class AnyBaseToDecimal {
+//    private AnyBaseToDecimal() {
+//    }
+//
+//    public static void main(String[] args) {
+//        assert convertToDecimal("1010", 2) == Integer.valueOf("1010", 2);
+//        assert convertToDecimal("777", 8) == Integer.valueOf("777", 8);
+//        assert convertToDecimal("999", 10) == Integer.valueOf("999", 10);
+//        assert convertToDecimal("ABCDEF", 16) == Integer.valueOf("ABCDEF", 16);
+//        assert convertToDecimal("XYZ", 36) == Integer.valueOf("XYZ", 36);
+//    }
+//
+//    /**
+//     * Convert any radix to decimal number
+//     *
+//     * @param s the string to be convert
+//     * @param radix the radix
+//     * @return decimal of bits
+//     * @throws NumberFormatException if {@code bits} or {@code radix} is invalid
+//     */
+//    public static int convertToDecimal(String s, int radix) {
+//        int num = 0;
+//        int pow = 1;
+//
+//        for (int i = s.length() - 1; i >= 0; i--) {
+//            int digit = valOfChar(s.charAt(i));
+//            if (digit >= radix) {
+//                throw new NumberFormatException("For input string " + s);
+//            }
+//            num += valOfChar(s.charAt(i)) * pow;
+//            pow *= radix;
+//        }
+//        return num;
+//    }
+//
+//    /**
+//     * Convert character to integer
+//     *
+//     * @param c the character
+//     * @return represented digit of given character
+//     * @throws NumberFormatException if {@code ch} is not UpperCase or Digit
+//     * character.
+//     */
+//    public static int valOfChar(char c) {
+//        if (!(Character.isUpperCase(c) || Character.isDigit(c))) {
+//            throw new NumberFormatException("invalid character :" + c);
+//        }
+//        return Character.isDigit(c) ? c - '0' : c - 'A' + 10;
+//    }
+//}
+/**
+ * 作者 Varun Upadhyay (https://github.com/varunu28)
+ */
+// 驱动程序
+public final class AnyBaseToDecimal {
+    private AnyBaseToDecimal() {
+    }
+
+    public static void main(String[] args) {
+        // 使用断言测试 convertToDecimal
+        System.out.println(convertToDecimal("1010", 2));
+        System.out.println(convertToDecimal("777", 8));
+        System.out.println(convertToDecimal("999", 10));
+        System.out.println(convertToDecimal("ABCDEF", 16));
+        System.out.println(convertToDecimal("XYZ", 36));
+
+        System.out.println("********************************");
+
+        System.out.println(Integer.valueOf("1010", 2));
+        System.out.println(Integer.valueOf("777", 8));
+        System.out.println(Integer.valueOf("999", 10));
+        System.out.println(Integer.valueOf("ABCDEF", 16));
+        System.out.println(Integer.valueOf("XYZ", 36));
+//
+    }
+
+    /**
+     * 将任何基数转换为十进制数
+     *
+     * @param s 要转换的字符串
+     * @param radix 基数
+     * @return 位的十进制数
+     * @throws NumberFormatException 如果 {@code bits} 或 {@code radix} 无效
+     */
+    public static int convertToDecimal(String s, int radix) {
+        int num = 0;
+        int pow = 1;
+
+        // 从字符串的最后一个字符开始,向前遍历每个字符
+        for (int i = s.length() - 1; i >= 0; i--) {
+            // 将字符转换为整数值
+            int digit = valOfChar(s.charAt(i));
+            // 如果字符代表的数字大于或等于基数,则抛出异常
+            if (digit >= radix) {
+                throw new NumberFormatException("输入字符串无效 " + s);
+            }
+            // 将字符代表的数字乘以当前的权重并加到 num 上
+            num += valOfChar(s.charAt(i)) * pow;
+            // 更新权重
+            pow *= radix;
+        }
+        return num;
+    }
+
+    /**
+     * 将字符转换为整数
+     *
+     * @param c 字符
+     * @return 给定字符的代表数字
+     * @throws NumberFormatException 如果 {@code ch} 不是大写字母或数字字符
+     */
+    public static int valOfChar(char c) {
+        // 如果字符不是大写字母或数字,则抛出异常
+        if (!(Character.isUpperCase(c) || Character.isDigit(c))) {
+            throw new NumberFormatException("无效字符:" + c);
+        }
+        // 如果字符是数字,则直接转换为数字;如果是大写字母,则转换为对应的数字(A=10, B=11, ...)
+        return Character.isDigit(c) ? c - '0' : c - 'A' + 10;
+    }
+}

+ 35 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/AnytoAny.java

@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+// given a source number , source base, destination base, this code can give you the destination
+// number.
+// sn ,sb,db ---> ()dn  .   this is what we have to do    .
+
+public final class AnytoAny {
+    private AnytoAny() {
+    }
+
+    public static void main(String[] args) {
+        Scanner scn = new Scanner(System.in);
+        int sn = scn.nextInt();
+        int sb = scn.nextInt();
+        int db = scn.nextInt();
+        int m = 1;
+        int dec = 0;
+        int dn = 0;
+        while (sn != 0) {
+            dec = dec + (sn % 10) * m;
+            m *= sb;
+            sn /= 10;
+        }
+        m = 1;
+        while (dec != 0) {
+            dn = dn + (dec % db) * m;
+            m *= 10;
+            dec /= db;
+        }
+        System.out.println(dn);
+        scn.close();
+    }
+}

+ 37 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/BinaryToDecimal.java

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+/**
+ * This class converts a Binary number to a Decimal number
+ */
+final class BinaryToDecimal {
+    private BinaryToDecimal() {
+    }
+
+    public static long binaryToDecimal(long binNum) {
+        long binCopy;
+        long d;
+        long s = 0;
+        long power = 0;
+        binCopy = binNum;
+        while (binCopy != 0) {
+            d = binCopy % 10;
+            s += d * (long) Math.pow(2, power++);
+            binCopy /= 10;
+        }
+        return s;
+    }
+
+    /**
+     * Main Method
+     *
+     * @param args Command line arguments
+     */
+    public static void main(String[] args) {
+        Scanner sc = new Scanner(System.in);
+        System.out.print("Binary number: ");
+        System.out.println("Decimal equivalent:" + binaryToDecimal(sc.nextLong()));
+        sc.close();
+    }
+}

+ 60 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/BinaryToHexadecimal.java

@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.HashMap;
+import java.util.Scanner;
+
+/**
+ * 将任何二进制数转换为十六进制数
+ *
+ * @author 西田·阿加瓦尔
+ */
+public final class BinaryToHexadecimal {
+    private BinaryToHexadecimal() {
+    }
+
+   /**
+     * 此方法将二进制数转换为十六进制数。
+     *
+     * @param binary 二进制数
+     * @return 十六进制数
+     */
+    static String binToHex(int binary) {
+        // hm to store hexadecimal codes for binary numbers within the range: 0000 to 1111 i.e. for
+        // decimal numbers 0 to 15
+        HashMap<Integer, String> hm = new HashMap<>();
+        // String to store hexadecimal code
+        String hex = "";
+        int i;
+        for (i = 0; i < 10; i++) {
+            hm.put(i, String.valueOf(i));
+        }
+        for (i = 10; i < 16; i++) {
+            hm.put(i, String.valueOf((char) ('A' + i - 10)));
+        }
+        int currbit;
+        while (binary != 0) {
+            int code4 = 0; // to store decimal equivalent of number formed by 4 decimal digits
+            for (i = 0; i < 4; i++) {
+                currbit = binary % 10;
+                binary = binary / 10;
+                code4 += currbit * (int) Math.pow(2, i);
+            }
+            hex = hm.get(code4) + hex;
+        }
+        return hex;
+    }
+
+    /**
+     * Main method
+     *
+     * @param args Command line arguments
+     */
+    public static void main(String[] args) {
+        Scanner sc = new Scanner(System.in);
+        System.out.println("Enter binary number:");
+        int binary = sc.nextInt();
+        String hex = binToHex(binary);
+        System.out.println("Hexadecimal Code:" + hex);
+        sc.close();
+    }
+}

+ 50 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/BinaryToOctal.java

@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+/**
+ * Converts any Binary number to an Octal Number
+ *
+ * @author Zachary Jones
+ */
+public final class BinaryToOctal {
+    private BinaryToOctal() {
+    }
+
+    /**
+     * Main method
+     *
+     * @param args Command line arguments
+     */
+    public static void main(String[] args) {
+        Scanner sc = new Scanner(System.in);
+        System.out.println("Input the binary number: ");
+        int b = sc.nextInt();
+        System.out.println("Octal equivalent: " + convertBinaryToOctal(b));
+        sc.close();
+    }
+
+    /**
+     * This method converts a binary number to an octal number.
+     *
+     * @param binary The binary number
+     * @return The octal number
+     */
+    public static String convertBinaryToOctal(int binary) {
+        String octal = "";
+        int currBit = 0;
+        int j = 1;
+        while (binary != 0) {
+            int code3 = 0;
+            for (int i = 0; i < 3; i++) {
+                currBit = binary % 10;
+                binary = binary / 10;
+                code3 += currBit * j;
+                j *= 2;
+            }
+            octal = code3 + octal;
+            j = 1;
+        }
+        return octal;
+    }
+}

+ 69 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/DecimalToAnyBase.java

@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+/**
+ * @author Varun Upadhyay (<a href="https://github.com/varunu28">...</a>)
+ */
+// Driver Program
+public final class DecimalToAnyBase {
+    private DecimalToAnyBase() {
+    }
+
+    public static void main(String[] args) throws Exception {
+        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+        System.out.println("Enter the decimal input below: ");
+        int decInput = Integer.parseInt(br.readLine());
+        System.out.println();
+
+        System.out.println("Enter the base below: ");
+        int base = Integer.parseInt(br.readLine());
+        System.out.println();
+
+        System.out.println("Decimal Input"
+            + " is: " + decInput);
+        System.out.println("Value of " + decInput + " in base " + base + " is: " + convertToAnyBase(decInput, base));
+
+        br.close();
+    }
+
+    /**
+     * This method produces a String value of any given input decimal in any
+     * base
+     *
+     * @param inp Decimal of which we need the value in base in String format
+     * @return string format of the converted value in the given base
+     */
+    public static String convertToAnyBase(int inp, int base) {
+        ArrayList<Character> charArr = new ArrayList<>();
+
+        while (inp > 0) {
+            charArr.add(reVal(inp % base));
+            inp /= base;
+        }
+
+        StringBuilder str = new StringBuilder(charArr.size());
+
+        for (Character ch : charArr) {
+            str.append(ch);
+        }
+
+        return str.reverse().toString();
+    }
+
+    /**
+     * This method produces character value of the input integer and returns it
+     *
+     * @param num integer of which we need the character value of
+     * @return character value of input integer
+     */
+    public static char reVal(int num) {
+        if (num >= 0 && num <= 9) {
+            return (char) (num + '0');
+        } else {
+            return (char) (num - 10 + 'A');
+        }
+    }
+}

+ 63 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/DecimalToBinary.java

@@ -0,0 +1,63 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+/**
+ * This class converts a Decimal number to a Binary number
+ */
+final class DecimalToBinary {
+    private DecimalToBinary() {
+    }
+
+    /**
+     * Main Method
+     *
+     * @param args Command Line Arguments
+     */
+    public static void main(String[] args) {
+        conventionalConversion();
+        bitwiseConversion();
+    }
+
+    /**
+     * This method converts a decimal number to a binary number using a
+     * conventional algorithm.
+     */
+    public static void conventionalConversion() {
+        int n;
+        int b = 0;
+        int c = 0;
+        int d;
+        Scanner input = new Scanner(System.in);
+        System.out.printf("Conventional conversion.%n Enter the decimal number: ");
+        n = input.nextInt();
+        while (n != 0) {
+            d = n % 2;
+            b = b + d * (int) Math.pow(10, c++);
+            n /= 2;
+        } // converting decimal to binary
+        System.out.println("\tBinary number: " + b);
+        input.close();
+    }
+
+    /**
+     * This method converts a decimal number to a binary number using a bitwise
+     * algorithm
+     */
+    public static void bitwiseConversion() {
+        int n;
+        int b = 0;
+        int c = 0;
+        int d;
+        Scanner input = new Scanner(System.in);
+        System.out.printf("Bitwise conversion.%n Enter the decimal number: ");
+        n = input.nextInt();
+        while (n != 0) {
+            d = (n & 1);
+            b += d * (int) Math.pow(10, c++);
+            n >>= 1;
+        }
+        System.out.println("\tBinary number: " + b);
+        input.close();
+    }
+}

+ 51 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/DecimalToHexaDecimal.java

@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+// hex = [0 - 9] -> [A - F]
+final class DecimalToHexaDecimal {
+    private DecimalToHexaDecimal() {
+    }
+
+    private static final int SIZE_OF_INT_IN_HALF_BYTES = 8;
+    private static final int NUMBER_OF_BITS_IN_HALF_BYTE = 4;
+    private static final int HALF_BYTE = 0x0F;
+    private static final char[] HEX_DIGITS = {
+        '0',
+        '1',
+        '2',
+        '3',
+        '4',
+        '5',
+        '6',
+        '7',
+        '8',
+        '9',
+        'A',
+        'B',
+        'C',
+        'D',
+        'E',
+        'F',
+    };
+
+    // Returns the hex value of the dec entered in the parameter.
+    public static String decToHex(int dec) {
+        StringBuilder hexBuilder = new StringBuilder(SIZE_OF_INT_IN_HALF_BYTES);
+        hexBuilder.setLength(SIZE_OF_INT_IN_HALF_BYTES);
+        for (int i = SIZE_OF_INT_IN_HALF_BYTES - 1; i >= 0; --i) {
+            int j = dec & HALF_BYTE;
+            hexBuilder.setCharAt(i, HEX_DIGITS[j]);
+            dec >>= NUMBER_OF_BITS_IN_HALF_BYTE;
+        }
+        return hexBuilder.toString().toLowerCase();
+    }
+
+    // Test above function.
+    public static void main(String[] args) {
+        System.out.println("Test...");
+        int dec = 305445566;
+        String libraryDecToHex = Integer.toHexString(dec);
+        String decToHex = decToHex(dec);
+        System.out.println("Result from the library : " + libraryDecToHex);
+        System.out.println("Result decToHex method : " + decToHex);
+    }
+}

+ 38 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/DecimalToOctal.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+/**
+ * This class converts Decimal numbers to Octal Numbers
+ */
+public final class DecimalToOctal {
+    private DecimalToOctal() {
+    }
+
+    /**
+     * Main Method
+     *
+     * @param args Command line Arguments
+     */
+
+    // enter in a decimal value to get Octal output
+    public static void main(String[] args) {
+        Scanner sc = new Scanner(System.in);
+        int n;
+        int k;
+        int d;
+        int s = 0;
+        int c = 0;
+        System.out.print("Decimal number: ");
+        n = sc.nextInt();
+        k = n;
+        while (k != 0) {
+            d = k % 8;
+            s += d * (int) Math.pow(10, c++);
+            k /= 8;
+        }
+
+        System.out.println("Octal equivalent:" + s);
+        sc.close();
+    }
+}

+ 75 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/HexToOct.java

@@ -0,0 +1,75 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+/**
+ * Converts any Hexadecimal Number to Octal
+ *
+ * @author Tanmay Joshi
+ */
+public final class HexToOct {
+    private HexToOct() {
+    }
+
+    /**
+     * This method converts a Hexadecimal number to a decimal number
+     *
+     * @param s The Hexadecimal Number
+     * @return The Decimal number
+     */
+    public static int hex2decimal(String s) {
+        String str = "0123456789ABCDEF";
+        s = s.toUpperCase();
+        int val = 0;
+        for (int i = 0; i < s.length(); i++) {
+            char a = s.charAt(i);
+            int n = str.indexOf(a);
+            val = 16 * val + n;
+        }
+        return val;
+    }
+
+    /**
+     * This method converts a Decimal number to a octal number
+     *
+     * @param q The Decimal Number
+     * @return The Octal number
+     */
+    public static int decimal2octal(int q) {
+        int now;
+        int i = 1;
+        int octnum = 0;
+        while (q > 0) {
+            now = q % 8;
+            octnum = (now * (int) (Math.pow(10, i))) + octnum;
+            q /= 8;
+            i++;
+        }
+        octnum /= 10;
+        return octnum;
+    }
+
+    /**
+     * Main method that gets the hex input from user and converts it into octal.
+     *
+     * @param args arguments
+     */
+    public static void main(String[] args) {
+        String hexadecnum;
+        int decnum;
+        int octalnum;
+        Scanner scan = new Scanner(System.in);
+
+        System.out.print("Enter Hexadecimal Number : ");
+        hexadecnum = scan.nextLine();
+
+        // first convert hexadecimal to decimal
+        decnum = hex2decimal(hexadecnum); // Pass the string to the hex2decimal function and get the decimal form in
+        // variable decnum
+
+        // convert decimal to octal
+        octalnum = decimal2octal(decnum);
+        System.out.println("Number in octal: " + octalnum);
+        scan.close();
+    }
+}

+ 43 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/HexaDecimalToBinary.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+// Hex [0-9],[A-F] -> Binary [0,1]
+public class HexaDecimalToBinary {
+    public String convert(String numHex) {
+        // String a HexaDecimal:
+        int conHex = Integer.parseInt(numHex, 16);
+        // Hex a Binary:
+        String binary = Integer.toBinaryString(conHex);
+        // Output:
+        return completeDigits(binary);
+    }
+
+    public String completeDigits(String binNum) {
+        final int longBits = 8;
+        for (int i = binNum.length(); i < longBits; i++) {
+            binNum = "0" + binNum;
+        }
+        return binNum;
+    }
+
+    public static void main(String[] args) {
+        // Testing Numbers:
+        String[] hexNums = {
+            "1",
+            "A1",
+            "ef",
+            "BA",
+            "AA",
+            "BB",
+            "19",
+            "01",
+            "02",
+            "03",
+            "04",
+        };
+        HexaDecimalToBinary objConvert = new HexaDecimalToBinary();
+
+        for (String num : hexNums) {
+            System.out.println(num + " = " + objConvert.convert(num));
+        }
+    }
+}

+ 39 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/HexaDecimalToDecimal.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+public final class HexaDecimalToDecimal {
+    private HexaDecimalToDecimal() {
+    }
+
+    // convert hexadecimal to decimal
+    public static int getHexaToDec(String hex) {
+        String digits = "0123456789ABCDEF";
+        hex = hex.toUpperCase();
+        int val = 0;
+        for (int i = 0; i < hex.length(); i++) {
+            int d = digits.indexOf(hex.charAt(i));
+            val = 16 * val + d;
+        }
+        return val;
+    }
+
+    // Main method gets the hexadecimal input from user and converts it into Decimal output.
+    public static void main(String[] args) {
+        String hexaInput;
+        int decOutput;
+        Scanner scan = new Scanner(System.in);
+
+        System.out.print("Enter Hexadecimal Number : ");
+        hexaInput = scan.nextLine();
+
+        // convert hexadecimal to decimal
+        decOutput = getHexaToDec(hexaInput);
+        /*
+    Pass the string to the getHexaToDec function
+    and it returns the decimal form in the variable decOutput.
+         */
+        System.out.println("Number in Decimal: " + decOutput);
+        scan.close();
+    }
+}

+ 68 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/IntegerToRoman.java

@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+/**
+ * Converting Integers into Roman Numerals
+ *
+ * <p>
+ * ('I', 1); ('IV',4); ('V', 5); ('IX',9); ('X', 10); ('XL',40); ('L', 50);
+ * ('XC',90); ('C', 100); ('D', 500); ('M', 1000);
+ */
+public final class IntegerToRoman {
+    private IntegerToRoman() {
+    }
+
+    private static final int[] ALL_ROMAN_NUMBERS_IN_ARABIC = new int[] {
+        1000,
+        900,
+        500,
+        400,
+        100,
+        90,
+        50,
+        40,
+        10,
+        9,
+        5,
+        4,
+        1,
+    };
+    private static final String[] ALL_ROMAN_NUMBERS = new String[] {
+        "M",
+        "CM",
+        "D",
+        "CD",
+        "C",
+        "XC",
+        "L",
+        "XL",
+        "X",
+        "IX",
+        "V",
+        "IV",
+        "I",
+    };
+
+    // Value must be > 0
+    public static String integerToRoman(int num) {
+        if (num <= 0) {
+            return "";
+        }
+
+        StringBuilder builder = new StringBuilder();
+
+        for (int a = 0; a < ALL_ROMAN_NUMBERS_IN_ARABIC.length; a++) {
+            int times = num / ALL_ROMAN_NUMBERS_IN_ARABIC[a];
+            for (int b = 0; b < times; b++) {
+                builder.append(ALL_ROMAN_NUMBERS[a]);
+            }
+
+            num -= times * ALL_ROMAN_NUMBERS_IN_ARABIC[a];
+        }
+
+        return builder.toString();
+    }
+
+    public static void main(String[] args) {
+        System.out.println(IntegerToRoman.integerToRoman(2131));
+    }
+}

+ 43 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/OctalToBinary.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+/**
+ * Converts any Octal Number to a Binary Number
+ *
+ * @author Bama Charan Chhandogi
+ */
+
+public final class OctalToBinary {
+    private OctalToBinary() {
+    }
+    public static long convertOctalToBinary(int octalNumber) {
+        long binaryNumber = 0;
+        int digitPosition = 1;
+
+        while (octalNumber != 0) {
+            int octalDigit = octalNumber % 10;
+            long binaryDigit = convertOctalDigitToBinary(octalDigit);
+
+            binaryNumber += binaryDigit * digitPosition;
+
+            octalNumber /= 10;
+            digitPosition *= 1000; // Move to the next group of 3 binary digits
+        }
+
+        return binaryNumber;
+    }
+
+    public static long convertOctalDigitToBinary(int octalDigit) {
+        long binaryDigit = 0;
+        int binaryMultiplier = 1;
+
+        while (octalDigit != 0) {
+            int octalDigitRemainder = octalDigit % 2;
+            binaryDigit += octalDigitRemainder * binaryMultiplier;
+
+            octalDigit /= 2;
+            binaryMultiplier *= 10;
+        }
+
+        return binaryDigit;
+    }
+}

+ 47 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/OctalToDecimal.java

@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+/**
+ * Converts any Octal Number to a Decimal Number
+ *
+ * @author Zachary Jones
+ */
+public final class OctalToDecimal {
+    private OctalToDecimal() {
+    }
+
+    /**
+     * Main method
+     *
+     * @param args Command line arguments
+     */
+    public static void main(String[] args) {
+        Scanner sc = new Scanner(System.in);
+        System.out.print("Octal Input: ");
+        String inputOctal = sc.nextLine();
+        int result = convertOctalToDecimal(inputOctal);
+        if (result != -1) {
+            System.out.println("Result convertOctalToDecimal : " + result);
+        }
+        sc.close();
+    }
+
+    /**
+     * This method converts an octal number to a decimal number.
+     *
+     * @param inputOctal The octal number
+     * @return The decimal number
+     */
+    public static int convertOctalToDecimal(String inputOctal) {
+        try {
+            // Actual conversion of Octal to Decimal:
+            return Integer.parseInt(inputOctal, 8);
+        } catch (NumberFormatException ne) {
+            // Printing a warning message if the input is not a valid octal
+            // number:
+            System.out.println("Invalid Input, Expecting octal number 0-7");
+            return -1;
+        }
+    }
+}

+ 65 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/OctalToHexadecimal.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+/**
+ * Converts any Octal Number to HexaDecimal
+ *
+ * @author Tanmay Joshi
+ */
+public final class OctalToHexadecimal {
+    private OctalToHexadecimal() {
+    }
+
+    /**
+     * This method converts a Octal number to a decimal number
+     *
+     * @param s The Octal Number
+     * @return The Decimal number
+     */
+    public static int octToDec(String s) {
+        int i = 0;
+        for (int j = 0; j < s.length(); j++) {
+            char num = s.charAt(j);
+            num -= '0';
+            i *= 8;
+            i += num;
+        }
+        return i;
+    }
+
+    /**
+     * This method converts a Decimal number to a Hexadecimal number
+     *
+     * @param d The Decimal Number
+     * @return The Hexadecimal number
+     */
+    public static String decimalToHex(int d) {
+        String digits = "0123456789ABCDEF";
+        if (d <= 0) {
+            return "0";
+        }
+        String hex = "";
+        while (d > 0) {
+            int digit = d % 16;
+            hex = digits.charAt(digit) + hex;
+            d = d / 16;
+        }
+        return hex;
+    }
+
+    public static void main(String[] args) {
+        Scanner input = new Scanner(System.in);
+        System.out.print("Enter the Octal number: ");
+        // Take octal number as input from user in a string
+        String oct = input.next();
+
+        // Pass the octal number to function and get converted decimal form
+        int decimal = octToDec(oct);
+
+        // Pass the decimal number to function and get converted Hex form of the number
+        String hex = decimalToHex(decimal);
+        System.out.println("The Hexadecimal equivalant is: " + hex);
+        input.close();
+    }
+}

+ 168 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/RgbHsvConversion.java

@@ -0,0 +1,168 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Arrays;
+
+/**
+ * The RGB color model is an additive color model in which red, green, and blue
+ * light are added together in various ways to reproduce a broad array of
+ * colors. The name of the model comes from the initials of the three additive
+ * primary colors, red, green, and blue. Meanwhile, the HSV representation
+ * models how colors appear under light. In it, colors are represented using
+ * three components: hue, saturation and (brightness-)value. This class provides
+ * methods for converting colors from one representation to the other.
+ * (description adapted from <a href="https://en.wikipedia.org/wiki/RGB_color_model">[1]</a> and
+ * <a href="https://en.wikipedia.org/wiki/HSL_and_HSV">[2]</a>).
+ */
+public final class RgbHsvConversion {
+    private RgbHsvConversion() {
+    }
+
+    public static void main(String[] args) {
+        // Expected RGB-values taken from https://www.rapidtables.com/convert/color/hsv-to-rgb.html
+
+        // Test hsvToRgb-method
+        assert Arrays.equals(hsvToRgb(0, 0, 0), new int[] {0, 0, 0});
+        assert Arrays.equals(hsvToRgb(0, 0, 1), new int[] {255, 255, 255});
+        assert Arrays.equals(hsvToRgb(0, 1, 1), new int[] {255, 0, 0});
+        assert Arrays.equals(hsvToRgb(60, 1, 1), new int[] {255, 255, 0});
+        assert Arrays.equals(hsvToRgb(120, 1, 1), new int[] {0, 255, 0});
+        assert Arrays.equals(hsvToRgb(240, 1, 1), new int[] {0, 0, 255});
+        assert Arrays.equals(hsvToRgb(300, 1, 1), new int[] {255, 0, 255});
+        assert Arrays.equals(hsvToRgb(180, 0.5, 0.5), new int[] {64, 128, 128});
+        assert Arrays.equals(hsvToRgb(234, 0.14, 0.88), new int[] {193, 196, 224});
+        assert Arrays.equals(hsvToRgb(330, 0.75, 0.5), new int[] {128, 32, 80});
+
+        // Test rgbToHsv-method
+        // approximate-assertions needed because of small deviations due to converting between
+        // int-values and double-values.
+        assert approximatelyEqualHsv(rgbToHsv(0, 0, 0), new double[] {0, 0, 0});
+        assert approximatelyEqualHsv(rgbToHsv(255, 255, 255), new double[] {0, 0, 1});
+        assert approximatelyEqualHsv(rgbToHsv(255, 0, 0), new double[] {0, 1, 1});
+        assert approximatelyEqualHsv(rgbToHsv(255, 255, 0), new double[] {60, 1, 1});
+        assert approximatelyEqualHsv(rgbToHsv(0, 255, 0), new double[] {120, 1, 1});
+        assert approximatelyEqualHsv(rgbToHsv(0, 0, 255), new double[] {240, 1, 1});
+        assert approximatelyEqualHsv(rgbToHsv(255, 0, 255), new double[] {300, 1, 1});
+        assert approximatelyEqualHsv(rgbToHsv(64, 128, 128), new double[] {180, 0.5, 0.5});
+        assert approximatelyEqualHsv(rgbToHsv(193, 196, 224), new double[] {234, 0.14, 0.88});
+        assert approximatelyEqualHsv(rgbToHsv(128, 32, 80), new double[] {330, 0.75, 0.5});
+    }
+
+    /**
+     * Conversion from the HSV-representation to the RGB-representation.
+     *
+     * @param hue Hue of the color.
+     * @param saturation Saturation of the color.
+     * @param value Brightness-value of the color.
+     * @return The tuple of RGB-components.
+     */
+    public static int[] hsvToRgb(double hue, double saturation, double value) {
+        if (hue < 0 || hue > 360) {
+            throw new IllegalArgumentException("hue should be between 0 and 360");
+        }
+
+        if (saturation < 0 || saturation > 1) {
+            throw new IllegalArgumentException("saturation should be between 0 and 1");
+        }
+
+        if (value < 0 || value > 1) {
+            throw new IllegalArgumentException("value should be between 0 and 1");
+        }
+
+        double chroma = value * saturation;
+        double hueSection = hue / 60;
+        double secondLargestComponent = chroma * (1 - Math.abs(hueSection % 2 - 1));
+        double matchValue = value - chroma;
+
+        return getRgbBySection(hueSection, chroma, matchValue, secondLargestComponent);
+    }
+
+    /**
+     * Conversion from the RGB-representation to the HSV-representation.
+     *
+     * @param red Red-component of the color.
+     * @param green Green-component of the color.
+     * @param blue Blue-component of the color.
+     * @return The tuple of HSV-components.
+     */
+    public static double[] rgbToHsv(int red, int green, int blue) {
+        if (red < 0 || red > 255) {
+            throw new IllegalArgumentException("red should be between 0 and 255");
+        }
+
+        if (green < 0 || green > 255) {
+            throw new IllegalArgumentException("green should be between 0 and 255");
+        }
+
+        if (blue < 0 || blue > 255) {
+            throw new IllegalArgumentException("blue should be between 0 and 255");
+        }
+
+        double dRed = (double) red / 255;
+        double dGreen = (double) green / 255;
+        double dBlue = (double) blue / 255;
+        double value = Math.max(Math.max(dRed, dGreen), dBlue);
+        double chroma = value - Math.min(Math.min(dRed, dGreen), dBlue);
+        double saturation = value == 0 ? 0 : chroma / value;
+        double hue;
+
+        if (chroma == 0) {
+            hue = 0;
+        } else if (value == dRed) {
+            hue = 60 * (0 + (dGreen - dBlue) / chroma);
+        } else if (value == dGreen) {
+            hue = 60 * (2 + (dBlue - dRed) / chroma);
+        } else {
+            hue = 60 * (4 + (dRed - dGreen) / chroma);
+        }
+
+        hue = (hue + 360) % 360;
+
+        return new double[] {hue, saturation, value};
+    }
+
+    private static boolean approximatelyEqualHsv(double[] hsv1, double[] hsv2) {
+        boolean bHue = Math.abs(hsv1[0] - hsv2[0]) < 0.2;
+        boolean bSaturation = Math.abs(hsv1[1] - hsv2[1]) < 0.002;
+        boolean bValue = Math.abs(hsv1[2] - hsv2[2]) < 0.002;
+
+        return bHue && bSaturation && bValue;
+    }
+
+    private static int[] getRgbBySection(double hueSection, double chroma, double matchValue, double secondLargestComponent) {
+        int red;
+        int green;
+        int blue;
+
+        if (hueSection >= 0 && hueSection <= 1) {
+            red = convertToInt(chroma + matchValue);
+            green = convertToInt(secondLargestComponent + matchValue);
+            blue = convertToInt(matchValue);
+        } else if (hueSection > 1 && hueSection <= 2) {
+            red = convertToInt(secondLargestComponent + matchValue);
+            green = convertToInt(chroma + matchValue);
+            blue = convertToInt(matchValue);
+        } else if (hueSection > 2 && hueSection <= 3) {
+            red = convertToInt(matchValue);
+            green = convertToInt(chroma + matchValue);
+            blue = convertToInt(secondLargestComponent + matchValue);
+        } else if (hueSection > 3 && hueSection <= 4) {
+            red = convertToInt(matchValue);
+            green = convertToInt(secondLargestComponent + matchValue);
+            blue = convertToInt(chroma + matchValue);
+        } else if (hueSection > 4 && hueSection <= 5) {
+            red = convertToInt(secondLargestComponent + matchValue);
+            green = convertToInt(matchValue);
+            blue = convertToInt(chroma + matchValue);
+        } else {
+            red = convertToInt(chroma + matchValue);
+            green = convertToInt(matchValue);
+            blue = convertToInt(secondLargestComponent + matchValue);
+        }
+
+        return new int[] {red, green, blue};
+    }
+
+    private static int convertToInt(double input) {
+        return (int) Math.round(255 * input);
+    }
+}

+ 65 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/RomanToInteger.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public final class RomanToInteger {
+    private RomanToInteger() {
+    }
+
+    private static final Map<Character, Integer> ROMAN_TO_INT = new HashMap<>() {
+        {
+            put('I', 1);
+            put('V', 5);
+            put('X', 10);
+            put('L', 50);
+            put('C', 100);
+            put('D', 500);
+            put('M', 1000);
+        }
+    };
+
+    // Roman Number = Roman Numerals
+
+    /**
+     * This function convert Roman number into Integer
+     *
+     * @param a Roman number string
+     * @return integer
+     */
+    public static int romanToInt(String a) {
+        a = a.toUpperCase();
+        char prev = ' ';
+
+        int sum = 0;
+
+        int newPrev = 0;
+        for (int i = a.length() - 1; i >= 0; i--) {
+            char c = a.charAt(i);
+
+            if (prev != ' ') {
+                // checking current Number greater than previous or not
+                newPrev = ROMAN_TO_INT.get(prev) > newPrev ? ROMAN_TO_INT.get(prev) : newPrev;
+            }
+
+            int currentNum = ROMAN_TO_INT.get(c);
+
+            // if current number greater than prev max previous then add
+            if (currentNum >= newPrev) {
+                sum += currentNum;
+            } else {
+                // subtract upcoming number until upcoming number not greater than prev max
+                sum -= currentNum;
+            }
+
+            prev = c;
+        }
+
+        return sum;
+    }
+
+    public static void main(String[] args) {
+        int sum = romanToInt("MDCCCIV");
+        System.out.println(sum);
+    }
+}

+ 67 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/conversions/TurkishToLatinConversion.java

@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.conversions;
+
+import java.util.Scanner;
+
+/**
+ * Converts turkish character to latin character
+ *
+ * @author Özgün Gökşenli
+ */
+public final class TurkishToLatinConversion {
+    private TurkishToLatinConversion() {
+    }
+
+    /**
+     * Main method
+     *
+     * @param args Command line arguments
+     */
+    public static void main(String[] args) {
+        Scanner sc = new Scanner(System.in);
+        System.out.println("Input the string: ");
+        String b = sc.next();
+        System.out.println("Converted: " + convertTurkishToLatin(b));
+        sc.close();
+    }
+
+    /**
+     * This method converts a turkish character to latin character.
+     *
+     * @param param String paramter
+     * @return String
+     */
+    public static String convertTurkishToLatin(String param) {
+        char[] turkishChars = new char[] {
+            0x131,
+            0x130,
+            0xFC,
+            0xDC,
+            0xF6,
+            0xD6,
+            0x15F,
+            0x15E,
+            0xE7,
+            0xC7,
+            0x11F,
+            0x11E,
+        };
+        char[] latinChars = new char[] {
+            'i',
+            'I',
+            'u',
+            'U',
+            'o',
+            'O',
+            's',
+            'S',
+            'c',
+            'C',
+            'g',
+            'G',
+        };
+        for (int i = 0; i < turkishChars.length; i++) {
+            param = param.replaceAll(String.valueOf(turkishChars[i]), String.valueOf(latinChars[i]));
+        }
+        return param;
+    }
+}

+ 32 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/Node.java

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Node<T> {
+
+    private final T value;
+    private final List<Node<T>> children;
+
+    public Node(final T value) {
+        this.value = value;
+        this.children = new ArrayList<>();
+    }
+
+    public Node(final T value, final List<Node<T>> children) {
+        this.value = value;
+        this.children = children;
+    }
+
+    public T getValue() {
+        return value;
+    }
+
+    public void addChild(Node<T> child) {
+        children.add(child);
+    }
+
+    public List<Node<T>> getChildren() {
+        return children;
+    }
+}

+ 128 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/bags/Bag.java

@@ -0,0 +1,128 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.bags;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Collection which does not allow removing elements (only collect and iterate)
+ *
+ * @param <Element> - the generic type of an element in this bag
+ */
+public class Bag<Element> implements Iterable<Element> {
+
+    private Node<Element> firstElement; // first element of the bag
+    private int size; // size of bag
+
+    private static final class Node<Element> {
+
+        private Element content;
+        private Node<Element> nextElement;
+    }
+
+    /**
+     * Create an empty bag
+     */
+    public Bag() {
+        firstElement = null;
+        size = 0;
+    }
+
+    /**
+     * @return true if this bag is empty, false otherwise
+     */
+    public boolean isEmpty() {
+        return firstElement == null;
+    }
+
+    /**
+     * @return the number of elements
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * @param element - the element to add
+     */
+    public void add(Element element) {
+        Node<Element> oldfirst = firstElement;
+        firstElement = new Node<>();
+        firstElement.content = element;
+        firstElement.nextElement = oldfirst;
+        size++;
+    }
+
+    /**
+     * Checks if the bag contains a specific element
+     *
+     * @param element which you want to look for
+     * @return true if bag contains element, otherwise false
+     */
+    public boolean contains(Element element) {
+        for (Element value : this) {
+            if (value.equals(element)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return an iterator that iterates over the elements in this bag in
+     * arbitrary order
+     */
+    public Iterator<Element> iterator() {
+        return new ListIterator<>(firstElement);
+    }
+
+    @SuppressWarnings("hiding")
+    private class ListIterator<Element> implements Iterator<Element> {
+
+        private Node<Element> currentElement;
+
+        ListIterator(Node<Element> firstElement) {
+            currentElement = firstElement;
+        }
+
+        public boolean hasNext() {
+            return currentElement != null;
+        }
+
+        /**
+         * remove is not allowed in a bag
+         */
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        public Element next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            Element element = currentElement.content;
+            currentElement = currentElement.nextElement;
+            return element;
+        }
+    }
+
+    /**
+     * main-method for testing
+     */
+    public static void main(String[] args) {
+        Bag<String> bag = new Bag<>();
+
+        bag.add("1");
+        bag.add("1");
+        bag.add("2");
+
+        System.out.println("size of bag = " + bag.size());
+        for (String s : bag) {
+            System.out.println(s);
+        }
+
+        System.out.println(bag.contains(null));
+        System.out.println(bag.contains("1"));
+        System.out.println(bag.contains("3"));
+    }
+}

+ 61 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/bloomfilter/BloomFilter.java

@@ -0,0 +1,61 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.bloomfilter;
+
+import java.util.BitSet;
+
+public class BloomFilter<T> {
+
+    private int numberOfHashFunctions;
+    private BitSet bitArray;
+    private Hash<T>[] hashFunctions;
+
+    public BloomFilter(int numberOfHashFunctions, int n) {
+        this.numberOfHashFunctions = numberOfHashFunctions;
+        hashFunctions = new Hash[numberOfHashFunctions];
+        bitArray = new BitSet(n);
+        insertHash();
+    }
+
+    private void insertHash() {
+        for (int i = 0; i < numberOfHashFunctions; i++) {
+            hashFunctions[i] = new Hash(i);
+        }
+    }
+
+    public void insert(T key) {
+        for (Hash<T> hash : hashFunctions) {
+            int position = hash.compute(key) % bitArray.size();
+            bitArray.set(position);
+        }
+    }
+
+    public boolean contains(T key) {
+        for (Hash<T> hash : hashFunctions) {
+            int position = hash.compute(key) % bitArray.size();
+            if (!bitArray.get(position)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private class Hash<T> {
+
+        int index;
+
+        Hash(int index) {
+            this.index = index;
+        }
+
+        public int compute(T key) {
+            return index * asciiString(String.valueOf(key));
+        }
+
+        private int asciiString(String word) {
+            int number = 0;
+            for (int i = 0; i < word.length(); i++) {
+                number += word.charAt(i);
+            }
+            return number;
+        }
+    }
+}

+ 64 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/buffers/CircularBuffer.java

@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.buffers;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class CircularBuffer<Item> {
+    private final Item[] buffer;
+    private final CircularPointer putPointer;
+    private final CircularPointer getPointer;
+    private final AtomicInteger size = new AtomicInteger(0);
+
+    public CircularBuffer(int size) {
+        // noinspection unchecked
+        this.buffer = (Item[]) new Object[size];
+        this.putPointer = new CircularPointer(0, size);
+        this.getPointer = new CircularPointer(0, size);
+    }
+
+    public boolean isEmpty() {
+        return size.get() == 0;
+    }
+
+    public boolean isFull() {
+        return size.get() == buffer.length;
+    }
+
+    public Item get() {
+        if (isEmpty()) {
+            return null;
+        }
+
+        Item item = buffer[getPointer.getAndIncrement()];
+        size.decrementAndGet();
+        return item;
+    }
+
+    public boolean put(Item item) {
+        if (isFull()) {
+            return false;
+        }
+
+        buffer[putPointer.getAndIncrement()] = item;
+        size.incrementAndGet();
+        return true;
+    }
+
+    private static class CircularPointer {
+        private int pointer;
+        private final int max;
+
+        CircularPointer(int pointer, int max) {
+            this.pointer = pointer;
+            this.max = max;
+        }
+
+        public int getAndIncrement() {
+            if (pointer == max) {
+                pointer = 0;
+            }
+            int tmp = pointer;
+            pointer++;
+            return tmp;
+        }
+    }
+}

+ 143 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/caches/LFUCache.java

@@ -0,0 +1,143 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.caches;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Java program for LFU Cache (https://en.wikipedia.org/wiki/Least_frequently_used)
+ * @author Akshay Dubey (https://github.com/itsAkshayDubey)
+ */
+public class LFUCache<K, V> {
+
+    private class Node {
+
+        private K key;
+        private V value;
+        private int frequency;
+        private Node previous;
+        private Node next;
+
+        Node(K key, V value, int frequency) {
+            this.key = key;
+            this.value = value;
+            this.frequency = frequency;
+        }
+    }
+
+    private Node head;
+    private Node tail;
+    private Map<K, Node> map = null;
+    private Integer capacity;
+    private static final int DEFAULT_CAPACITY = 100;
+
+    public LFUCache() {
+        this.capacity = DEFAULT_CAPACITY;
+    }
+
+    public LFUCache(Integer capacity) {
+        this.capacity = capacity;
+        this.map = new HashMap<>();
+    }
+
+    /**
+     * This method returns value present in the cache corresponding to the key passed as parameter
+     *
+     * @param <K> key for which value is to be retrieved
+     * @returns <V> object corresponding to the key passed as parameter, returns null if <K> key is
+     *     not present in the cache
+     */
+    public V get(K key) {
+        if (this.map.get(key) == null) {
+            return null;
+        }
+
+        Node node = map.get(key);
+        removeNode(node);
+        node.frequency += 1;
+        addNodeWithUpdatedFrequency(node);
+
+        return node.value;
+    }
+
+    /**
+     * This method stores <K> key and <V> value in the cache
+     *
+     * @param <K> key which is to be stored in the cache
+     * @param <V> value which is to be stored in the cache
+     */
+    public void put(K key, V value) {
+        if (map.containsKey(key)) {
+            Node node = map.get(key);
+            node.value = value;
+            node.frequency += 1;
+            removeNode(node);
+            addNodeWithUpdatedFrequency(node);
+        } else {
+            if (map.size() >= capacity) {
+                map.remove(this.head.key);
+                removeNode(head);
+            }
+            Node node = new Node(key, value, 1);
+            addNodeWithUpdatedFrequency(node);
+            map.put(key, node);
+        }
+    }
+
+    /**
+     * This method stores the node in the cache with updated frequency
+     *
+     * @param Node node which is to be updated in the cache
+     */
+    private void addNodeWithUpdatedFrequency(Node node) {
+        if (tail != null && head != null) {
+            Node temp = this.head;
+            while (temp != null) {
+                if (temp.frequency > node.frequency) {
+                    if (temp == head) {
+                        node.next = temp;
+                        temp.previous = node;
+                        this.head = node;
+                        break;
+                    } else {
+                        node.next = temp;
+                        node.previous = temp.previous;
+                        temp.previous.next = node;
+                        temp.previous = node;
+                        break;
+                    }
+                } else {
+                    temp = temp.next;
+                    if (temp == null) {
+                        tail.next = node;
+                        node.previous = tail;
+                        node.next = null;
+                        tail = node;
+                        break;
+                    }
+                }
+            }
+        } else {
+            tail = node;
+            head = tail;
+        }
+    }
+
+    /**
+     * This method removes node from the cache
+     *
+     * @param Node node which is to be removed in the cache
+     */
+    private void removeNode(Node node) {
+        if (node.previous != null) {
+            node.previous.next = node.next;
+        } else {
+            this.head = node.next;
+        }
+
+        if (node.next != null) {
+            node.next.previous = node.previous;
+        } else {
+            this.tail = node.previous;
+        }
+    }
+}

+ 171 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/caches/LRUCache.java

@@ -0,0 +1,171 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.caches;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Least recently used (LRU)
+ * <p>
+ * Discards the least recently used items first. This algorithm requires keeping
+ * track of what was used when, which is expensive if one wants to make sure the
+ * algorithm always discards the least recently used item.
+ * https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)
+ *
+ * @param <K> key type
+ * @param <V> value type
+ */
+public class LRUCache<K, V> {
+
+    private final Map<K, Entry<K, V>> data = new HashMap<>();
+    private Entry<K, V> head;
+    private Entry<K, V> tail;
+    private int cap;
+    private static final int DEFAULT_CAP = 100;
+
+    public LRUCache() {
+        setCapacity(DEFAULT_CAP);
+    }
+
+    public LRUCache(int cap) {
+        setCapacity(cap);
+    }
+
+    private void setCapacity(int newCapacity) {
+        checkCapacity(newCapacity);
+        for (int i = data.size(); i > newCapacity; i--) {
+            Entry<K, V> evicted = evict();
+            data.remove(evicted.getKey());
+        }
+        this.cap = newCapacity;
+    }
+
+    private Entry<K, V> evict() {
+        if (head == null) {
+            throw new RuntimeException("cache cannot be empty!");
+        }
+        Entry<K, V> evicted = head;
+        head = evicted.getNextEntry();
+        head.setPreEntry(null);
+        evicted.setNextEntry(null);
+        return evicted;
+    }
+
+    private void checkCapacity(int capacity) {
+        if (capacity <= 0) {
+            throw new RuntimeException("capacity must greater than 0!");
+        }
+    }
+
+    public V get(K key) {
+        if (!data.containsKey(key)) {
+            return null;
+        }
+        final Entry<K, V> entry = data.get(key);
+        moveNodeToLast(entry);
+        return entry.getValue();
+    }
+
+    private void moveNodeToLast(Entry<K, V> entry) {
+        if (tail == entry) {
+            return;
+        }
+        final Entry<K, V> preEntry = entry.getPreEntry();
+        final Entry<K, V> nextEntry = entry.getNextEntry();
+        if (preEntry != null) {
+            preEntry.setNextEntry(nextEntry);
+        }
+        if (nextEntry != null) {
+            nextEntry.setPreEntry(preEntry);
+        }
+        if (head == entry) {
+            head = nextEntry;
+        }
+        tail.setNextEntry(entry);
+        entry.setPreEntry(tail);
+        entry.setNextEntry(null);
+        tail = entry;
+    }
+
+    public void put(K key, V value) {
+        if (data.containsKey(key)) {
+            final Entry<K, V> existingEntry = data.get(key);
+            existingEntry.setValue(value);
+            moveNodeToLast(existingEntry);
+            return;
+        }
+        Entry<K, V> newEntry;
+        if (data.size() == cap) {
+            newEntry = evict();
+            data.remove(newEntry.getKey());
+        } else {
+            newEntry = new Entry<>();
+        }
+
+        newEntry.setKey(key);
+        newEntry.setValue(value);
+        addNewEntry(newEntry);
+        data.put(key, newEntry);
+    }
+
+    private void addNewEntry(Entry<K, V> newEntry) {
+        if (data.isEmpty()) {
+            head = newEntry;
+            tail = newEntry;
+            return;
+        }
+        tail.setNextEntry(newEntry);
+        newEntry.setPreEntry(tail);
+        newEntry.setNextEntry(null);
+        tail = newEntry;
+    }
+
+    static final class Entry<I, J> {
+
+        private Entry<I, J> preEntry;
+        private Entry<I, J> nextEntry;
+        private I key;
+        private J value;
+
+        Entry() {
+        }
+
+        Entry(Entry<I, J> preEntry, Entry<I, J> nextEntry, I key, J value) {
+            this.preEntry = preEntry;
+            this.nextEntry = nextEntry;
+            this.key = key;
+            this.value = value;
+        }
+
+        public Entry<I, J> getPreEntry() {
+            return preEntry;
+        }
+
+        public void setPreEntry(Entry<I, J> preEntry) {
+            this.preEntry = preEntry;
+        }
+
+        public Entry<I, J> getNextEntry() {
+            return nextEntry;
+        }
+
+        public void setNextEntry(Entry<I, J> nextEntry) {
+            this.nextEntry = nextEntry;
+        }
+
+        public I getKey() {
+            return key;
+        }
+
+        public void setKey(I key) {
+            this.key = key;
+        }
+
+        public J getValue() {
+            return value;
+        }
+
+        public void setValue(J value) {
+            this.value = value;
+        }
+    }
+}

+ 169 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/caches/MRUCache.java

@@ -0,0 +1,169 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.caches;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Most recently used (MRU)
+ * <p>
+ * In contrast to Least Recently Used (LRU), MRU discards the most recently used
+ * items first.
+ * https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU)
+ *
+ * @param <K> key type
+ * @param <V> value type
+ */
+public class MRUCache<K, V> {
+
+    private final Map<K, Entry<K, V>> data = new HashMap<>();
+    private Entry<K, V> head;
+    private Entry<K, V> tail;
+    private int cap;
+    private static final int DEFAULT_CAP = 100;
+
+    public MRUCache() {
+        setCapacity(DEFAULT_CAP);
+    }
+
+    private void setCapacity(int newCapacity) {
+        checkCapacity(newCapacity);
+        for (int i = data.size(); i > newCapacity; i--) {
+            Entry<K, V> evicted = evict();
+            data.remove(evicted.getKey());
+        }
+        this.cap = newCapacity;
+    }
+
+    private void checkCapacity(int capacity) {
+        if (capacity <= 0) {
+            throw new RuntimeException("capacity must greater than 0!");
+        }
+    }
+
+    private Entry<K, V> evict() {
+        if (head == null) {
+            throw new RuntimeException("cache cannot be empty!");
+        }
+        final Entry<K, V> evicted = this.tail;
+        tail = evicted.getPreEntry();
+        tail.setNextEntry(null);
+        evicted.setNextEntry(null);
+        return evicted;
+    }
+
+    public MRUCache(int cap) {
+        setCapacity(cap);
+    }
+
+    public V get(K key) {
+        if (!data.containsKey(key)) {
+            return null;
+        }
+        final Entry<K, V> entry = data.get(key);
+        moveEntryToLast(entry);
+        return entry.getValue();
+    }
+
+    public void put(K key, V value) {
+        if (data.containsKey(key)) {
+            final Entry<K, V> exitingEntry = data.get(key);
+            exitingEntry.setValue(value);
+            moveEntryToLast(exitingEntry);
+            return;
+        }
+        Entry<K, V> newEntry;
+        if (data.size() == cap) {
+            newEntry = evict();
+            data.remove(newEntry.getKey());
+        } else {
+            newEntry = new Entry<>();
+        }
+        newEntry.setKey(key);
+        newEntry.setValue(value);
+        addNewEntry(newEntry);
+        data.put(key, newEntry);
+    }
+
+    private void addNewEntry(Entry<K, V> newEntry) {
+        if (data.isEmpty()) {
+            head = newEntry;
+            tail = newEntry;
+            return;
+        }
+        tail.setNextEntry(newEntry);
+        newEntry.setPreEntry(tail);
+        newEntry.setNextEntry(null);
+        tail = newEntry;
+    }
+
+    private void moveEntryToLast(Entry<K, V> entry) {
+        if (tail == entry) {
+            return;
+        }
+        final Entry<K, V> preEntry = entry.getPreEntry();
+        final Entry<K, V> nextEntry = entry.getNextEntry();
+        if (preEntry != null) {
+            preEntry.setNextEntry(nextEntry);
+        }
+        if (nextEntry != null) {
+            nextEntry.setPreEntry(preEntry);
+        }
+        if (head == entry) {
+            head = nextEntry;
+        }
+        tail.setNextEntry(entry);
+        entry.setPreEntry(tail);
+        entry.setNextEntry(null);
+        tail = entry;
+    }
+
+    static final class Entry<I, J> {
+
+        private Entry<I, J> preEntry;
+        private Entry<I, J> nextEntry;
+        private I key;
+        private J value;
+
+        Entry() {
+        }
+
+        Entry(Entry<I, J> preEntry, Entry<I, J> nextEntry, I key, J value) {
+            this.preEntry = preEntry;
+            this.nextEntry = nextEntry;
+            this.key = key;
+            this.value = value;
+        }
+
+        public Entry<I, J> getPreEntry() {
+            return preEntry;
+        }
+
+        public void setPreEntry(Entry<I, J> preEntry) {
+            this.preEntry = preEntry;
+        }
+
+        public Entry<I, J> getNextEntry() {
+            return nextEntry;
+        }
+
+        public void setNextEntry(Entry<I, J> nextEntry) {
+            this.nextEntry = nextEntry;
+        }
+
+        public I getKey() {
+            return key;
+        }
+
+        public void setKey(I key) {
+            this.key = key;
+        }
+
+        public J getValue() {
+            return value;
+        }
+
+        public void setValue(J value) {
+            this.value = value;
+        }
+    }
+}

+ 84 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/GCounter.java

@@ -0,0 +1,84 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.crdt;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * G-Counter (Grow-only Counter) is a state-based CRDT (Conflict-free Replicated Data Type)
+ * designed for tracking counts in a distributed and concurrent environment.
+ * Each process maintains its own counter, allowing only increments. The total count
+ * is obtained by summing individual process counts.
+ * This implementation supports incrementing, querying the total count,
+ * comparing with other G-Counters, and merging with another G-Counter
+ * to compute the element-wise maximum.
+ * (https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
+ *
+ * @author itakurah (https://github.com/itakurah)
+ */
+
+class GCounter {
+    private final Map<Integer, Integer> counterMap;
+    private final int myId;
+    private final int n;
+
+    /**
+     * Constructs a G-Counter for a cluster of n nodes.
+     *
+     * @param n The number of nodes in the cluster.
+     */
+    GCounter(int myId, int n) {
+        this.myId = myId;
+        this.n = n;
+        this.counterMap = new HashMap<>();
+
+        for (int i = 0; i < n; i++) {
+            counterMap.put(i, 0);
+        }
+    }
+
+    /**
+     * Increments the counter for the current node.
+     */
+    public void increment() {
+        counterMap.put(myId, counterMap.get(myId) + 1);
+    }
+
+    /**
+     * Gets the total value of the counter by summing up values from all nodes.
+     *
+     * @return The total value of the counter.
+     */
+    public int value() {
+        int sum = 0;
+        for (int v : counterMap.values()) {
+            sum += v;
+        }
+        return sum;
+    }
+
+    /**
+     * Compares the state of this G-Counter with another G-Counter.
+     *
+     * @param other The other G-Counter to compare with.
+     * @return True if the state of this G-Counter is less than or equal to the state of the other G-Counter.
+     */
+    public boolean compare(GCounter other) {
+        for (int i = 0; i < n; i++) {
+            if (this.counterMap.get(i) > other.counterMap.get(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Merges the state of this G-Counter with another G-Counter.
+     *
+     * @param other The other G-Counter to merge with.
+     */
+    public void merge(GCounter other) {
+        for (int i = 0; i < n; i++) {
+            this.counterMap.put(i, Math.max(this.counterMap.get(i), other.counterMap.get(i)));
+        }
+    }
+}

+ 65 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/GSet.java

@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.crdt;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * GSet (Grow-only Set) is a state-based CRDT (Conflict-free Replicated Data Type)
+ * that allows only the addition of elements and ensures that once an element is added,
+ * it cannot be removed. The merge operation of two G-Sets is their union.
+ * This implementation supports adding elements, looking up elements, comparing with other G-Sets,
+ * and merging with another G-Set to create a new G-Set containing all unique elements from both sets.
+ * (https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
+ *
+ * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
+ */
+
+public class GSet<T> {
+    private final Set<T> elements;
+
+    /**
+     * Constructs an empty G-Set.
+     */
+    public GSet() {
+        this.elements = new HashSet<>();
+    }
+
+    /**
+     * Adds an element to the G-Set.
+     *
+     * @param e the element to be added
+     */
+    public void addElement(T e) {
+        elements.add(e);
+    }
+
+    /**
+     * Checks if the given element is present in the G-Set.
+     *
+     * @param e the element to be checked
+     * @return true if the element is present, false otherwise
+     */
+    public boolean lookup(T e) {
+        return elements.contains(e);
+    }
+
+    /**
+     * Compares the G-Set with another G-Set to check if it is a subset.
+     *
+     * @param other the other G-Set to compare with
+     * @return true if the current G-Set is a subset of the other, false otherwise
+     */
+    public boolean compare(GSet<T> other) {
+        return other.elements.containsAll(elements);
+    }
+
+    /**
+     * Merges the current G-Set with another G-Set, creating a new G-Set
+     * containing all unique elements from both sets.
+     *
+     * @param other the G-Set to merge with
+     */
+    public void merge(GSet<T> other) {
+        elements.addAll(other.elements);
+    }
+}

+ 138 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/LWWElementSet.java

@@ -0,0 +1,138 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.crdt;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data Type)
+ * designed for managing sets in a distributed and concurrent environment. It supports the addition and removal
+ * of elements, using timestamps to determine the order of operations. The set is split into two subsets:
+ * the add set for elements to be added and the remove set for elements to be removed.
+ *
+ * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
+ * @see <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type">Conflict-free_replicated_data_type</a>
+ * @see <a href="https://github.com/itakurah">itakurah (Niklas Hoefflin)</a>
+ */
+
+class Element {
+    String key;
+    int timestamp;
+    Bias bias;
+
+    /**
+     * Constructs a new Element with the specified key, timestamp and bias.
+     *
+     * @param key       The key of the element.
+     * @param timestamp The timestamp associated with the element.
+     * @param bias      The bias of the element (ADDS or REMOVALS).
+     */
+    Element(String key, int timestamp, Bias bias) {
+        this.key = key;
+        this.timestamp = timestamp;
+        this.bias = bias;
+    }
+}
+
+enum Bias {
+    /**
+     * ADDS bias for the add set.
+     * REMOVALS bias for the remove set.
+     */
+    ADDS,
+    REMOVALS
+}
+
+class LWWElementSet {
+    private final Map<String, Element> addSet;
+    private final Map<String, Element> removeSet;
+
+    /**
+     * Constructs an empty LWWElementSet.
+     */
+    LWWElementSet() {
+        this.addSet = new HashMap<>();
+        this.removeSet = new HashMap<>();
+    }
+
+    /**
+     * Adds an element to the addSet.
+     *
+     * @param e The element to be added.
+     */
+    public void add(Element e) {
+        addSet.put(e.key, e);
+    }
+
+    /**
+     * Removes an element from the removeSet.
+     *
+     * @param e The element to be removed.
+     */
+    public void remove(Element e) {
+        if (lookup(e)) {
+            removeSet.put(e.key, e);
+        }
+    }
+
+    /**
+     * Checks if an element is in the LWWElementSet by comparing timestamps in the addSet and removeSet.
+     *
+     * @param e The element to be checked.
+     * @return True if the element is present, false otherwise.
+     */
+    public boolean lookup(Element e) {
+        Element inAddSet = addSet.get(e.key);
+        Element inRemoveSet = removeSet.get(e.key);
+
+        return (inAddSet != null && (inRemoveSet == null || inAddSet.timestamp > inRemoveSet.timestamp));
+    }
+
+    /**
+     * Compares the LWWElementSet with another LWWElementSet to check if addSet and removeSet are a subset.
+     *
+     * @param other The LWWElementSet to compare.
+     * @return True if the set is subset, false otherwise.
+     */
+    public boolean compare(LWWElementSet other) {
+        return other.addSet.keySet().containsAll(addSet.keySet()) && other.removeSet.keySet().containsAll(removeSet.keySet());
+    }
+
+    /**
+     * Merges another LWWElementSet into this set by resolving conflicts based on timestamps.
+     *
+     * @param other The LWWElementSet to merge.
+     */
+    public void merge(LWWElementSet other) {
+        for (Element e : other.addSet.values()) {
+            if (!addSet.containsKey(e.key) || compareTimestamps(addSet.get(e.key), e)) {
+                addSet.put(e.key, e);
+            }
+        }
+
+        for (Element e : other.removeSet.values()) {
+            if (!removeSet.containsKey(e.key) || compareTimestamps(removeSet.get(e.key), e)) {
+                removeSet.put(e.key, e);
+            }
+        }
+    }
+
+    /**
+     * Compares timestamps of two elements based on their bias (ADDS or REMOVALS).
+     *
+     * @param e     The first element.
+     * @param other The second element.
+     * @return True if the first element's timestamp is greater or the bias is ADDS and timestamps are equal.
+     */
+    public boolean compareTimestamps(Element e, Element other) {
+        if (e.bias != other.bias) {
+            throw new IllegalArgumentException("Invalid bias value");
+        }
+        Bias bias = e.bias;
+        int timestampComparison = Integer.compare(e.timestamp, other.timestamp);
+
+        if (timestampComparison == 0) {
+            return bias != Bias.ADDS;
+        }
+        return timestampComparison < 0;
+    }
+}

+ 191 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/ORSet.java

@@ -0,0 +1,191 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.crdt;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * ORSet (Observed-Removed Set) is a state-based CRDT (Conflict-free Replicated Data Type)
+ * that supports both addition and removal of elements. This particular implementation follows
+ * the Add-Wins strategy, meaning that in case of conflicting add and remove operations,
+ * the add operation takes precedence. The merge operation of two OR-Sets ensures that
+ * elements added at any replica are eventually observed at all replicas. Removed elements,
+ * once observed, are never reintroduced.
+ * This OR-Set implementation provides methods for adding elements, removing elements,
+ * checking for element existence, retrieving the set of elements, comparing with other OR-Sets,
+ * and merging with another OR-Set to create a new OR-Set containing all unique elements
+ * from both sets.
+ *
+ * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
+ * @see <a href="https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type">Conflict-free_replicated_data_type</a>
+ * @see <a href="https://github.com/itakurah">itakurah (Niklas Hoefflin)</a>
+ */
+
+public class ORSet<T> {
+
+    private final Set<Pair<T>> elements;
+    private final Set<Pair<T>> tombstones;
+
+    /**
+     * Constructs an empty OR-Set.
+     */
+    public ORSet() {
+        this.elements = new HashSet<>();
+        this.tombstones = new HashSet<>();
+    }
+
+    /**
+     * Checks if the set contains the specified element.
+     *
+     * @param element the element to check for
+     * @return true if the set contains the element, false otherwise
+     */
+    public boolean contains(T element) {
+        return elements.stream().anyMatch(pair -> pair.getElement().equals(element));
+    }
+
+    /**
+     * Retrieves the elements in the set.
+     *
+     * @return a set containing the elements
+     */
+    public Set<T> elements() {
+        Set<T> result = new HashSet<>();
+        elements.forEach(pair -> result.add(pair.getElement()));
+        return result;
+    }
+
+    /**
+     * Adds the specified element to the set.
+     *
+     * @param element the element to add
+     */
+    public void add(T element) {
+        String n = prepare();
+        effect(element, n);
+    }
+
+    /**
+     * Removes the specified element from the set.
+     *
+     * @param element the element to remove
+     */
+    public void remove(T element) {
+        Set<Pair<T>> pairsToRemove = prepare(element);
+        effect(pairsToRemove);
+    }
+
+    /**
+     * Collect all pairs with the specified element.
+     *
+     * @param element the element to collect pairs for
+     * @return a set of pairs with the specified element to be removed
+     */
+    private Set<Pair<T>> prepare(T element) {
+        Set<Pair<T>> pairsToRemove = new HashSet<>();
+        for (Pair<T> pair : elements) {
+            if (pair.getElement().equals(element)) {
+                pairsToRemove.add(pair);
+            }
+        }
+        return pairsToRemove;
+    }
+
+    /**
+     * Generates a unique tag for the element.
+     *
+     * @return the unique tag
+     */
+    private String prepare() {
+        return generateUniqueTag();
+    }
+
+    /**
+     * Adds the element with the specified unique tag to the set.
+     *
+     * @param element the element to add
+     * @param n       the unique tag associated with the element
+     */
+    private void effect(T element, String n) {
+        Pair<T> pair = new Pair<>(element, n);
+        elements.add(pair);
+        elements.removeAll(tombstones);
+    }
+
+    /**
+     * Removes the specified pairs from the set.
+     *
+     * @param pairsToRemove the pairs to remove
+     */
+    private void effect(Set<Pair<T>> pairsToRemove) {
+        elements.removeAll(pairsToRemove);
+        tombstones.addAll(pairsToRemove);
+    }
+
+    /**
+     * Generates a unique tag.
+     *
+     * @return the unique tag
+     */
+    private String generateUniqueTag() {
+        return UUID.randomUUID().toString();
+    }
+
+    /**
+     * Compares this Add-Wins OR-Set with another OR-Set to check if elements and tombstones are a subset.
+     *
+     * @param other the other OR-Set to compare
+     * @return true if the sets are subset, false otherwise
+     */
+    public boolean compare(ORSet<T> other) {
+        Set<Pair<T>> union = new HashSet<>(elements);
+        union.addAll(tombstones);
+
+        Set<Pair<T>> otherUnion = new HashSet<>(other.elements);
+        otherUnion.addAll(other.tombstones);
+
+        return otherUnion.containsAll(union) && other.tombstones.containsAll(tombstones);
+    }
+
+    /**
+     * Merges this Add-Wins OR-Set with another OR-Set.
+     *
+     * @param other the other OR-Set to merge
+     */
+    public void merge(ORSet<T> other) {
+        elements.removeAll(other.tombstones);
+        other.elements.removeAll(tombstones);
+        elements.addAll(other.elements);
+        tombstones.addAll(other.tombstones);
+    }
+
+    /**
+     * Represents a pair containing an element and a unique tag.
+     *
+     * @param <T> the type of the element in the pair
+     */
+    public static class Pair<T> {
+        private final T element;
+        private final String uniqueTag;
+
+        /**
+         * Constructs a pair with the specified element and unique tag.
+         *
+         * @param element   the element in the pair
+         * @param uniqueTag the unique tag associated with the element
+         */
+        public Pair(T element, String uniqueTag) {
+            this.element = element;
+            this.uniqueTag = uniqueTag;
+        }
+
+        /**
+         * Gets the element from the pair.
+         *
+         * @return the element
+         */
+        public T getElement() {
+            return element;
+        }
+    }
+}

+ 100 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/PNCounter.java

@@ -0,0 +1,100 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.crdt;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * PN-Counter (Positive-Negative Counter) is a state-based CRDT (Conflict-free Replicated Data Type)
+ * designed for tracking counts with both increments and decrements in a distributed and concurrent environment.
+ * It combines two G-Counters, one for increments (P) and one for decrements (N).
+ * The total count is obtained by subtracting the value of the decrement counter from the increment counter.
+ * This implementation supports incrementing, decrementing, querying the total count,
+ * comparing with other PN-Counters, and merging with another PN-Counter
+ * to compute the element-wise maximum for both increment and decrement counters.
+ * (https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
+ *
+ * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
+ */
+
+class PNCounter {
+    private final Map<Integer, Integer> pCounter;
+    private final Map<Integer, Integer> nCounter;
+    private final int myId;
+    private final int n;
+
+    /**
+     * Constructs a PN-Counter for a cluster of n nodes.
+     *
+     * @param myId The identifier of the current node.
+     * @param n    The number of nodes in the cluster.
+     */
+    PNCounter(int myId, int n) {
+        this.myId = myId;
+        this.n = n;
+        this.pCounter = new HashMap<>();
+        this.nCounter = new HashMap<>();
+
+        for (int i = 0; i < n; i++) {
+            pCounter.put(i, 0);
+            nCounter.put(i, 0);
+        }
+    }
+
+    /**
+     * Increments the increment counter for the current node.
+     */
+    public void increment() {
+        pCounter.put(myId, pCounter.get(myId) + 1);
+    }
+
+    /**
+     * Increments the decrement counter for the current node.
+     */
+    public void decrement() {
+        nCounter.put(myId, nCounter.get(myId) + 1);
+    }
+
+    /**
+     * Gets the total value of the counter by subtracting the decrement counter from the increment counter.
+     *
+     * @return The total value of the counter.
+     */
+    public int value() {
+        int sumP = pCounter.values().stream().mapToInt(Integer::intValue).sum();
+        int sumN = nCounter.values().stream().mapToInt(Integer::intValue).sum();
+        return sumP - sumN;
+    }
+
+    /**
+     * Compares the state of this PN-Counter with another PN-Counter.
+     *
+     * @param other The other PN-Counter to compare with.
+     * @return True if the state of this PN-Counter is less than or equal to the state of the other PN-Counter.
+     */
+    public boolean compare(PNCounter other) {
+        if (this.n != other.n) {
+            throw new IllegalArgumentException("Cannot compare PN-Counters with different number of nodes");
+        }
+        for (int i = 0; i < n; i++) {
+            if (this.pCounter.get(i) > other.pCounter.get(i) && this.nCounter.get(i) > other.nCounter.get(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Merges the state of this PN-Counter with another PN-Counter.
+     *
+     * @param other The other PN-Counter to merge with.
+     */
+    public void merge(PNCounter other) {
+        if (this.n != other.n) {
+            throw new IllegalArgumentException("Cannot merge PN-Counters with different number of nodes");
+        }
+        for (int i = 0; i < n; i++) {
+            this.pCounter.put(i, Math.max(this.pCounter.get(i), other.pCounter.get(i)));
+            this.nCounter.put(i, Math.max(this.nCounter.get(i), other.nCounter.get(i)));
+        }
+    }
+}

+ 84 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/crdt/TwoPSet.java

@@ -0,0 +1,84 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.crdt;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * TwoPhaseSet (2P-Set) is a state-based CRDT (Conflict-free Replicated Data Type) designed for managing sets
+ * with support for both addition and removal operations in a distributed and concurrent environment.
+ * It combines two G-Sets (grow-only sets) - one set for additions and another set (tombstone set) for removals.
+ * Once an element is removed and placed in the tombstone set, it cannot be re-added, adhering to "remove-wins" semantics.
+ * This implementation supports querying the presence of elements, adding elements, removing elements,
+ * comparing with other 2P-Sets, and merging two 2P-Sets while preserving the remove-wins semantics.
+ * (https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type)
+ *
+ * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah)
+ */
+
+public class TwoPSet<T> {
+    private final Set<T> setA;
+    private final Set<T> setR;
+
+    /**
+     * Constructs an empty Two-Phase Set.
+     */
+    public TwoPSet() {
+        this.setA = new HashSet<>();
+        this.setR = new HashSet<>();
+    }
+
+    /**
+     * Checks if an element is in the set and has not been removed.
+     *
+     * @param element The element to be checked.
+     * @return True if the element is in the set and has not been removed, otherwise false.
+     */
+    public boolean lookup(T element) {
+        return setA.contains(element) && !setR.contains(element);
+    }
+
+    /**
+     * Adds an element to the set.
+     *
+     * @param element The element to be added.
+     */
+    public void add(T element) {
+        setA.add(element);
+    }
+
+    /**
+     * Removes an element from the set. The element will be placed in the tombstone set.
+     *
+     * @param element The element to be removed.
+     */
+    public void remove(T element) {
+        if (lookup(element)) {
+            setR.add(element);
+        }
+    }
+
+    /**
+     * Compares the current 2P-Set with another 2P-Set.
+     *
+     * @param otherSet The other 2P-Set to compare with.
+     * @return True if both SetA and SetR are subset, otherwise false.
+     */
+    public boolean compare(TwoPSet<T> otherSet) {
+        return otherSet.setA.containsAll(setA) && otherSet.setR.containsAll(setR);
+    }
+
+    /**
+     * Merges the current 2P-Set with another 2P-Set.
+     *
+     * @param otherSet The other 2P-Set to merge with.
+     * @return A new 2P-Set containing the merged elements.
+     */
+    public TwoPSet<T> merge(TwoPSet<T> otherSet) {
+        TwoPSet<T> mergedSet = new TwoPSet<>();
+        mergedSet.setA.addAll(this.setA);
+        mergedSet.setA.addAll(otherSet.setA);
+        mergedSet.setR.addAll(this.setR);
+        mergedSet.setR.addAll(otherSet.setR);
+        return mergedSet;
+    }
+}

+ 53 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java

@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.disjointsetunion;
+
+/**
+ * Disjoint Set Union or DSU is useful for solving problems related to connected components,
+ * cycle detection in graphs, and maintaining relationships in disjoint sets of data.
+ * It is commonly employed in graph algorithms and problems.
+ *
+ * @see <a href="https://en.wikipedia.org/wiki/Disjoint-set_data_structure">Disjoint Set Union</a>
+ */
+public class DisjointSetUnion<T> {
+
+    /**
+     * Creates a new node of DSU with parent initialised as same node
+     */
+    public Node<T> makeSet(final T x) {
+        return new Node<T>(x);
+    }
+
+    /**
+     * Finds and returns the representative (root) element of the set to which a given element belongs.
+     * This operation uses path compression to optimize future findSet operations.
+     */
+    public Node<T> findSet(Node<T> node) {
+        while (node != node.parent) {
+            node = node.parent;
+        }
+        return node;
+    }
+
+    /**
+     * Unions two sets by merging their representative elements. The merge is performed based on the rank of each set
+     * to ensure efficient merging and path compression to optimize future findSet operations.
+     */
+    public void unionSets(final Node<T> x, final Node<T> y) {
+        Node<T> nx = findSet(x);
+        Node<T> ny = findSet(y);
+
+        if (nx == ny) {
+            return; // Both elements already belong to the same set.
+        }
+        // Merging happens based on rank of node, this is done to avoid long chaining of nodes and reduce time
+        // to find root of the component. Idea is to attach small components in big, instead of other way around.
+        if (nx.rank > ny.rank) {
+            ny.parent = nx;
+        } else if (ny.rank > nx.rank) {
+            nx.parent = ny;
+        } else {
+            // Both sets have the same rank; choose one as the parent and increment the rank.
+            ny.parent = nx;
+            nx.rank++;
+        }
+    }
+}

+ 25 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/disjointsetunion/Node.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.disjointsetunion;
+
+public class Node<T> {
+
+    /**
+     * The rank of the node, used for optimizing union operations.
+     */
+    public int rank;
+
+    /**
+     * Reference to the parent node in the set.
+     * Initially, a node is its own parent (represents a singleton set).
+     */
+    public Node<T> parent;
+
+    /**
+     * The data element associated with the node.
+     */
+    public T data;
+
+    public Node(final T data) {
+        this.data = data;
+        parent = this; // Initially, a node is its own parent.
+    }
+}

+ 227 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/dynamicarray/DynamicArray.java

@@ -0,0 +1,227 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.dynamicarray;
+
+import java.util.Arrays;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class implements a dynamic array
+ *
+ * @param <E> the type that each index of the array will hold
+ */
+public class DynamicArray<E> implements Iterable<E> {
+
+    private static final int DEFAULT_CAPACITY = 16;
+
+    private int capacity;
+    private int size;
+    private Object[] elements;
+
+    /**
+     * constructor
+     *
+     * @param capacity the starting length of the desired array
+     */
+    public DynamicArray(final int capacity) {
+        this.size = 0;
+        this.capacity = capacity;
+        this.elements = new Object[this.capacity];
+    }
+
+    /**
+     * No-args constructor
+     */
+    public DynamicArray() {
+        this(DEFAULT_CAPACITY);
+    }
+
+    /**
+     * Adds an element to the array If full, creates a copy array twice the size
+     * of the current one
+     *
+     * @param element the element of type <E> to be added to the array
+     */
+    public void add(final E element) {
+        if (this.size == this.elements.length) {
+            this.elements = Arrays.copyOf(this.elements, newCapacity(2 * this.capacity));
+        }
+
+        this.elements[this.size] = element;
+        size++;
+    }
+
+    /**
+     * Places element of type <E> at the desired index
+     *
+     * @param index the index for the element to be placed
+     * @param element the element to be inserted
+     */
+    public void put(final int index, E element) {
+        this.elements[index] = element;
+    }
+
+    /**
+     * get method for element at a given index returns null if the index is
+     * empty
+     *
+     * @param index the desired index of the element
+     * @return <E> the element at the specified index
+     */
+    public E get(final int index) {
+        return getElement(index);
+    }
+
+    /**
+     * Removes an element from the array
+     *
+     * @param index the index of the element to be removed
+     * @return <E> the element removed
+     */
+    public E remove(final int index) {
+        final E oldElement = getElement(index);
+        fastRemove(this.elements, index);
+
+        if (this.capacity > DEFAULT_CAPACITY && size * 4 <= this.capacity) {
+            this.elements = Arrays.copyOf(this.elements, newCapacity(this.capacity / 2));
+        }
+        return oldElement;
+    }
+
+    /**
+     * get method for size field
+     *
+     * @return int size
+     */
+    public int getSize() {
+        return this.size;
+    }
+
+    /**
+     * isEmpty helper method
+     *
+     * @return boolean true if the array contains no elements, false otherwise
+     */
+    public boolean isEmpty() {
+        return this.size == 0;
+    }
+
+    public Stream<E> stream() {
+        return StreamSupport.stream(spliterator(), false);
+    }
+
+    private void fastRemove(final Object[] elements, final int index) {
+        final int newSize = this.size - 1;
+
+        if (newSize > index) {
+            System.arraycopy(elements, index + 1, elements, index, newSize - index);
+        }
+
+        this.size = newSize;
+        this.elements[this.size] = null;
+    }
+
+    private E getElement(final int index) {
+        return (E) this.elements[index];
+    }
+
+    private int newCapacity(int capacity) {
+        this.capacity = capacity;
+        return this.capacity;
+    }
+
+    /**
+     * returns a String representation of this object
+     *
+     * @return String a String representing the array
+     */
+    @Override
+    public String toString() {
+        return Arrays.toString(Arrays.stream(this.elements).filter(Objects::nonNull).toArray());
+    }
+
+    /**
+     * Creates and returns a new Dynamic Array Iterator
+     *
+     * @return Iterator a Dynamic Array Iterator
+     */
+    @Override
+    public Iterator<E> iterator() {
+        return new DynamicArrayIterator();
+    }
+
+    private final class DynamicArrayIterator implements Iterator<E> {
+
+        private int cursor;
+
+        @Override
+        public boolean hasNext() {
+            return this.cursor != size;
+        }
+
+        @Override
+        public E next() {
+            if (this.cursor > DynamicArray.this.size) {
+                throw new NoSuchElementException();
+            }
+
+            if (this.cursor > DynamicArray.this.elements.length) {
+                throw new ConcurrentModificationException();
+            }
+
+            final E element = DynamicArray.this.getElement(this.cursor);
+            this.cursor++;
+
+            return element;
+        }
+
+        @Override
+        public void remove() {
+            if (this.cursor < 0) {
+                throw new IllegalStateException();
+            }
+
+            DynamicArray.this.remove(this.cursor);
+            this.cursor--;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+
+            for (int i = 0; i < DynamicArray.this.size; i++) {
+                action.accept(DynamicArray.this.getElement(i));
+            }
+        }
+    }
+
+    /**
+     * This class is the driver for the DynamicArray<E> class it tests a variety
+     * of methods and prints the output
+     */
+    public static void main(String[] args) {
+        DynamicArray<String> names = new DynamicArray<>();
+        names.add("Peubes");
+        names.add("Marley");
+
+        for (String name : names) {
+            System.out.println(name);
+        }
+
+        names.stream().forEach(System.out::println);
+
+        System.out.println(names);
+
+        System.out.println(names.getSize());
+
+        names.remove(0);
+
+        for (String name : names) {
+            System.out.println(name);
+        }
+    }
+}

+ 198 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/AStar.java

@@ -0,0 +1,198 @@
+/*
+        Time Complexity = O(E), where E is equal to the number of edges
+ */
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+public final class AStar {
+    private AStar() {
+    }
+
+    private static class Graph {
+
+        // Graph's structure can be changed only applying changes to this class.
+
+        private ArrayList<ArrayList<Edge>> graph;
+
+        // Initialise ArrayLists in Constructor
+        Graph(int size) {
+            this.graph = new ArrayList<>();
+            for (int i = 0; i < size; i++) {
+                this.graph.add(new ArrayList<>());
+            }
+        }
+
+        private ArrayList<Edge> getNeighbours(int from) {
+            return this.graph.get(from);
+        }
+
+        // Graph is bidirectional, for just one direction remove second instruction of this method.
+        private void addEdge(Edge edge) {
+            this.graph.get(edge.getFrom()).add(new Edge(edge.getFrom(), edge.getTo(), edge.getWeight()));
+            this.graph.get(edge.getTo()).add(new Edge(edge.getTo(), edge.getFrom(), edge.getWeight()));
+        }
+    }
+
+    private static class Edge {
+
+        private int from;
+        private int to;
+        private int weight;
+
+        Edge(int from, int to, int weight) {
+            this.from = from;
+            this.to = to;
+            this.weight = weight;
+        }
+
+        public int getFrom() {
+            return from;
+        }
+
+        public int getTo() {
+            return to;
+        }
+
+        public int getWeight() {
+            return weight;
+        }
+    }
+
+    // class to iterate during the algorithm execution, and also used to return the solution.
+    private static class PathAndDistance {
+
+        private int distance; // distance advanced so far.
+        private ArrayList<Integer> path; // list of visited nodes in this path.
+        private int estimated; // heuristic value associated to the last node od the path (current node).
+
+        PathAndDistance(int distance, ArrayList<Integer> path, int estimated) {
+            this.distance = distance;
+            this.path = path;
+            this.estimated = estimated;
+        }
+
+        public int getDistance() {
+            return distance;
+        }
+
+        public ArrayList<Integer> getPath() {
+            return path;
+        }
+
+        public int getEstimated() {
+            return estimated;
+        }
+
+        private void printSolution() {
+            if (this.path != null) {
+                System.out.println("Optimal path: " + this.path + ", distance: " + this.distance);
+            } else {
+                System.out.println("There is no path available to connect the points");
+            }
+        }
+    }
+
+    private static void initializeGraph(Graph graph, ArrayList<Integer> data) {
+        for (int i = 0; i < data.size(); i += 4) {
+            graph.addEdge(new Edge(data.get(i), data.get(i + 1), data.get(i + 2)));
+        }
+        /*
+    .x. node
+    (y) cost
+    - or | or / bidirectional connection
+
+                          ( 98)- .7. -(86)- .4.
+                            |
+                    ( 85)- .17. -(142)- .18. -(92)- .8. -(87)- .11.
+                      |
+                     . 1. -------------------- (160)
+                      |  \                       |
+                    (211) \                     .6.
+                      |    \                     |
+                     . 5.  (101)-.13. -(138)   (115)
+                      |           |     |     /
+                    ( 99)       ( 97)   |    /
+                      |           |     |   /
+        .12. -(151)- .15. -(80)- .14.   |  /
+         |            |           |     | /
+       ( 71)        (140)       (146)- .2. -(120)
+         |            |                       |
+        .19. -( 75)- . 0.        .10. -(75)- .3.
+                      |            |
+                    (118)        ( 70)
+                      |            |
+                     .16. -(111)- .9.
+         */
+    }
+
+    public static void main(String[] args) {
+        // heuristic function optimistic values
+        int[] heuristic = {
+            366,
+            0,
+            160,
+            242,
+            161,
+            178,
+            77,
+            151,
+            226,
+            244,
+            241,
+            234,
+            380,
+            98,
+            193,
+            253,
+            329,
+            80,
+            199,
+            374,
+        };
+
+        Graph graph = new Graph(20);
+        ArrayList<Integer> graphData = new ArrayList<>(Arrays.asList(0, 19, 75, null, 0, 15, 140, null, 0, 16, 118, null, 19, 12, 71, null, 12, 15, 151, null, 16, 9, 111, null, 9, 10, 70, null, 10, 3, 75, null, 3, 2, 120, null, 2, 14, 146, null, 2, 13, 138, null, 2, 6, 115, null, 15, 14, 80, null,
+            15, 5, 99, null, 14, 13, 97, null, 5, 1, 211, null, 13, 1, 101, null, 6, 1, 160, null, 1, 17, 85, null, 17, 7, 98, null, 7, 4, 86, null, 17, 18, 142, null, 18, 8, 92, null, 8, 11, 87));
+        initializeGraph(graph, graphData);
+
+        PathAndDistance solution = aStar(3, 1, graph, heuristic);
+        solution.printSolution();
+    }
+
+    public static PathAndDistance aStar(int from, int to, Graph graph, int[] heuristic) {
+        // nodes are prioritised by the less value of the current distance of their paths, and the
+        // estimated value
+        // given by the heuristic function to reach the destination point from the current point.
+        PriorityQueue<PathAndDistance> queue = new PriorityQueue<>(Comparator.comparingInt(a -> (a.getDistance() + a.getEstimated())));
+
+        // dummy data to start the algorithm from the beginning point
+        queue.add(new PathAndDistance(0, new ArrayList<>(List.of(from)), 0));
+
+        boolean solutionFound = false;
+        PathAndDistance currentData = new PathAndDistance(-1, null, -1);
+        while (!queue.isEmpty() && !solutionFound) {
+            currentData = queue.poll(); // first in the queue, best node so keep exploring.
+            int currentPosition = currentData.getPath().get(currentData.getPath().size() - 1); // current node.
+            if (currentPosition == to) {
+                solutionFound = true;
+            } else {
+                for (Edge edge : graph.getNeighbours(currentPosition)) {
+                    if (!currentData.getPath().contains(edge.getTo())) { // Avoid Cycles
+                        ArrayList<Integer> updatedPath = new ArrayList<>(currentData.getPath());
+                        updatedPath.add(edge.getTo()); // Add the new node to the path, update the distance,
+                        // and the heuristic function value associated to that path.
+                        queue.add(new PathAndDistance(currentData.getDistance() + edge.getWeight(), updatedPath, heuristic[edge.getTo()]));
+                    }
+                }
+            }
+        }
+        return (solutionFound) ? currentData : new PathAndDistance(-1, null, -1);
+        // Out of while loop, if there is a solution, the current Data stores the optimal path, and
+        // its distance
+    }
+}

+ 184 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/BellmanFord.java

@@ -0,0 +1,184 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.Scanner;
+
+class BellmanFord /*
+                   * Implementation of Bellman ford to detect negative cycles. Graph accepts
+                   * inputs
+                   * in form of edges which have start vertex, end vertex and weights. Vertices
+                   * should be labelled with a
+                   * number between 0 and total number of vertices-1,both inclusive
+                   */
+{
+
+    int vertex;
+    int edge;
+    private Edge[] edges;
+    private int index = 0;
+
+    BellmanFord(int v, int e) {
+        vertex = v;
+        edge = e;
+        edges = new Edge[e];
+    }
+
+    class Edge {
+
+        int u;
+        int v;
+        int w;
+
+        /**
+         * @param u Source Vertex
+         * @param v End vertex
+         * @param c Weight
+         */
+        Edge(int a, int b, int c) {
+            u = a;
+            v = b;
+            w = c;
+        }
+    }
+
+    /**
+     * @param p[] Parent array which shows updates in edges
+     * @param i   Current vertex under consideration
+     */
+    void printPath(int[] p, int i) {
+        if (p[i] == -1) { // Found the path back to parent
+            return;
+        }
+        printPath(p, p[i]);
+        System.out.print(i + " ");
+    }
+
+    public static void main(String[] args) {
+        BellmanFord obj = new BellmanFord(0, 0); // Dummy object to call nonstatic variables
+        obj.go();
+    }
+
+    public void go() {
+        // shows distance to all vertices
+        // Interactive run for understanding the
+        // class first time. Assumes source vertex is 0 and
+        try (Scanner sc = new Scanner(System.in)) {
+            int i;
+            int v;
+            int e;
+            int u;
+            int ve;
+            int w;
+            int j;
+            int neg = 0;
+            System.out.println("Enter no. of vertices and edges please");
+            v = sc.nextInt();
+            e = sc.nextInt();
+            Edge[] arr = new Edge[e]; // Array of edges
+            System.out.println("Input edges");
+            for (i = 0; i < e; i++) {
+                u = sc.nextInt();
+                ve = sc.nextInt();
+                w = sc.nextInt();
+                arr[i] = new Edge(u, ve, w);
+            }
+            int[] dist = new int[v]; // Distance array for holding the finalized shortest path distance
+                                     // between source
+            // and all vertices
+            int[] p = new int[v]; // Parent array for holding the paths
+            for (i = 0; i < v; i++) {
+                dist[i] = Integer.MAX_VALUE; // Initializing distance values
+            }
+            dist[0] = 0;
+            p[0] = -1;
+            for (i = 0; i < v - 1; i++) {
+                for (j = 0; j < e; j++) {
+                    if (dist[arr[j].u] != Integer.MAX_VALUE && dist[arr[j].v] > dist[arr[j].u] + arr[j].w) {
+                        dist[arr[j].v] = dist[arr[j].u] + arr[j].w; // Update
+                        p[arr[j].v] = arr[j].u;
+                    }
+                }
+            }
+            // Final cycle for negative checking
+            for (j = 0; j < e; j++) {
+                if (dist[arr[j].u] != Integer.MAX_VALUE && dist[arr[j].v] > dist[arr[j].u] + arr[j].w) {
+                    neg = 1;
+                    System.out.println("Negative cycle");
+                    break;
+                }
+            }
+            if (neg == 0) { // Go ahead and show results of computation
+                System.out.println("Distances are: ");
+                for (i = 0; i < v; i++) {
+                    System.out.println(i + " " + dist[i]);
+                }
+                System.out.println("Path followed:");
+                for (i = 0; i < v; i++) {
+                    System.out.print("0 ");
+                    printPath(p, i);
+                    System.out.println();
+                }
+            }
+        }
+    }
+
+    /**
+     * @param source Starting vertex
+     * @param end    Ending vertex
+     * @param Edge   Array of edges
+     */
+    public void show(int source, int end,
+        Edge[] arr) { // be created by using addEdge() method and passed by calling getEdgeArray()
+                      // method // Just shows results of computation, if graph is passed to it. The
+                      // graph should
+        int i;
+        int j;
+        int v = vertex;
+        int e = edge;
+        int neg = 0;
+        double[] dist = new double[v]; // Distance array for holding the finalized shortest path
+                                       // distance between source
+        // and all vertices
+        int[] p = new int[v]; // Parent array for holding the paths
+        for (i = 0; i < v; i++) {
+            dist[i] = Integer.MAX_VALUE; // Initializing distance values
+        }
+        dist[source] = 0;
+        p[source] = -1;
+        for (i = 0; i < v - 1; i++) {
+            for (j = 0; j < e; j++) {
+                if ((int) dist[arr[j].u] != Integer.MAX_VALUE && dist[arr[j].v] > dist[arr[j].u] + arr[j].w) {
+                    dist[arr[j].v] = dist[arr[j].u] + arr[j].w; // Update
+                    p[arr[j].v] = arr[j].u;
+                }
+            }
+        }
+        // Final cycle for negative checking
+        for (j = 0; j < e; j++) {
+            if ((int) dist[arr[j].u] != Integer.MAX_VALUE && dist[arr[j].v] > dist[arr[j].u] + arr[j].w) {
+                neg = 1;
+                System.out.println("Negative cycle");
+                break;
+            }
+        }
+        if (neg == 0) { // Go ahead and show results of computaion
+            System.out.println("Distance is: " + dist[end]);
+            System.out.println("Path followed:");
+            System.out.print(source + " ");
+            printPath(p, end);
+            System.out.println();
+        }
+    }
+
+    /**
+     * @param x Source Vertex
+     * @param y End vertex
+     * @param z Weight
+     */
+    public void addEdge(int x, int y, int z) { // Adds unidirectional edge
+        edges[index++] = new Edge(x, y, z);
+    }
+
+    public Edge[] getEdgeArray() {
+        return edges;
+    }
+}

+ 81 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/BipartiteGrapfDFS.java

@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Given an adjacency list of a graph adj of V no. of vertices having 0 based
+ * index. Check whether the graph is bipartite or not.
+ *
+ * Input : {{0, 1, 0, 1}, {1, 0, 1, 0}, {0, 1, 0, 1}, {1, 0, 1, 0}}
+ *
+ * Output : YES
+ */
+public final class BipartiteGrapfDFS {
+    private BipartiteGrapfDFS() {
+    }
+
+    private static boolean bipartite(int v, ArrayList<ArrayList<Integer>> adj, int[] color, int node) {
+        if (color[node] == -1) {
+            color[node] = 1;
+        }
+        for (Integer it : adj.get(node)) {
+            if (color[it] == -1) {
+                color[it] = 1 - color[node];
+                if (!bipartite(v, adj, color, it)) {
+                    return false;
+                }
+            } else if (color[it] == color[node]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean isBipartite(int v, ArrayList<ArrayList<Integer>> adj) {
+        // Code here
+        int[] color = new int[v + 1];
+        Arrays.fill(color, -1);
+
+        for (int i = 0; i < v; i++) {
+            if (color[i] == -1) {
+                if (!bipartite(v, adj, color, i)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public static void main(String[] args) throws IOException {
+        BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
+        int t = Integer.parseInt(read.readLine().trim());
+        while (t-- > 0) {
+            String[] str1 = read.readLine().trim().split(" ");
+            int numVertices = Integer.parseInt(str1[0]);
+            int numEdges = Integer.parseInt(str1[1]);
+
+            ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
+            for (int i = 0; i < numVertices; i++) {
+                adj.add(new ArrayList<>());
+            }
+            for (int i = 0; i < numEdges; i++) {
+                String[] str2 = read.readLine().trim().split(" ");
+                int vertexU = Integer.parseInt(str2[0]);
+                int vertexV = Integer.parseInt(str2[1]);
+                adj.get(vertexU).add(vertexV);
+                adj.get(vertexV).add(vertexU);
+            }
+
+            boolean ans = isBipartite(numVertices, adj);
+            if (ans) {
+                System.out.println("YES");
+            } else {
+                System.out.println("NO");
+            }
+        }
+    }
+}

+ 217 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/BoruvkaAlgorithm.java

@@ -0,0 +1,217 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Boruvka's algorithm to find Minimum Spanning Tree
+ * (https://en.wikipedia.org/wiki/Bor%C5%AFvka%27s_algorithm)
+ *
+ * @author itakurah (https://github.com/itakurah)
+ */
+
+final class BoruvkaAlgorithm {
+    private BoruvkaAlgorithm() {
+    }
+
+    /**
+     * Represents an edge in the graph
+     */
+    static class Edge {
+        final int src;
+        final int dest;
+        final int weight;
+
+        Edge(final int src, final int dest, final int weight) {
+            this.src = src;
+            this.dest = dest;
+            this.weight = weight;
+        }
+    }
+
+    /**
+     * Represents the graph
+     */
+    static class Graph {
+        final int vertex;
+        final List<Edge> edges;
+
+        /**
+         * Constructor for the graph
+         *
+         * @param vertex number of vertices
+         * @param edges  list of edges
+         */
+        Graph(final int vertex, final List<Edge> edges) {
+            if (vertex < 0) {
+                throw new IllegalArgumentException("Number of vertices must be positive");
+            }
+            if (edges == null || edges.isEmpty()) {
+                throw new IllegalArgumentException("Edges list must not be null or empty");
+            }
+            for (final var edge : edges) {
+                checkEdgeVertices(edge.src, vertex);
+                checkEdgeVertices(edge.dest, vertex);
+            }
+
+            this.vertex = vertex;
+            this.edges = edges;
+        }
+    }
+
+    /**
+     * Represents a subset for Union-Find operations
+     */
+    private static class Component {
+        int parent;
+        int rank;
+
+        Component(final int parent, final int rank) {
+            this.parent = parent;
+            this.rank = rank;
+        }
+    }
+
+    /**
+     * Represents the state of Union-Find components and the result list
+     */
+    private static class BoruvkaState {
+        List<Edge> result;
+        Component[] components;
+        final Graph graph;
+
+        BoruvkaState(final Graph graph) {
+            this.result = new ArrayList<>();
+            this.components = initializeComponents(graph);
+            this.graph = graph;
+        }
+
+        /**
+         * Adds the cheapest edges to the result list and performs Union operation on the subsets.
+         *
+         * @param cheapest Array containing the cheapest edge for each subset.
+         */
+        void merge(final Edge[] cheapest) {
+            for (int i = 0; i < graph.vertex; ++i) {
+                if (cheapest[i] != null) {
+                    final var component1 = find(components, cheapest[i].src);
+                    final var component2 = find(components, cheapest[i].dest);
+
+                    if (component1 != component2) {
+                        result.add(cheapest[i]);
+                        union(components, component1, component2);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Checks if there are more edges to add to the result list
+         *
+         * @return true if there are more edges to add, false otherwise
+         */
+        boolean hasMoreEdgesToAdd() {
+            return result.size() < graph.vertex - 1;
+        }
+
+        /**
+         * Computes the cheapest edges for each subset in the Union-Find structure.
+         *
+         * @return an array containing the cheapest edge for each subset.
+         */
+        private Edge[] computeCheapestEdges() {
+            Edge[] cheapest = new Edge[graph.vertex];
+            for (final var edge : graph.edges) {
+                final var set1 = find(components, edge.src);
+                final var set2 = find(components, edge.dest);
+
+                if (set1 != set2) {
+                    if (cheapest[set1] == null || edge.weight < cheapest[set1].weight) {
+                        cheapest[set1] = edge;
+                    }
+                    if (cheapest[set2] == null || edge.weight < cheapest[set2].weight) {
+                        cheapest[set2] = edge;
+                    }
+                }
+            }
+            return cheapest;
+        }
+
+        /**
+         * Initializes subsets for Union-Find
+         *
+         * @param graph the graph
+         * @return the initialized subsets
+         */
+        private static Component[] initializeComponents(final Graph graph) {
+            Component[] components = new Component[graph.vertex];
+            for (int v = 0; v < graph.vertex; ++v) {
+                components[v] = new Component(v, 0);
+            }
+            return components;
+        }
+    }
+
+    /**
+     * Finds the parent of the subset using path compression
+     *
+     * @param components array of subsets
+     * @param i          index of the subset
+     * @return the parent of the subset
+     */
+    static int find(final Component[] components, final int i) {
+        if (components[i].parent != i) {
+            components[i].parent = find(components, components[i].parent);
+        }
+        return components[i].parent;
+    }
+
+    /**
+     * Performs the Union operation for Union-Find
+     *
+     * @param components array of subsets
+     * @param x          index of the first subset
+     * @param y          index of the second subset
+     */
+    static void union(Component[] components, final int x, final int y) {
+        final int xroot = find(components, x);
+        final int yroot = find(components, y);
+
+        if (components[xroot].rank < components[yroot].rank) {
+            components[xroot].parent = yroot;
+        } else if (components[xroot].rank > components[yroot].rank) {
+            components[yroot].parent = xroot;
+        } else {
+            components[yroot].parent = xroot;
+            components[xroot].rank++;
+        }
+    }
+
+    /**
+     * Boruvka's algorithm to find the Minimum Spanning Tree
+     *
+     * @param graph the graph
+     * @return list of edges in the Minimum Spanning Tree
+     */
+    static List<Edge> boruvkaMST(final Graph graph) {
+        var boruvkaState = new BoruvkaState(graph);
+
+        while (boruvkaState.hasMoreEdgesToAdd()) {
+            final var cheapest = boruvkaState.computeCheapestEdges();
+            boruvkaState.merge(cheapest);
+        }
+        return boruvkaState.result;
+    }
+
+    /**
+     * Checks if the edge vertices are in a valid range
+     *
+     * @param vertex     the vertex to check
+     * @param upperBound the upper bound for the vertex range
+     */
+    private static void checkEdgeVertices(final int vertex, final int upperBound) {
+        if (vertex < 0 || vertex >= upperBound) {
+            throw new IllegalArgumentException("Edge vertex out of range");
+        }
+    }
+}

+ 146 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/ConnectedComponent.java

@@ -0,0 +1,146 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A class that counts the number of different connected components in a graph
+ *
+ * @author Lukas Keul, Florian Mercks
+ */
+class Graph<E extends Comparable<E>> {
+
+    class Node {
+
+        E name;
+
+        Node(E name) {
+            this.name = name;
+        }
+    }
+
+    class Edge {
+
+        Node startNode;
+        Node endNode;
+
+        Edge(Node startNode, Node endNode) {
+            this.startNode = startNode;
+            this.endNode = endNode;
+        }
+    }
+
+    ArrayList<Edge> edgeList;
+    ArrayList<Node> nodeList;
+
+    Graph() {
+        edgeList = new ArrayList<Edge>();
+        nodeList = new ArrayList<Node>();
+    }
+
+    /**
+     * Adds a new Edge to the graph. If the nodes aren't yet in nodeList, they
+     * will be added to it.
+     *
+     * @param startNode the starting Node from the edge
+     * @param endNode the ending Node from the edge
+     */
+    public void addEdge(E startNode, E endNode) {
+        Node start = null;
+        Node end = null;
+        for (Node node : nodeList) {
+            if (startNode.compareTo(node.name) == 0) {
+                start = node;
+            } else if (endNode.compareTo(node.name) == 0) {
+                end = node;
+            }
+        }
+        if (start == null) {
+            start = new Node(startNode);
+            nodeList.add(start);
+        }
+        if (end == null) {
+            end = new Node(endNode);
+            nodeList.add(end);
+        }
+
+        edgeList.add(new Edge(start, end));
+    }
+
+    /**
+     * Main method used for counting the connected components. Iterates through
+     * the array of nodes to do a depth first search to get all nodes of the
+     * graph from the actual node. These nodes are added to the array
+     * markedNodes and will be ignored if they are chosen in the nodeList.
+     *
+     * @return returns the amount of unconnected graphs
+     */
+    public int countGraphs() {
+        int count = 0;
+        Set<Node> markedNodes = new HashSet<Node>();
+
+        for (Node n : nodeList) {
+            if (markedNodes.add(n)) {
+                markedNodes.addAll(depthFirstSearch(n, new ArrayList<Node>()));
+                count++;
+            }
+        }
+
+        return count;
+    }
+
+    /**
+     * Implementation of depth first search.
+     *
+     * @param n the actual visiting node
+     * @param visited A list of already visited nodes in the depth first search
+     * @return returns a set of visited nodes
+     */
+    public ArrayList<Node> depthFirstSearch(Node n, ArrayList<Node> visited) {
+        visited.add(n);
+        for (Edge e : edgeList) {
+            if (e.startNode.equals(n) && !visited.contains(e.endNode)) {
+                depthFirstSearch(e.endNode, visited);
+            }
+        }
+        return visited;
+    }
+}
+
+public final class ConnectedComponent {
+    private ConnectedComponent() {
+    }
+
+    public static void main(String[] args) {
+        Graph<Character> graphChars = new Graph<>();
+
+        // Graph 1
+        graphChars.addEdge('a', 'b');
+        graphChars.addEdge('a', 'e');
+        graphChars.addEdge('b', 'e');
+        graphChars.addEdge('b', 'c');
+        graphChars.addEdge('c', 'd');
+        graphChars.addEdge('d', 'a');
+
+        graphChars.addEdge('x', 'y');
+        graphChars.addEdge('x', 'z');
+
+        graphChars.addEdge('w', 'w');
+
+        Graph<Integer> graphInts = new Graph<>();
+
+        // Graph 2
+        graphInts.addEdge(1, 2);
+        graphInts.addEdge(2, 3);
+        graphInts.addEdge(2, 4);
+        graphInts.addEdge(3, 5);
+
+        graphInts.addEdge(7, 8);
+        graphInts.addEdge(8, 10);
+        graphInts.addEdge(10, 8);
+
+        System.out.println("Amount of different char-graphs: " + graphChars.countGraphs());
+        System.out.println("Amount of different int-graphs: " + graphInts.countGraphs());
+    }
+}

+ 92 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/Cycles.java

@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+
+class Cycle {
+
+    private final int nodes;
+    private final int edges;
+    private int[][] adjacencyMatrix;
+    private boolean[] visited;
+    ArrayList<ArrayList<Integer>> cycles = new ArrayList<ArrayList<Integer>>();
+
+    Cycle() {
+        Scanner in = new Scanner(System.in);
+        System.out.print("Enter the no. of nodes: ");
+        nodes = in.nextInt();
+        System.out.print("Enter the no. of Edges: ");
+        edges = in.nextInt();
+
+        adjacencyMatrix = new int[nodes][nodes];
+        visited = new boolean[nodes];
+
+        for (int i = 0; i < nodes; i++) {
+            visited[i] = false;
+        }
+
+        System.out.println("Enter the details of each edges <Start Node> <End Node>");
+
+        for (int i = 0; i < edges; i++) {
+            int start;
+            int end;
+            start = in.nextInt();
+            end = in.nextInt();
+            adjacencyMatrix[start][end] = 1;
+        }
+        in.close();
+    }
+
+    public void start() {
+        for (int i = 0; i < nodes; i++) {
+            ArrayList<Integer> temp = new ArrayList<>();
+            dfs(i, i, temp);
+            for (int j = 0; j < nodes; j++) {
+                adjacencyMatrix[i][j] = 0;
+                adjacencyMatrix[j][i] = 0;
+            }
+        }
+    }
+
+    private void dfs(Integer start, Integer curr, ArrayList<Integer> temp) {
+        temp.add(curr);
+        visited[curr] = true;
+        for (int i = 0; i < nodes; i++) {
+            if (adjacencyMatrix[curr][i] == 1) {
+                if (i == start) {
+                    cycles.add(new ArrayList<Integer>(temp));
+                } else {
+                    if (!visited[i]) {
+                        dfs(start, i, temp);
+                    }
+                }
+            }
+        }
+
+        if (temp.size() > 0) {
+            temp.remove(temp.size() - 1);
+        }
+        visited[curr] = false;
+    }
+
+    public void printAll() {
+        for (int i = 0; i < cycles.size(); i++) {
+            for (int j = 0; j < cycles.get(i).size(); j++) {
+                System.out.print(cycles.get(i).get(j) + " -> ");
+            }
+            System.out.println(cycles.get(i).get(0));
+            System.out.println();
+        }
+    }
+}
+
+public final class Cycles {
+    private Cycles() {
+    }
+
+    public static void main(String[] args) {
+        Cycle c = new Cycle();
+        c.start();
+        c.printAll();
+    }
+}

+ 86 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/DIJSKSTRAS_ALGORITHM.java

@@ -0,0 +1,86 @@
+/*
+Refer https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-greedy-algo-7/
+for better understanding
+ */
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+class Dijkstras {
+
+    int k = 9;
+
+    int minDist(int[] dist, Boolean[] set) {
+        int min = Integer.MAX_VALUE;
+        int minIndex = -1;
+
+        for (int r = 0; r < k; r++) {
+            if (!set[r] && dist[r] <= min) {
+                min = dist[r];
+                minIndex = r;
+            }
+        }
+
+        return minIndex;
+    }
+
+    void print(int[] dist) {
+        System.out.println("Vertex \t\t Distance");
+        for (int i = 0; i < k; i++) {
+            System.out.println(i + " \t " + dist[i]);
+        }
+    }
+
+    void dijkstra(int[][] graph, int src) {
+        int[] dist = new int[k];
+        Boolean[] set = new Boolean[k];
+
+        for (int i = 0; i < k; i++) {
+            dist[i] = Integer.MAX_VALUE;
+            set[i] = Boolean.FALSE;
+        }
+
+        dist[src] = 0;
+
+        for (int c = 0; c < k - 1; c++) {
+            int u = minDist(dist, set);
+
+            set[u] = Boolean.TRUE;
+
+            for (int v = 0; v < k; v++) {
+                if (!set[v] && graph[u][v] != 0 && dist[u] != Integer.MAX_VALUE && dist[u] + graph[u][v] < dist[v]) {
+                    dist[v] = dist[u] + graph[u][v];
+                }
+            }
+        }
+
+        print(dist);
+    }
+
+    public static void main(String[] args) {
+        int[][] graph = new int[][] {
+            {0, 4, 0, 0, 0, 0, 0, 8, 0},
+            {4, 0, 8, 0, 0, 0, 0, 11, 0},
+            {0, 8, 0, 7, 0, 4, 0, 0, 2},
+            {0, 0, 7, 0, 9, 14, 0, 0, 0},
+            {0, 0, 0, 9, 0, 10, 0, 0, 0},
+            {0, 0, 4, 14, 10, 0, 2, 0, 0},
+            {0, 0, 0, 0, 0, 2, 0, 1, 6},
+            {8, 11, 0, 0, 0, 0, 1, 0, 7},
+            {0, 0, 2, 0, 0, 0, 6, 7, 0},
+        };
+        Dijkstras t = new Dijkstras();
+        t.dijkstra(graph, 0);
+    } // main
+} // djikstras
+/*
+OUTPUT :
+Vertex   Distance
+0            0
+1            4
+2            12
+3            19
+4            21
+5            11
+6            9
+7            8
+8            14
+ */

+ 72 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/FloydWarshall.java

@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.Scanner;
+
+public class FloydWarshall {
+
+    private int[][] distanceMatrix;
+    private int numberofvertices; // number of vertices in the graph
+    public static final int INFINITY = 999;
+
+    public FloydWarshall(int numberofvertices) {
+        distanceMatrix = new int[numberofvertices + 1][numberofvertices + 1]; // stores the value of distance from all the possible path form the source
+        // vertex to destination vertex
+        // The matrix is initialized with 0's by default
+        this.numberofvertices = numberofvertices;
+    }
+
+    public void floydwarshall(int[][] adjacencyMatrix) { // calculates all the distances from source to destination vertex
+        for (int source = 1; source <= numberofvertices; source++) {
+            for (int destination = 1; destination <= numberofvertices; destination++) {
+                distanceMatrix[source][destination] = adjacencyMatrix[source][destination];
+            }
+        }
+        for (int intermediate = 1; intermediate <= numberofvertices; intermediate++) {
+            for (int source = 1; source <= numberofvertices; source++) {
+                for (int destination = 1; destination <= numberofvertices; destination++) {
+                    if (distanceMatrix[source][intermediate] + distanceMatrix[intermediate][destination] < distanceMatrix[source][destination]) { // calculated distance it get replaced as
+                                                                                                                                                  // new shortest distance // if the new
+                                                                                                                                                  // distance calculated is less then the
+                                                                                                                                                  // earlier shortest
+                        distanceMatrix[source][destination] = distanceMatrix[source][intermediate] + distanceMatrix[intermediate][destination];
+                    }
+                }
+            }
+        }
+        for (int source = 1; source <= numberofvertices; source++) {
+            System.out.print("\t" + source);
+        }
+        System.out.println();
+        for (int source = 1; source <= numberofvertices; source++) {
+            System.out.print(source + "\t");
+            for (int destination = 1; destination <= numberofvertices; destination++) {
+                System.out.print(distanceMatrix[source][destination] + "\t");
+            }
+            System.out.println();
+        }
+    }
+
+    public static void main(String... arg) {
+        Scanner scan = new Scanner(System.in);
+        System.out.println("Enter the number of vertices");
+        int numberOfVertices = scan.nextInt();
+        int[][] adjacencyMatrix = new int[numberOfVertices + 1][numberOfVertices + 1];
+        System.out.println("Enter the Weighted Matrix for the graph");
+        for (int source = 1; source <= numberOfVertices; source++) {
+            for (int destination = 1; destination <= numberOfVertices; destination++) {
+                adjacencyMatrix[source][destination] = scan.nextInt();
+                if (source == destination) {
+                    adjacencyMatrix[source][destination] = 0;
+                    continue;
+                }
+                if (adjacencyMatrix[source][destination] == 0) {
+                    adjacencyMatrix[source][destination] = INFINITY;
+                }
+            }
+        }
+        System.out.println("The Transitive Closure of the Graph");
+        FloydWarshall floydwarshall = new FloydWarshall(numberOfVertices);
+        floydwarshall.floydwarshall(adjacencyMatrix);
+        scan.close();
+    }
+}

+ 140 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/Graphs.java

@@ -0,0 +1,140 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+
+class AdjacencyListGraph<E extends Comparable<E>> {
+
+    ArrayList<Vertex> vertices;
+
+    AdjacencyListGraph() {
+        vertices = new ArrayList<>();
+    }
+
+    private class Vertex {
+
+        E data;
+        ArrayList<Vertex> adjacentVertices;
+
+        Vertex(E data) {
+            adjacentVertices = new ArrayList<>();
+            this.data = data;
+        }
+
+        public boolean addAdjacentVertex(Vertex to) {
+            for (Vertex v : adjacentVertices) {
+                if (v.data.compareTo(to.data) == 0) {
+                    return false; // the edge already exists
+                }
+            }
+            return adjacentVertices.add(to); // this will return true;
+        }
+
+        public boolean removeAdjacentVertex(E to) {
+            // use indexes here so it is possible to
+            // remove easily without implementing
+            // equals method that ArrayList.remove(Object o) uses
+            for (int i = 0; i < adjacentVertices.size(); i++) {
+                if (adjacentVertices.get(i).data.compareTo(to) == 0) {
+                    adjacentVertices.remove(i);
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * this method removes an edge from the graph between two specified
+     * vertices
+     *
+     * @param from the data of the vertex the edge is from
+     * @param to the data of the vertex the edge is going to
+     * @return returns false if the edge doesn't exist, returns true if the edge
+     * exists and is removed
+     */
+    public boolean removeEdge(E from, E to) {
+        Vertex fromV = null;
+        for (Vertex v : vertices) {
+            if (from.compareTo(v.data) == 0) {
+                fromV = v;
+                break;
+            }
+        }
+        if (fromV == null) {
+            return false;
+        }
+        return fromV.removeAdjacentVertex(to);
+    }
+
+    /**
+     * this method adds an edge to the graph between two specified vertices
+     *
+     * @param from the data of the vertex the edge is from
+     * @param to the data of the vertex the edge is going to
+     * @return returns true if the edge did not exist, return false if it
+     * already did
+     */
+    public boolean addEdge(E from, E to) {
+        Vertex fromV = null;
+        Vertex toV = null;
+        for (Vertex v : vertices) {
+            if (from.compareTo(v.data) == 0) { // see if from vertex already exists
+                fromV = v;
+            } else if (to.compareTo(v.data) == 0) { // see if to vertex already exists
+                toV = v;
+            }
+            if (fromV != null && toV != null) {
+                break; // both nodes exist so stop searching
+            }
+        }
+        if (fromV == null) {
+            fromV = new Vertex(from);
+            vertices.add(fromV);
+        }
+        if (toV == null) {
+            toV = new Vertex(to);
+            vertices.add(toV);
+        }
+        return fromV.addAdjacentVertex(toV);
+    }
+
+    /**
+     * this gives a list of vertices in the graph and their adjacencies
+     *
+     * @return returns a string describing this graph
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        for (Vertex v : vertices) {
+            sb.append("Vertex: ");
+            sb.append(v.data);
+            sb.append("\n");
+            sb.append("Adjacent vertices: ");
+            for (Vertex v2 : v.adjacentVertices) {
+                sb.append(v2.data);
+                sb.append(" ");
+            }
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+}
+
+public final class Graphs {
+    private Graphs() {
+    }
+
+    public static void main(String[] args) {
+        AdjacencyListGraph<Integer> graph = new AdjacencyListGraph<>();
+        assert graph.addEdge(1, 2);
+        assert graph.addEdge(1, 5);
+        assert graph.addEdge(2, 5);
+        assert !graph.addEdge(1, 2);
+        assert graph.addEdge(2, 3);
+        assert graph.addEdge(3, 4);
+        assert graph.addEdge(4, 1);
+        assert !graph.addEdge(2, 3);
+        System.out.println(graph);
+    }
+}

+ 107 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/HamiltonianCycle.java

@@ -0,0 +1,107 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+/**
+ * Java program for Hamiltonian Cycle
+ * (https://en.wikipedia.org/wiki/Hamiltonian_path)
+ *
+ * @author Akshay Dubey (https://github.com/itsAkshayDubey)
+ */
+public class HamiltonianCycle {
+
+    private int vertex;
+    private int pathCount;
+    private int[] cycle;
+    private int[][] graph;
+
+    /**
+     * Find hamiltonian cycle for given graph G(V,E)
+     *
+     * @param graph Adjacency matrix of a graph G(V, E)
+     *              for which hamiltonian path is to be found
+     * @return Array containing hamiltonian cycle
+     *         else returns 1D array with value -1.
+     */
+    public int[] findHamiltonianCycle(int[][] graph) {
+        this.vertex = graph.length;
+        this.cycle = new int[this.vertex + 1];
+
+        // Initialize path array with -1 value
+        for (int i = 0; i < this.cycle.length; i++) {
+            this.cycle[i] = -1;
+        }
+
+        this.graph = graph;
+
+        this.cycle[0] = 0;
+        this.pathCount = 1;
+        if (!isPathFound(0)) {
+            for (int i = 0; i < this.cycle.length; i++) {
+                this.cycle[i] = -1;
+            }
+        } else {
+            this.cycle[this.cycle.length - 1] = this.cycle[0];
+        }
+
+        return cycle;
+    }
+
+    /**
+     * function to find paths recursively
+     * Find paths recursively from given vertex
+     *
+     * @param vertex Vertex from which path is to be found
+     * @returns true if path is found false otherwise
+     */
+    public boolean isPathFound(int vertex) {
+        boolean isLastVertexConnectedToStart = this.graph[vertex][0] == 1 && this.pathCount == this.vertex;
+        if (isLastVertexConnectedToStart) {
+            return true;
+        }
+
+        /** all vertices selected but last vertex not linked to 0 **/
+        if (this.pathCount == this.vertex) {
+            return false;
+        }
+
+        for (int v = 0; v < this.vertex; v++) {
+            /** if connected **/
+            if (this.graph[vertex][v] == 1) {
+                /** add to path **/
+                this.cycle[this.pathCount++] = v;
+
+                /** remove connection **/
+                this.graph[vertex][v] = 0;
+                this.graph[v][vertex] = 0;
+
+                /** if vertex not already selected solve recursively **/
+                if (!isPresent(v)) {
+                    return isPathFound(v);
+                }
+
+                /** restore connection **/
+                this.graph[vertex][v] = 1;
+                this.graph[v][vertex] = 1;
+
+                /** remove path **/
+                this.cycle[--this.pathCount] = -1;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * function to check if path is already selected
+     * Check if path is already selected
+     *
+     * @param vertex Starting vertex
+     */
+    public boolean isPresent(int vertex) {
+        for (int i = 0; i < pathCount - 1; i++) {
+            if (cycle[i] == vertex) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}

+ 141 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/KahnsAlgorithm.java

@@ -0,0 +1,141 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+/**
+ * An algorithm that sorts a graph in toplogical order.
+ */
+/**
+ * A class that represents the adjaceny list of a graph
+ */
+class AdjacencyList<E extends Comparable<E>> {
+
+    Map<E, ArrayList<E>> adj;
+
+    AdjacencyList() {
+        adj = new LinkedHashMap<E, ArrayList<E>>();
+    }
+
+    /**
+     * This function adds an Edge to the adjaceny list
+     *
+     * @param from , the vertex the edge is from
+     * @param to, the vertex the edge is going to
+     */
+    void addEdge(E from, E to) {
+        try {
+            adj.get(from).add(to);
+        } catch (Exception E) {
+            adj.put(from, new ArrayList<E>());
+            adj.get(from).add(to);
+        }
+        if (!adj.containsKey(to)) {
+            adj.put(to, new ArrayList<E>());
+        }
+    }
+
+    /**
+     * @param v, A vertex in a graph
+     * @return returns an ArrayList of all the adjacents of vertex v
+     */
+    ArrayList<E> getAdjacents(E v) {
+        return adj.get(v);
+    }
+
+    /**
+     * @return returns a set of all vertices in the graph
+     */
+    Set<E> getVertices() {
+        return adj.keySet();
+    }
+}
+
+class TopologicalSort<E extends Comparable<E>> {
+
+    AdjacencyList<E> graph;
+    Map<E, Integer> inDegree;
+
+    TopologicalSort(AdjacencyList<E> graph) {
+        this.graph = graph;
+    }
+
+    /**
+     * Calculates the in degree of all vertices
+     */
+    void calculateInDegree() {
+        inDegree = new HashMap<>();
+        for (E vertex : graph.getVertices()) {
+            if (!inDegree.containsKey(vertex)) {
+                inDegree.put(vertex, 0);
+            }
+            for (E adjacent : graph.getAdjacents(vertex)) {
+                try {
+                    inDegree.put(adjacent, inDegree.get(adjacent) + 1);
+                } catch (Exception e) {
+                    inDegree.put(adjacent, 1);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns an ArrayList with vertices arranged in topological order
+     */
+    ArrayList<E> topSortOrder() {
+        calculateInDegree();
+        Queue<E> q = new LinkedList<E>();
+
+        for (final var entry : inDegree.entrySet()) {
+            if (entry.getValue() == 0) {
+                q.add(entry.getKey());
+            }
+        }
+
+        ArrayList<E> answer = new ArrayList<>();
+
+        while (!q.isEmpty()) {
+            E current = q.poll();
+            answer.add(current);
+            for (E adjacent : graph.getAdjacents(current)) {
+                inDegree.put(adjacent, inDegree.get(adjacent) - 1);
+                if (inDegree.get(adjacent) == 0) {
+                    q.add(adjacent);
+                }
+            }
+        }
+
+        return answer;
+    }
+}
+
+/**
+ * A driver class that sorts a given graph in topological order.
+ */
+public final class KahnsAlgorithm {
+    private KahnsAlgorithm() {
+    }
+
+    public static void main(String[] args) {
+        // Graph definition and initialization
+        AdjacencyList<String> graph = new AdjacencyList<>();
+        graph.addEdge("a", "b");
+        graph.addEdge("c", "a");
+        graph.addEdge("a", "d");
+        graph.addEdge("b", "d");
+        graph.addEdge("c", "u");
+        graph.addEdge("u", "b");
+
+        TopologicalSort<String> topSort = new TopologicalSort<>(graph);
+
+        // Printing the order
+        for (String s : topSort.topSortOrder()) {
+            System.out.print(s + " ");
+        }
+    }
+}

+ 147 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/Kosaraju.java

@@ -0,0 +1,147 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Java program that implements Kosaraju Algorithm.
+ * @author Shivanagouda S A (https://github.com/shivu2002a)
+ *
+ */
+
+/**
+ * Kosaraju algorithm is a linear time algorithm to find the strongly connected components of a
+   directed graph, which, from here onwards will be referred by SCC. It leverages the fact that the
+ transpose graph (same graph with all the edges reversed) has exactly the same SCCs as the original
+ graph.
+
+ * A graph is said to be strongly connected if every vertex is reachable from every other vertex.
+   The SCCs of a directed graph form a partition into subgraphs that are themselves strongly
+ connected. Single node is always a SCC.
+
+ * Example:
+
+    0 <--- 2 -------> 3 -------- > 4 ---- > 7
+    |     ^                      | ^       ^
+    |    /                       |  \     /
+    |   /                        |   \   /
+    v  /                         v    \ /
+    1                            5 --> 6
+
+    For the above graph, the SCC list goes as follows:
+    0, 1, 2
+    3
+    4, 5, 6
+    7
+
+    We can also see that order of the nodes in an SCC doesn't matter since they are in cycle.
+
+ {@summary}
+ * Kosaraju Algorithm:
+    1. Perform DFS traversal of the graph. Push node to stack before returning. This gives edges
+ sorted by lowest finish time.
+    2. Find the transpose graph by reversing the edges.
+    3. Pop nodes one by one from the stack and again to DFS on the modified graph.
+
+    The transpose graph of the above graph:
+     0 ---> 2 <------- 3 <------- 4 <------ 7
+    ^     /                      ^ \       /
+    |    /                       |  \     /
+    |   /                        |   \   /
+    |  v                         |    v v
+    1                            5 <--- 6
+
+    We can observe that this graph has the same SCC as that of original graph.
+
+ */
+
+public class Kosaraju {
+
+    // Sort edges according to lowest finish time
+    Stack<Integer> stack = new Stack<Integer>();
+
+    // Store each component
+    private List<Integer> scc = new ArrayList<>();
+
+    // All the strongly connected components
+    private List<List<Integer>> sccsList = new ArrayList<>();
+
+    /**
+     *
+     * @param v Node count
+     * @param list Adjacency list of graph
+     * @return List of SCCs
+     */
+    public List<List<Integer>> kosaraju(int v, List<List<Integer>> list) {
+
+        sortEdgesByLowestFinishTime(v, list);
+
+        List<List<Integer>> transposeGraph = createTransposeMatrix(v, list);
+
+        findStronglyConnectedComponents(v, transposeGraph);
+
+        return sccsList;
+    }
+
+    private void sortEdgesByLowestFinishTime(int v, List<List<Integer>> list) {
+        int[] vis = new int[v];
+        for (int i = 0; i < v; i++) {
+            if (vis[i] == 0) {
+                dfs(i, vis, list);
+            }
+        }
+    }
+
+    private List<List<Integer>> createTransposeMatrix(int v, List<List<Integer>> list) {
+        var transposeGraph = new ArrayList<List<Integer>>(v);
+        for (int i = 0; i < v; i++) {
+            transposeGraph.add(new ArrayList<>());
+        }
+        for (int i = 0; i < v; i++) {
+            for (Integer neigh : list.get(i)) {
+                transposeGraph.get(neigh).add(i);
+            }
+        }
+        return transposeGraph;
+    }
+
+    /**
+     *
+     * @param v Node count
+     * @param transposeGraph Transpose of the given adjacency list
+     */
+    public void findStronglyConnectedComponents(int v, List<List<Integer>> transposeGraph) {
+        int[] vis = new int[v];
+        while (!stack.isEmpty()) {
+            var node = stack.pop();
+            if (vis[node] == 0) {
+                dfs2(node, vis, transposeGraph);
+                sccsList.add(scc);
+                scc = new ArrayList<>();
+            }
+        }
+    }
+
+    // Dfs to store the nodes in order of lowest finish time
+    private void dfs(int node, int[] vis, List<List<Integer>> list) {
+        vis[node] = 1;
+        for (Integer neighbour : list.get(node)) {
+            if (vis[neighbour] == 0) {
+                dfs(neighbour, vis, list);
+            }
+        }
+        stack.push(node);
+    }
+
+    // Dfs to find all the nodes of each strongly connected component
+    private void dfs2(int node, int[] vis, List<List<Integer>> list) {
+        vis[node] = 1;
+        for (Integer neighbour : list.get(node)) {
+            if (vis[neighbour] == 0) {
+                dfs2(neighbour, vis, list);
+            }
+        }
+        scc.add(node);
+    }
+}

+ 103 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/Kruskal.java

@@ -0,0 +1,103 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+// Problem -> Connect all the edges with the minimum cost.
+// Possible Solution -> Kruskal Algorithm (KA), KA finds the minimum-spanning-tree, which means, the
+// group of edges with the minimum sum of their weights that connect the whole graph.
+// The graph needs to be connected, because if there are nodes impossible to reach, there are no
+// edges that could connect every node in the graph.
+// KA is a Greedy Algorithm, because edges are analysed based on their weights, that is why a
+// Priority Queue is used, to take first those less weighted.
+// This implementations below has some changes compared to conventional ones, but they are explained
+// all along the code.
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.PriorityQueue;
+
+public class Kruskal {
+
+    // Complexity: O(E log V) time, where E is the number of edges in the graph and V is the number
+    // of vertices
+    private static class Edge {
+
+        private int from;
+        private int to;
+        private int weight;
+
+        Edge(int from, int to, int weight) {
+            this.from = from;
+            this.to = to;
+            this.weight = weight;
+        }
+    }
+
+    private static void addEdge(HashSet<Edge>[] graph, int from, int to, int weight) {
+        graph[from].add(new Edge(from, to, weight));
+    }
+
+    public static void main(String[] args) {
+        HashSet<Edge>[] graph = new HashSet[7];
+        for (int i = 0; i < graph.length; i++) {
+            graph[i] = new HashSet<>();
+        }
+        addEdge(graph, 0, 1, 2);
+        addEdge(graph, 0, 2, 3);
+        addEdge(graph, 0, 3, 3);
+        addEdge(graph, 1, 2, 4);
+        addEdge(graph, 2, 3, 5);
+        addEdge(graph, 1, 4, 3);
+        addEdge(graph, 2, 4, 1);
+        addEdge(graph, 3, 5, 7);
+        addEdge(graph, 4, 5, 8);
+        addEdge(graph, 5, 6, 9);
+
+        System.out.println("Initial Graph: ");
+        for (int i = 0; i < graph.length; i++) {
+            for (Edge edge : graph[i]) {
+                System.out.println(i + " <-- weight " + edge.weight + " --> " + edge.to);
+            }
+        }
+
+        Kruskal k = new Kruskal();
+        HashSet<Edge>[] solGraph = k.kruskal(graph);
+
+        System.out.println("\nMinimal Graph: ");
+        for (int i = 0; i < solGraph.length; i++) {
+            for (Edge edge : solGraph[i]) {
+                System.out.println(i + " <-- weight " + edge.weight + " --> " + edge.to);
+            }
+        }
+    }
+
+    public HashSet<Edge>[] kruskal(HashSet<Edge>[] graph) {
+        int nodes = graph.length;
+        int[] captain = new int[nodes];
+        // captain of i, stores the set with all the connected nodes to i
+        HashSet<Integer>[] connectedGroups = new HashSet[nodes];
+        HashSet<Edge>[] minGraph = new HashSet[nodes];
+        PriorityQueue<Edge> edges = new PriorityQueue<>((Comparator.comparingInt(edge -> edge.weight)));
+        for (int i = 0; i < nodes; i++) {
+            minGraph[i] = new HashSet<>();
+            connectedGroups[i] = new HashSet<>();
+            connectedGroups[i].add(i);
+            captain[i] = i;
+            edges.addAll(graph[i]);
+        }
+        int connectedElements = 0;
+        // as soon as two sets merge all the elements, the algorithm must stop
+        while (connectedElements != nodes && !edges.isEmpty()) {
+            Edge edge = edges.poll();
+            // This if avoids cycles
+            if (!connectedGroups[captain[edge.from]].contains(edge.to) && !connectedGroups[captain[edge.to]].contains(edge.from)) {
+                // merge sets of the captains of each point connected by the edge
+                connectedGroups[captain[edge.from]].addAll(connectedGroups[captain[edge.to]]);
+                // update captains of the elements merged
+                connectedGroups[captain[edge.from]].forEach(i -> captain[i] = captain[edge.from]);
+                // add Edge to minimal graph
+                addEdge(minGraph, edge.from, edge.to, edge.weight);
+                // count how many elements have been merged
+                connectedElements = connectedGroups[captain[edge.from]].size();
+            }
+        }
+        return minGraph;
+    }
+}

+ 345 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/MatrixGraphs.java

@@ -0,0 +1,345 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+/**
+ * Implementation of a graph in a matrix form Also known as an adjacency matrix
+ * representation [Adjacency matrix -
+ * Wikipedia](https://en.wikipedia.org/wiki/Adjacency_matrix)
+ *
+ * @author Unknown
+ */
+public final class MatrixGraphs {
+    private MatrixGraphs() {
+    }
+
+    public static void main(String[] args) {
+        AdjacencyMatrixGraph graph = new AdjacencyMatrixGraph(10);
+        graph.addEdge(1, 2);
+        graph.addEdge(1, 5);
+        graph.addEdge(2, 5);
+        graph.addEdge(1, 2);
+        graph.addEdge(2, 3);
+        graph.addEdge(3, 4);
+        graph.addEdge(4, 1);
+        graph.addEdge(2, 3);
+        graph.addEdge(3, 9);
+        graph.addEdge(9, 1);
+        graph.addEdge(9, 8);
+        graph.addEdge(1, 8);
+        graph.addEdge(5, 6);
+        System.out.println("The graph matrix:");
+        System.out.println(graph);
+        System.out.println("Depth first order beginning at node '1':");
+        System.out.println(graph.depthFirstOrder(1));
+        System.out.println("Breadth first order beginning at node '1':");
+        System.out.println(graph.breadthFirstOrder(1));
+    }
+}
+
+/**
+ * AdjacencyMatrixGraph Implementation
+ */
+class AdjacencyMatrixGraph {
+
+    /**
+     * The number of vertices in the graph
+     */
+    private int vertexCount;
+
+    /**
+     * The number of edges in the graph
+     */
+    private int edgeCount;
+
+    /**
+     * The adjacency matrix for the graph
+     */
+    private int[][] adjMatrix;
+
+    /**
+     * Static variables to define whether or not an edge exists in the adjacency
+     * matrix
+     */
+    static final int EDGE_EXIST = 1;
+    static final int EDGE_NONE = 0;
+
+    /**
+     * Constructor
+     */
+    AdjacencyMatrixGraph(int givenNumberOfVertices) {
+        this.setNumberOfVertices(givenNumberOfVertices);
+        this.setNumberOfEdges(0);
+        this.setAdjacency(new int[givenNumberOfVertices][givenNumberOfVertices]);
+        for (int i = 0; i < givenNumberOfVertices; i++) {
+            for (int j = 0; j < givenNumberOfVertices; j++) {
+                this.adjacency()[i][j] = AdjacencyMatrixGraph.EDGE_NONE;
+            }
+        }
+    }
+
+    /**
+     * Updates the number of vertices in the graph
+     *
+     * @param newNumberOfVertices the new number of vertices
+     */
+    private void setNumberOfVertices(int newNumberOfVertices) {
+        this.vertexCount = newNumberOfVertices;
+    }
+
+    /**
+     * Getter for `this.vertexCount`
+     *
+     * @return the number of vertices in the graph
+     */
+    public int numberOfVertices() {
+        return this.vertexCount;
+    }
+
+    /**
+     * Updates the number of edges in the graph
+     *
+     * @param newNumberOfEdges
+     *
+     */
+    private void setNumberOfEdges(int newNumberOfEdges) {
+        this.edgeCount = newNumberOfEdges;
+    }
+
+    /**
+     * Getter for `this.edgeCount`
+     *
+     * @return the number of edges
+     */
+    public int numberOfEdges() {
+        return this.edgeCount;
+    }
+
+    /**
+     * Sets a new matrix as the adjacency matrix
+     *
+     * @param newAdjacency the new adjaceny matrix
+     */
+    private void setAdjacency(int[][] newAdjacency) {
+        this.adjMatrix = newAdjacency;
+    }
+
+    /**
+     * Getter for the adjacency matrix
+     *
+     * @return the adjacency matrix
+     */
+    private int[][] adjacency() {
+        return this.adjMatrix;
+    }
+
+    /**
+     * Checks if two vertices are connected by an edge
+     *
+     * @param from the parent vertex to check for adjacency
+     * @param to the child vertex to check for adjacency
+     * @return whether or not the vertices are adjancent
+     */
+    private boolean adjacencyOfEdgeDoesExist(int from, int to) {
+        return (this.adjacency()[from][to] != AdjacencyMatrixGraph.EDGE_NONE);
+    }
+
+    /**
+     * Checks if a particular vertex exists in a graph
+     *
+     * @param aVertex the vertex to check for existence
+     * @return whether or not the vertex exists
+     */
+    public boolean vertexDoesExist(int aVertex) {
+        return aVertex >= 0 && aVertex < this.numberOfVertices();
+    }
+
+    /**
+     * Checks if two vertices are connected by an edge
+     *
+     * @param from the parent vertex to check for adjacency
+     * @param to the child vertex to check for adjacency
+     * @return whether or not the vertices are adjancent
+     */
+    public boolean edgeDoesExist(int from, int to) {
+        if (this.vertexDoesExist(from) && this.vertexDoesExist(to)) {
+            return (this.adjacencyOfEdgeDoesExist(from, to));
+        }
+
+        return false;
+    }
+
+    /**
+     * This method adds an edge to the graph between two specified vertices
+     *
+     * @param from the data of the vertex the edge is from
+     * @param to the data of the vertex the edge is going to
+     * @return returns true if the edge did not exist, return false if it
+     * already did
+     */
+    public boolean addEdge(int from, int to) {
+        if (this.vertexDoesExist(from) && this.vertexDoesExist(to)) {
+            if (!this.adjacencyOfEdgeDoesExist(from, to)) {
+                this.adjacency()[from][to] = AdjacencyMatrixGraph.EDGE_EXIST;
+                this.adjacency()[to][from] = AdjacencyMatrixGraph.EDGE_EXIST;
+                this.setNumberOfEdges(this.numberOfEdges() + 1);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * this method removes an edge from the graph between two specified vertices
+     *
+     * @param from the data of the vertex the edge is from
+     * @param to the data of the vertex the edge is going to
+     * @return returns false if the edge doesn't exist, returns true if the edge
+     * exists and is removed
+     */
+    public boolean removeEdge(int from, int to) {
+        if (!this.vertexDoesExist(from) || !this.vertexDoesExist(to)) {
+            if (this.adjacencyOfEdgeDoesExist(from, to)) {
+                this.adjacency()[from][to] = AdjacencyMatrixGraph.EDGE_NONE;
+                this.adjacency()[to][from] = AdjacencyMatrixGraph.EDGE_NONE;
+                this.setNumberOfEdges(this.numberOfEdges() - 1);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This method returns a list of the vertices in a depth first order
+     * beginning with the specified vertex
+     *
+     * @param startVertex the vertex to begin the traversal
+     * @return the list of the ordered vertices
+     */
+    public List<Integer> depthFirstOrder(int startVertex) {
+        // If the startVertex is invalid, return an empty list
+        if (startVertex >= vertexCount || startVertex < 0) {
+            return new ArrayList<Integer>();
+        }
+
+        // Create an array to track the visited vertices
+        boolean[] visited = new boolean[vertexCount];
+
+        // Create a list to keep track of the order of our traversal
+        ArrayList<Integer> orderList = new ArrayList<Integer>();
+
+        // Perform our DFS algorithm
+        depthFirstOrder(startVertex, visited, orderList);
+
+        return orderList;
+    }
+
+    /**
+     * Helper method for public depthFirstOrder(int) that will perform a depth
+     * first traversal recursively on the graph
+     *
+     * @param currentVertex the currently exploring vertex
+     * @param visited the array of values denoting whether or not that vertex
+     * has been visited
+     * @param orderList the list to add vertices to as they are visited
+     */
+    private void depthFirstOrder(int currentVertex, boolean[] visited, List<Integer> orderList) {
+        // If this vertex has already been visited, do nothing and return
+        if (visited[currentVertex]) {
+            return;
+        }
+
+        // Visit the currentVertex by marking it as visited and adding it
+        // to the orderList
+        visited[currentVertex] = true;
+        orderList.add(currentVertex);
+
+        // Get the adjacency array for this vertex
+        int[] adjacent = adjMatrix[currentVertex];
+        for (int i = 0; i < adjacent.length; i++) { // we are considering exploring, recurse on it // If an edge exists between the
+                                                    // currentVertex and the vertex
+            if (adjacent[i] == AdjacencyMatrixGraph.EDGE_EXIST) {
+                depthFirstOrder(i, visited, orderList);
+            }
+        }
+    }
+
+    /**
+     * This method returns a list of the vertices in a breadth first order
+     * beginning with the specified vertex
+     *
+     * @param startVertex the vertext to begin the traversal
+     * @return the list of the ordered vertices
+     */
+    public List<Integer> breadthFirstOrder(int startVertex) {
+        // If the specified startVertex is invalid, return an empty list
+        if (startVertex >= vertexCount || startVertex < 0) {
+            return new ArrayList<Integer>();
+        }
+
+        // Create an array to keep track of the visited vertices
+        boolean[] visited = new boolean[vertexCount];
+
+        // Create a list to keep track of the ordered vertices
+        ArrayList<Integer> orderList = new ArrayList<Integer>();
+
+        // Create a queue for our BFS algorithm and add the startVertex
+        // to the queue
+        Queue<Integer> queue = new LinkedList<Integer>();
+        queue.add(startVertex);
+
+        // Continue until the queue is empty
+        while (!queue.isEmpty()) {
+            // Remove the first vertex in the queue
+            int currentVertex = queue.poll();
+
+            // If we've visited this vertex, skip it
+            if (visited[currentVertex]) {
+                continue;
+            }
+
+            // We now visit this vertex by adding it to the orderList and
+            // marking it as visited
+            orderList.add(currentVertex);
+            visited[currentVertex] = true;
+
+            // Get the adjacency array for the currentVertex and
+            // check each node
+            int[] adjacent = adjMatrix[currentVertex];
+            for (int vertex = 0; vertex < adjacent.length; vertex++) { // vertex we are considering exploring, we add it to the queue // If an
+                                                                       // edge exists between the current vertex and the
+                if (adjacent[vertex] == AdjacencyMatrixGraph.EDGE_EXIST) {
+                    queue.add(vertex);
+                }
+            }
+        }
+
+        return orderList;
+    }
+
+    /**
+     * this gives a list of vertices in the graph and their adjacencies
+     *
+     * @return returns a string describing this graph
+     */
+    public String toString() {
+        String s = "    ";
+        for (int i = 0; i < this.numberOfVertices(); i++) {
+            s = s + i + " ";
+        }
+        s = s + " \n";
+
+        for (int i = 0; i < this.numberOfVertices(); i++) {
+            s = s + i + " : ";
+            for (int j = 0; j < this.numberOfVertices(); j++) {
+                s = s + this.adjMatrix[i][j] + " ";
+            }
+            s = s + "\n";
+        }
+        return s;
+    }
+}

+ 110 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/PrimMST.java

@@ -0,0 +1,110 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+/**
+ * A Java program for Prim's Minimum Spanning Tree (MST) algorithm. adjacency
+ * matrix representation of the graph
+ */
+class PrimMST {
+
+    // Number of vertices in the graph
+
+    private static final int V = 5;
+
+    // A utility function to find the vertex with minimum key
+    // value, from the set of vertices not yet included in MST
+    int minKey(int[] key, Boolean[] mstSet) {
+        // Initialize min value
+        int min = Integer.MAX_VALUE;
+        int minIndex = -1;
+
+        for (int v = 0; v < V; v++) {
+            if (!mstSet[v] && key[v] < min) {
+                min = key[v];
+                minIndex = v;
+            }
+        }
+
+        return minIndex;
+    }
+
+    // A utility function to print the constructed MST stored in
+    // parent[]
+    void printMST(int[] parent, int n, int[][] graph) {
+        System.out.println("Edge   Weight");
+        for (int i = 1; i < V; i++) {
+            System.out.println(parent[i] + " - " + i + "    " + graph[i][parent[i]]);
+        }
+    }
+
+    // Function to construct and print MST for a graph represented
+    //  using adjacency matrix representation
+    void primMST(int[][] graph) {
+        // Array to store constructed MST
+        int[] parent = new int[V];
+
+        // Key values used to pick minimum weight edge in cut
+        int[] key = new int[V];
+
+        // To represent set of vertices not yet included in MST
+        Boolean[] mstSet = new Boolean[V];
+
+        // Initialize all keys as INFINITE
+        for (int i = 0; i < V; i++) {
+            key[i] = Integer.MAX_VALUE;
+            mstSet[i] = Boolean.FALSE;
+        }
+
+        // Always include first 1st vertex in MST.
+        key[0] = 0; // Make key 0 so that this vertex is
+        // picked as first vertex
+        parent[0] = -1; // First node is always root of MST
+
+        // The MST will have V vertices
+        for (int count = 0; count < V - 1; count++) {
+            // Pick thd minimum key vertex from the set of vertices
+            // not yet included in MST
+            int u = minKey(key, mstSet);
+
+            // Add the picked vertex to the MST Set
+            mstSet[u] = Boolean.TRUE;
+
+            // Update key value and parent index of the adjacent
+            // vertices of the picked vertex. Consider only those
+            // vertices which are not yet included in MST
+            for (int v = 0; v < V; v++) // Update the key only if graph[u][v] is smaller than key[v] // mstSet[v] is
+                                        // false for vertices not yet included in MST // graph[u][v] is non zero only
+                                        // for adjacent vertices of m
+            {
+                if (graph[u][v] != 0 && !mstSet[v] && graph[u][v] < key[v]) {
+                    parent[v] = u;
+                    key[v] = graph[u][v];
+                }
+            }
+        }
+
+        // print the constructed MST
+        printMST(parent, V, graph);
+    }
+
+    public static void main(String[] args) {
+        /* Let us create the following graph
+       2    3
+    (0)--(1)--(2)
+    |    / \   |
+    6| 8/   \5 |7
+    | /      \ |
+    (3)-------(4)
+         9          */
+        PrimMST t = new PrimMST();
+        int[][] graph = new int[][] {
+            {0, 2, 0, 6, 0},
+            {2, 0, 3, 8, 5},
+            {0, 3, 0, 0, 7},
+            {6, 8, 0, 0, 9},
+            {0, 5, 7, 9, 0},
+        };
+
+        // Print the solution
+        t.primMST(graph);
+    }
+}

+ 91 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/README.md

@@ -0,0 +1,91 @@
+## Graphs
+Graph is a useful data structure for representing most of the real-world problems involving a set of users/candidates/nodes and their relations. A graph consists of two parameters:
+
+```
+V = a set of vertices
+E = a set of edges
+```
+
+Each edge in `E` connects any two vertices from `V`. Based on the type of edge, graphs can be of two types:
+
+1. **Directed**: The edges are directed in nature, which means that when there is an edge from node `A` to `B`, it does not imply that there is an edge from `B` to `A`. An example of a directed edge graph is the **follow** feature of social media. If you follow a celebrity, it doesn't imply that they follow you.
+
+2. **Undirected**: The edges don't have any direction. So if `A` and `B` are connected, we can assume that there is an edge from both `A` to `B` and `B` to `A`. For example, in a social media graph, if two persons are friends, it implies that both are friends with each other.
+
+### Components of a Graph
+
+**Vertices:** Vertices are the fundamental units of the graph. Sometimes, vertices are also known as vertex or nodes. Every node/vertex can be labeled or unlabelled.
+
+**Edges:** Edges are used to connect two nodes of the graph. They can be an ordered pair of nodes in a directed graph. Edges can connect any two nodes in any possible way. There are no rules. Sometimes, edges are also known as arcs. Every edge can be labeled/unlabeled.
+
+Graphs are used to solve many real-life problems. Graphs are used to represent networks. The networks may include paths in a city, telephone network, or circuit network. Graphs are also used in social networks like LinkedIn, Facebook. For example, on Facebook, each person is represented with a vertex (or node). Each node is a structure and contains information like person id, name, gender, locale, etc.
+
+### Graph Representation
+
+Graph can be represented in the following ways:
+
+**Set Representation:** Set representation of a graph involves two sets: Set of vertices V = {V1, V2, V3, V4} and set of edges E = {{V1, V2}, {V2, V3}, {V3, V4}, {V4, V1}}. This representation is efficient for memory but does not allow parallel edges.
+
+**Sequential Representation:** This representation of a graph can be represented by means of matrices: Adjacency Matrix, Incidence matrix, and Path matrix.
+
+**Adjacency Matrix:** This matrix includes information about the adjacent nodes. Here, aij = 1 if there is an edge from Vi to Vj; otherwise, it's 0. It is a matrix of order V×V.
+
+**Incidence Matrix:** This matrix includes information about the incidence of edges on the nodes. Here, aij = 1 if the jth edge Ej is incident on the ith vertex Vi; otherwise, it's 0. It is a matrix of order V×E.
+
+**Path Matrix:** This matrix includes information about the simple path between two vertices. Here, Pij = 1 if there is a path from Vi to Vj; otherwise, it's 0. It is also called the reachability matrix of graph G.
+
+**Linked Representation:** This representation gives information about the nodes to which a specific node is connected, i.e., adjacency lists. This representation gives the adjacency lists of the vertices with the help of arrays and linked lists. In the adjacency lists, the vertices connected to the specific vertex are arranged in the form of lists that are connected to that vertex.
+
+### Real-Time Applications of Graph
+
+Graphs are used to represent the flow of control in computers.
+Graphs are used in social networking sites where users act as nodes, and connections between them act as edges.
+In an operating system, graphs are used as resource allocation graphs.
+Graphs are used in Google Maps to find the shortest route.
+Graphs are also used in the airline system for effective route optimization.
+In state transition diagrams, the graph is used to represent states and their transitions.
+In transportation, graphs are used to find the shortest path.
+In circuits, graphs can be used to represent circuit points as nodes and wires as edges.
+Graphs are used in solving puzzles with only one solution, such as mazes.
+Graphs are used in computer networks for Peer to Peer (P2P) applications.
+Graphs, basically in the form of DAG (Directed Acyclic Graph), are used as an alternative to blockchain for cryptocurrency. For example, cryptocurrencies like IOTA and Nano are mainly based on DAG.
+
+### Advantages of Graph
+
+Using graphs, we can easily find the shortest path, neighbors of the nodes, and many more.
+Graphs are used to implement algorithms like DFS and BFS.
+They are used to find minimum spanning trees, which have many practical applications.
+Graphs help in organizing data.
+Because of their non-linear structure, graphs help in understanding complex problems and their visualization.
+
+### Disadvantages of Graph
+
+Graphs use lots of pointers, which can be complex to handle.
+They can have large memory complexity.
+If the graph is represented with an adjacency matrix, then it does not allow parallel edges, and multiplication of the graph is also difficult.
+
+### Representation
+
+1. **Adjacency Lists**: Each node is represented as an entry, and all the edges are represented as a list emerging from the corresponding node. So, if vertex 1 has edges to 2, 3, and 6, the list corresponding to 1 will have 2, 3, and 6 as entries. Consider the following graph:
+
+```
+0: 1-->2-->3
+1: 0-->2
+2: 0-->1
+3: 0-->4
+4: 3
+```
+
+It means there are edges from 0 to 1, 2, and 3; from 1 to 0 and 2, and so on.
+
+2. **Adjacency Matrix**: The graph is represented as a matrix of size |V| x |V|, and an entry 1 in cell (i, j) implies that there is an edge from i to j. 0 represents no edge. The matrix for the above graph:
+
+```
+   0 1 2 3 4
+
+0  0 1 1 1 0
+1  1 0 1 0 0
+2  1 1 0 0 0
+3  1 0 0 0 1
+4  0 0 0 1 0
+```

+ 131 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/TarjansAlgorithm.java

@@ -0,0 +1,131 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Java program that implements Tarjan's Algorithm.
+ * @author Shivanagouda S A (https://github.com/shivu2002a)
+ *
+ */
+
+/**
+ * Tarjan's algorithm is a linear time algorithm to find the strongly connected components of a
+   directed graph, which, from here onwards will be referred as SCC.
+
+ * A graph is said to be strongly connected if every vertex is reachable from every other vertex.
+   The SCCs of a directed graph form a partition into subgraphs that are themselves strongly
+ connected. Single node is always a SCC.
+
+ * Example:
+    0 --------> 1 -------> 3 --------> 4
+    ^          /
+    |         /
+    |        /
+    |       /
+    |      /
+    |     /
+    |    /
+    |   /
+    |  /
+    | /
+    |V
+    2
+
+    For the above graph, the SCC list goes as follows:
+    1, 2, 0
+    3
+    4
+
+    We can also see that order of the nodes in an SCC doesn't matter since they are in cycle.
+
+ {@summary}
+    Tarjan's Algorithm:
+    * DFS search produces a DFS tree
+    * Strongly Connected Components form subtrees of the DFS tree.
+    * If we can find the head of these subtrees, we can get all the nodes in that subtree (including
+ the head) and that will be one SCC.
+    * There is no back edge from one SCC to another (here can be cross edges, but they will not be
+ used).
+
+    * Kosaraju Algorithm aims at doing the same but uses two DFS traversalse whereas Tarjan’s
+ algorithm does the same in a single DFS, which leads to much lower constant factors in the latter.
+
+ */
+public class TarjansAlgorithm {
+
+    // Timer for tracking lowtime and insertion time
+    private int time;
+
+    private List<List<Integer>> sccList = new ArrayList<List<Integer>>();
+
+    public List<List<Integer>> stronglyConnectedComponents(int v, List<List<Integer>> graph) {
+
+        // Initially all vertices as unvisited, insertion and low time are undefined
+
+        // insertionTime:Time when a node is visited 1st time while DFS traversal
+
+        // lowTime: indicates the earliest visited vertex (the vertex with minimum insertion time)
+        // that can be reached from a subtree rooted with a particular node.
+        int[] lowTime = new int[v];
+        int[] insertionTime = new int[v];
+        for (int i = 0; i < v; i++) {
+            insertionTime[i] = -1;
+            lowTime[i] = -1;
+        }
+
+        // To check if element is present in stack
+        boolean[] isInStack = new boolean[v];
+
+        // Store nodes during DFS
+        Stack<Integer> st = new Stack<Integer>();
+
+        for (int i = 0; i < v; i++) {
+            if (insertionTime[i] == -1) {
+                stronglyConnCompsUtil(i, lowTime, insertionTime, isInStack, st, graph);
+            }
+        }
+
+        return sccList;
+    }
+
+    private void stronglyConnCompsUtil(int u, int[] lowTime, int[] insertionTime, boolean[] isInStack, Stack<Integer> st, List<List<Integer>> graph) {
+
+        // Initialize insertion time and lowTime value of current node
+        insertionTime[u] = time;
+        lowTime[u] = time;
+        time += 1;
+
+        // Push current node into stack
+        isInStack[u] = true;
+        st.push(u);
+
+        // Go through all vertices adjacent to this
+        for (Integer vertex : graph.get(u)) {
+            // If the adjacent node is unvisited, do DFS
+            if (insertionTime[vertex] == -1) {
+                stronglyConnCompsUtil(vertex, lowTime, insertionTime, isInStack, st, graph);
+                // update lowTime for the current node comparing lowtime of adj node
+                lowTime[u] = Math.min(lowTime[u], lowTime[vertex]);
+            } else if (isInStack[vertex]) {
+                // If adj node is in stack, update low
+                lowTime[u] = Math.min(lowTime[u], insertionTime[vertex]);
+            }
+        }
+        // If lowtime and insertion time are same, current node is the head of an SCC
+        //  head node found, get all the nodes in this SCC
+        if (lowTime[u] == insertionTime[u]) {
+            int w = -1;
+            var scc = new ArrayList<Integer>();
+
+            // Stack has all the nodes of the current SCC
+            while (w != u) {
+                w = st.pop();
+                scc.add(w);
+                isInStack[w] = false;
+            }
+            sccList.add(scc);
+        }
+    }
+}

+ 113 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/graphs/WelshPowell.java

@@ -0,0 +1,113 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.graphs;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.stream.IntStream;
+
+/*
+ *  The Welsh-Powell algorithm is a graph coloring algorithm
+ *  used for coloring a graph with the minimum number of colors.
+ *  https://en.wikipedia.org/wiki/Graph_coloring
+ */
+
+public final class WelshPowell {
+    private static final int BLANK_COLOR = -1; // Representing uncolored state
+
+    private WelshPowell() {
+    }
+
+    static final class Graph {
+        private HashSet<Integer>[] adjacencyLists;
+
+        private Graph(int vertices) {
+            if (vertices < 0) {
+                throw new IllegalArgumentException("Number of vertices cannot be negative");
+            }
+
+            adjacencyLists = new HashSet[vertices];
+            Arrays.setAll(adjacencyLists, i -> new HashSet<>());
+        }
+
+        private void addEdge(int nodeA, int nodeB) {
+            validateVertex(nodeA);
+            validateVertex(nodeB);
+            if (nodeA == nodeB) {
+                throw new IllegalArgumentException("Self-loops are not allowed");
+            }
+            adjacencyLists[nodeA].add(nodeB);
+            adjacencyLists[nodeB].add(nodeA);
+        }
+
+        private void validateVertex(int vertex) {
+            if (vertex < 0 || vertex >= getNumVertices()) {
+                throw new IllegalArgumentException("Vertex " + vertex + " is out of bounds");
+            }
+        }
+
+        HashSet<Integer> getAdjacencyList(int vertex) {
+            return adjacencyLists[vertex];
+        }
+
+        int getNumVertices() {
+            return adjacencyLists.length;
+        }
+    }
+
+    public static Graph makeGraph(int numberOfVertices, int[][] listOfEdges) {
+        Graph graph = new Graph(numberOfVertices);
+        for (int[] edge : listOfEdges) {
+            if (edge.length != 2) {
+                throw new IllegalArgumentException("Edge array must have exactly two elements");
+            }
+            graph.addEdge(edge[0], edge[1]);
+        }
+        return graph;
+    }
+
+    public static int[] findColoring(Graph graph) {
+        int[] colors = initializeColors(graph.getNumVertices());
+        Integer[] sortedVertices = getSortedNodes(graph);
+        for (int vertex : sortedVertices) {
+            if (isBlank(colors[vertex])) {
+                boolean[] usedColors = computeUsedColors(graph, vertex, colors);
+                final var newColor = firstUnusedColor(usedColors);
+                colors[vertex] = newColor;
+                Arrays.stream(sortedVertices).forEach(otherVertex -> {
+                    if (isBlank(colors[otherVertex]) && !isAdjacentToColored(graph, otherVertex, colors)) {
+                        colors[otherVertex] = newColor;
+                    }
+                });
+            }
+        }
+        return colors;
+    }
+
+    private static boolean isBlank(int color) {
+        return color == BLANK_COLOR;
+    }
+
+    private static boolean isAdjacentToColored(Graph graph, int vertex, int[] colors) {
+        return graph.getAdjacencyList(vertex).stream().anyMatch(otherVertex -> !isBlank(colors[otherVertex]));
+    }
+
+    private static int[] initializeColors(int numberOfVertices) {
+        int[] colors = new int[numberOfVertices];
+        Arrays.fill(colors, BLANK_COLOR);
+        return colors;
+    }
+
+    private static Integer[] getSortedNodes(final Graph graph) {
+        return IntStream.range(0, graph.getNumVertices()).boxed().sorted(Comparator.comparingInt(v -> - graph.getAdjacencyList(v).size())).toArray(Integer[] ::new);
+    }
+
+    private static boolean[] computeUsedColors(final Graph graph, final int vertex, final int[] colors) {
+        boolean[] usedColors = new boolean[graph.getNumVertices()];
+        graph.getAdjacencyList(vertex).stream().map(neighbor -> colors[neighbor]).filter(color -> !isBlank(color)).forEach(color -> usedColors[color] = true);
+        return usedColors;
+    }
+
+    private static int firstUnusedColor(boolean[] usedColors) {
+        return IntStream.range(0, usedColors.length).filter(color -> !usedColors[color]).findFirst().getAsInt();
+    }
+}

+ 65 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/hashmap/Readme.md

@@ -0,0 +1,65 @@
+# HASHMAP DATA STRUCTURE
+
+A hash map organizes data so you can quickly look up values for a given key.
+
+## Strengths:
+- **Fast lookups**: Lookups take O(1) time on average.
+- **Flexible keys**: Most data types can be used for keys, as long as they're hashable.
+
+## Weaknesses:
+- **Slow worst-case**: Lookups take O(n) time in the worst case.
+- **Unordered**: Keys aren't stored in a special order. If you're looking for the smallest key, the largest key, or all the keys in a range, you'll need to look through every key to find it.
+- **Single-directional lookups**: While you can look up the value for a given key in O(1) time, looking up the keys for a given value requires looping through the whole dataset—O(n) time.
+- **Not cache-friendly**: Many hash table implementations use linked lists, which don't put data next to each other in memory.
+
+## Time Complexity
+|        | AVERAGE | WORST |
+|--------|---------|-------|
+| Space  | O(n)    | O(n)  |
+| Insert | O(1)    | O(n)  |
+| Lookup | O(1)    | O(n)  |
+| Delete | O(1)    | O(n)  |
+
+## Internal Structure of HashMap
+Internally HashMap contains an array of Node and a node is represented as a class that contains 4 fields:
+- int hash
+- K key
+- V value
+- Node next
+
+It can be seen that the node contains a reference to its object. So it’s a linked list.
+
+## Performance of HashMap
+The performance of HashMap depends on 2 parameters which are named as follows:
+- Initial Capacity
+- Load Factor
+
+
+**Initial Capacity**: It is the capacity of HashMap at the time of its creation (It is the number of buckets a HashMap can hold when the HashMap is instantiated). In Java, it is 2^4=16 initially, meaning it can hold 16 key-value pairs.
+
+**Load Factor**: It is the percent value of the capacity after which the capacity of Hashmap is to be increased (It is the percentage fill of buckets after which Rehashing takes place). In Java, it is 0.75f by default, meaning the rehashing takes place after filling 75% of the capacity.
+
+**Threshold**: It is the product of Load Factor and Initial Capacity. In Java, by default, it is (16 * 0.75 = 12). That is, Rehashing takes place after inserting 12 key-value pairs into the HashMap.
+
+**Rehashing** : It is the process of doubling the capacity of the HashMap after it reaches its Threshold. In Java, HashMap continues to rehash(by default) in the following sequence – 2^4, 2^5, 2^6, 2^7, …. so on. 
+
+If the initial capacity is kept higher then rehashing will never be done. But keeping it higher increases the time complexity of iteration. So it should be chosen very cleverly to increase performance. The expected number of values should be taken into account to set the initial capacity. The most generally preferred load factor value is 0.75 which provides a good deal between time and space costs. The load factor’s value varies between 0 and 1. 
+
+```
+Note: From Java 8 onward, Java has started using Self Balancing BST instead of a linked list for chaining. 
+The advantage of self-balancing bst is, that we get the worst case (when every key maps to the same slot) search time is O(Log n). 
+```
+
+Java has two hash table classes: HashTable and HashMap. In general, you should use a HashMap.
+
+While both classes use keys to look up values, there are some important differences, including:
+
+- A HashTable doesn't allow null keys or values; a HashMap does.
+- A HashTable is synchronized to prevent multiple threads from accessing it at once; a HashMap isn't.
+
+## When Hash Map operations cost O(n) time?
+
+**Hash collisions**: If all our keys caused hash collisions, we'd be at risk of having to walk through all of our values for a single lookup (in the example above, we'd have one big linked list). This is unlikely, but it could happen. That's the worst case.
+
+**Dynamic array resizing**: Suppose we keep adding more items to our hash map. As the number of keys and values in our hash map exceeds the number of indices in the underlying array, hash collisions become inevitable. To mitigate this, we could expand our underlying array whenever things start to get crowded. That requires allocating a larger array and rehashing all of our existing keys to figure out their new position—O(n) time.
+

+ 128 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java

@@ -0,0 +1,128 @@
+package cn.iocoder.yudao.framework.common.thealgorithms.datastructures.hashmap.hashing;
+
+import java.util.LinkedList;
+
+// implementation of generic hashmaps using array of Linked Lists
+
+public class GenericHashMapUsingArray<K, V> {
+
+    private int size; // n (total number of key-value pairs)
+    private LinkedList<Node>[] buckets; // N = buckets.length
+    private float lf = 0.75f;
+
+    public GenericHashMapUsingArray() {
+        initBuckets(16);
+        size = 0;
+    }
+
+    // load factor = 0.75 means if we need to add 100 items and we have added
+    // 75, then adding 76th item it will double the size, copy all elements
+    // & then add 76th item.
+
+    private void initBuckets(int n) {
+        buckets = new LinkedList[n];
+        for (int i = 0; i < buckets.length; i++) {
+            buckets[i] = new LinkedList<>();
+        }
+    }
+
+    public void put(K key, V value) {
+        int bucketIndex = hashFunction(key);
+        LinkedList<Node> nodes = buckets[bucketIndex];
+        for (Node node : nodes) { // if key present => update
+            if (node.key.equals(key)) {
+                node.value = value;
+                return;
+            }
+        }
+
+        // key is not present => insert
+        nodes.add(new Node(key, value));
+        size++;
+
+        if ((float) size / buckets.length > lf) {
+            reHash();
+        }
+    }
+
+    // tells which bucket to go to
+    private int hashFunction(K key) {
+        int hc = key.hashCode();
+        return Math.abs(hc) % buckets.length;
+    }
+
+    private void reHash() {
+        System.out.println("Rehashing!");
+        LinkedList<Node>[] old = buckets;
+        initBuckets(old.length * 2);
+        this.size = 0;
+
+        for (LinkedList<Node> nodes : old) {
+            for (Node node : nodes) {
+                put(node.key, node.value);
+            }
+        }
+    }
+
+    public void remove(K key) {
+        int bucketIndex = hashFunction(key);
+        LinkedList<Node> nodes = buckets[bucketIndex];
+
+        Node target = null;
+        for (Node node : nodes) {
+            if (node.key.equals(key)) {
+                target = node;
+                break;
+            }
+        }
+        nodes.remove(target);
+        size--;
+    }
+
+    public int size() {
+        return this.size;
+    }
+
+    public V get(K key) {
+        int bucketIndex = hashFunction(key);
+        LinkedList<Node> nodes = buckets[bucketIndex];
+        for (Node node : nodes) {
+            if (node.key.equals(key)) {
+                return node.value;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("{");
+        for (LinkedList<Node> nodes : buckets) {
+            for (Node node : nodes) {
+                builder.append(node.key);
+                builder.append(" : ");
+                builder.append(node.value);
+                builder.append(", ");
+            }
+        }
+        builder.append("}");
+        return builder.toString();
+    }
+
+    public boolean containsKey(K key) {
+        return get(key) != null;
+    }
+
+    public class Node {
+
+        K key;
+        V value;
+
+        public Node(K key, V value) {
+            this.key = key;
+            this.value = value;
+        }
+    }
+}

+ 0 - 0
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.