1.二分查找算法(非遞歸)html
/** * @desc 二分查詢(非遞歸方式) * 案例: * {1,3,8,10,11,67,100},編程實現二分查找,要求使用非遞歸方式完成。 * @Author xw * @Date 2019/9/27 */ public class BinarySearchNonRecursive { public static void main(String[] args) { int[] arr = {1, 3, 8, 10, 11, 67, 100}; int index = binarySearch(arr, 1); if (index != -1) { System.out.println("找到了,下標爲:" + index); } else { System.out.println("沒有找到--"); } } private static int binarySearch(int[] arr, int target) { int left = 0; int right = arr.length - 1; while (left <= right) { int mid = (left + right) / 2; if (arr[mid] == target) { return mid; } else if (arr[mid] > target) { right = mid - 1; // 向左找 } else { left = mid + 1; // 向右找 } } return -1; } }
2.分治算法git
/** * @desc 分治算法案例:漢諾塔 * (1)基本概念 * 分治算法是一種很重要的算法,字面上的解釋是「分而治之」,就是把一個複雜的問題 * 分解成兩個或更多的相同或類似的子問題...直到最後子問題能夠簡單的直接求解,原 * 問題的解即子問題的解的合併,這個技巧就是不少高效算法的基礎,如排序算法(快速排序,歸併排序),傅里葉變換(快速傅里葉變換)... * (2)基本步驟 * 1)分解:將原問題分解爲若干個規模較小的問題,相互獨立,與原問題形式相同的子問題 * 2)解決:若子問題規模較小則直接解決,不然遞歸地解各個子問題 * 3)合併:將各個子問題的解合併爲原問題的解 * (3)分治算法設計模式 * if |P|<=n0 * then return (ADHOC(P)) * // 將P分解爲較小的問題P1,P2...PK * for i <- 1 to k * do yi <- Divide-and-Conquer(Pi) 遞歸解決Pi * T <- MERGE(y1,y2...yk) 合併子問題 * return (T) * <p> * |P|:表示問題P的規模 * n0:表示閾值,表示當問題P的規模不超過n0時,問題已容易直接解出,沒必要再繼續分解。 * ADHOC(P):是該分治法中的基本子算法,用於直接解小規模的問題P。所以,當P的規模不超過n0時直接用算法ADHOC(P)求解 * 算法MERGE(y1,y2...yk):是該分治算法中的合併子算法,用於將P的子問題P1,P2...PK的相應的解y1,y2,..yk合併爲P的解。 * <p> * 經典案例:漢諾塔 * 思路分析: * (1)若是有一個盤,A->C * n0=2 * if (n<=n0) { * // 直接解出來 * } * // 將P分解爲較小的問題P1,P2...PK * while(n>n0) { * 分(n); * n--; * } * // T <- MERGE(y1,y2...yk) 合併子問題 * @Author xw * @Date 2019/9/27 */ public class HanoiTower { public static void main(String[] args) { hanoiTower(3, 'A', 'B', 'C'); } private static void hanoiTower(int num, char a, char b, char c) { if (num == 1) { // 只有一個盤,直接解出 System.out.println("第1個盤從" + a + "->" + c); } else { // 若是n>=2的狀況 // 1.先把最上面的全部盤A->B,移動過程會使用C hanoiTower(num - 1, a, c, b); // 2.把最下邊的盤A->C System.out.println("第" + num + "個盤從" + a + "->" + c); // 3.把B塔全部盤從B->C,移動過程使用到A hanoiTower(num - 1, b, a, c); } } }
3.動態規劃算法github
/** * @desc 動態規劃算法案例:揹包問題 * 思路分析: * (1)假設: * 用w[i],v[i]來肯定是否須要將該物品放入揹包中; * 即對於給定的n個物品,設v[i],w[i]分別爲第i個物品的價值和重量,C爲揹包的容量。 * 再令v[i][j] 表示在前i個物品中可以裝入容量j的揹包的最大價值。則咱們有下面的結果: * (2)結論: * 1)當v[i][0]=v[0][j]=0; // 表示填入表 第一行和第一列是0 * 2)當w[i]>j時;v[i][j]=v[i-1][j] // 當準備加入新增的商品的容量大於當前揹包的容量時,就直接使用上一個單元格的裝入策略 * 3)當j>=w[i]時;v[i][j]=max{v[i-1][j], v[i]+v[i-1][j-w[i]]} * // 當準入的新增的商品的容量小於等於當前揹包的容量,裝入方式: * v[i-1][j]:就是上一個單元格的裝入的最大值 * v[i]:表示當前商品的價值 * v[i-1][j-w[i]]:裝入i-1商品,到剩餘空間j-w[i]的最大值 * 當j>=w[i]時:v[i][j] = max{v[i-1][j], v[i-1][j-w[i]]} * <p> * 案例: * 物品 重量 價格 * 吉他(G) 1 1500 * 音響(S) 4 3000 * 電腦(L) 3 2000 * @Author xw * @Date 2019/9/27 */ public class KnapsackProblem { public static void main(String[] args) { int[] w = {1, 4, 3}; // 物品重量 int[] val = {1500, 3000, 2000}; // 物品價值 int m = 4; // 揹包的容量 int n = val.length; // 物品個數 // 建立二維數據 int[][] v = new int[n + 1][m + 1]; // 1)當v[i][0]=v[0][j]=0; // 表示填入表 第一行和第一列是0 for (int i = 0; i < v.length; i++) { v[0][i] = 0; // 第一列爲0 } for (int i = 0; i < v.length; i++) { v[i][0] = 0; // 第一行爲0 } int[][] path = new int[n + 1][m + 1]; for (int i = 1; i < v.length; i++) { for (int j = 1; j < v[0].length; j++) { // 不處理第1列 // 當w[i]>j時;v[i][j]=v[i-1][j] // 當準備加入新增的商品的容量大於當前揹包的容量時,就直接使用上一個單元格的裝入策略 if (w[i - 1] > j) { v[i][j] = v[i - 1][j]; } else { // 當j>=w[i]時;v[i][j]=max{v[i-1][j], v[i]+v[i-1][j-w[i]]} // v[i-1][j]:就是上一個單元格的裝入的最大值 // v[i]:表示當前商品的價值 // v[i-1][j-w[i]]:裝入i-1商品,到剩餘空間j-w[i]的最大值 // 當準入的新增的商品的容量小於等於當前揹包的容量,裝入方式: if (v[i - 1][j] < val[i - 1] + v[i - 1][j - w[i - 1]]) { // w[i]->w[i-1]替換? v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]]; // 把當前的狀況記錄到path path[i][j] = 1; } else { v[i][j] = v[i - 1][j]; } } } } // 輸出一把 for (int i = 0; i < v.length; i++) { for (int j = 0; j < v[i].length; j++) { System.out.print(v[i][j] + "\t"); } System.out.println(); } System.out.println("========================"); /*for (int i = 0; i < path.length; i++) { for (int j = 0; j < path[i].length; j++) { if (path[i][j] == 1) { System.out.println(String.format("第%d個商品放入揹包", i)); } } }*/ // 其實咱們只須要最後的放入 int i = path.length - 1; int j = path[0].length - 1; while (i > 0 && j > 0) { if (path[i][j] == 1) { System.out.println(String.format("第%d個商品放入到揹包", i)); j -= w[i - 1]; } i--; } } }
4.KMP算法算法
/** * @desc KMP算法 * 基本介紹: * (1)暴力匹配算法 * 1)若是當前字符匹配成功(即str1[i]=str2[i]),則i++,j++,繼續匹配下一個字符 * 2)若是失敗,令i=i-(j-1),j=0,至關於每次匹配失敗時,i回溯,j被轉爲0 * 3)用暴力方法解決的話就會有大量的回溯,每次只移動一位,如果不匹配,移動到下一位接着判斷,浪費大量時間。(不可行) * 4)暴力匹配實現 * (2)KMP算法介紹 * 1)KMP是一個解決模式串在文本串是否出現過,若是出現過,最先出現的位置就經典算法。 * 2)Knuth-Morris-Pratt字符串查找法,簡稱KMP。 * 3)KMP算法就是利用以前判斷過信息,經過一個next數組,保存模式串中先後最長公共序列的長度,每次回溯時,經過next數組找到, * 前面匹配的位置,省去了大量的計算時間 * 4)參考資料:https://www.cnblogs.com/ZuoAndFutureGirl/p/9028287.html * @Author xw * @Date 2019/9/27 */ public class KMPAlgorithm { public static void main(String[] args) { // 暴力匹配 String str1 = "ABCDE"; String str2 = "CD"; int index = violenceMatch(str1, str2); if (index != -1) { System.out.println("找到了,位置:" + index); } else { System.out.println("沒有找到!"); } // KMP算法介紹 // 字符串模板匹配值 str1 = "BBC ABCDAD ABCDABCDABDE"; str2 = "ABCDABD"; /*int[] next = kmpNext("ABCDABD"); System.out.println("next=" + Arrays.toString(next));*/ index = kmpMatch(str1, str2, kmpNext(str2)); if (index != -1) { System.out.println("找到了,位置:" + index); } else { System.out.println("沒有找到!"); } } }
5.貪心算法編程
/** * @desc 貪心算法 * 思路分析 * (1)使用窮舉法,列出每一個可能廣播臺集合,這被稱爲冪集。 * (2)假設有n個廣播臺,則廣播臺的組合共有2^n-1個,假設每秒能夠計算10個子集 * 廣播臺數量 子集總數 須要的時間 * 5 32 3.2秒 * 10 1024 102.4秒 * ... * * 案例:集合覆蓋問題 * 假設存在下面須要付費的廣播臺,以及廣播信號能夠覆蓋的地區,如何選擇 * 最少的廣播臺,讓全部的地區均可以接收信息 * 廣播臺 覆蓋地區 * K1 "北京","上海","天津" * K2 "廣州","北京","深圳" * K3 "成都","上海","杭州" * K4 "上海","天津" * K5 "杭州","大連" * @Author xw * @Date 2019/9/27 */ public class GreedyAlgorithm { public static void main(String[] args) { Map<String, Set<String>> broadcasts = new HashMap<>(); // 廣播電臺 broadcasts.put("K1", Arrays.stream(new String[]{"北京", "上海", "天津"}).collect(Collectors.toSet())); broadcasts.put("K2", Arrays.stream(new String[]{"廣州", "北京", "深圳"}).collect(Collectors.toSet())); broadcasts.put("K3", Arrays.stream(new String[]{"成都", "上海", "杭州"}).collect(Collectors.toSet())); broadcasts.put("K4", Arrays.stream(new String[]{"上海", "天津"}).collect(Collectors.toSet())); broadcasts.put("K5", Arrays.stream(new String[]{"杭州", "大連"}).collect(Collectors.toSet())); // [上海, 天津, 北京, 廣州, 深圳, 成都, 杭州, 大連] List<String> allAreas = broadcasts.values().stream().flatMap(Collection::stream).distinct().collect(Collectors.toList()); // 表示全部須要覆蓋的地區 System.out.println("allAreas=" + allAreas); List<String> selects = new ArrayList<>(); // 選擇的地區集合 // 定義一個臨時的集合,在遍歷過程當中,存放遍歷過程當中的電臺覆蓋的地區和當前尚未覆蓋的地區的交集 Set<String> tempSet = new HashSet<>(); String maxKey; // 最大的電臺,保存在一次遍歷過程當中,可以覆蓋最大未覆蓋的地區對應的電臺key while (allAreas.size() != 0) { maxKey = null; // 置空 // 遍歷broadcasts,取出對應key for (String key : broadcasts.keySet()) { tempSet.clear(); // 清空 Set<String> areas = broadcasts.get(key); tempSet.addAll(areas); tempSet.retainAll(allAreas); // tempSet = tempSet與allAreas的交集 if (tempSet.size() > 0 && (maxKey == null || tempSet.size() > broadcasts.get(maxKey).size())) { maxKey = key; } } if (maxKey != null) { selects.add(maxKey); // 將maxKey指向的廣播電臺覆蓋地區,從allAreas去掉 System.out.println("maxKey=" + maxKey); allAreas.removeAll(broadcasts.get(maxKey)); } } System.out.println("獲得的選擇結果是:" + selects); } }
6.普利姆算法設計模式
/** * @desc 普利姆算法 * 應用案例:修路問題 * <p> * 思路分析 * 1.從<A>頂點開始處理=><A,G> 2 * A,C[7] A-G[2] A-B[5] => * 2.<A,G>開始,將A和G頂點和他們相鄰的尚未訪問的頂面進行處理=> <A,G,B> * A-C[7] A-B[5] G-B[3] G-F[6] * 3.<A,G,B>開始,將A,G,B頂點和他們相鄰的尚未訪問的頂面進行處理=> <A,G,B> * A-C[7] G-E[4] G-F[6] B-D[9] * ... * 4.{A,G,B,E,F,D} -> C // 第6次大循環,對應邊<A,C>權值:7 => <A,G,B,E,F,D,C> * @Author xw * @Date 2019/10/4 */ public class PrimAlgorithm { public static void main(String[] args) { char[] data = {'A','B','C','D','E','F','G'}; int verxs = data.length; // 鄰接矩陣 int[][] weight = new int[][] { {10000,5,7,10000,10000,10000,2}, {5,10000,10000,9,10000,10000,3}, {7,10000,10000,10000,8,10000,10000}, {10000,9,10000,10000,10000,4,10000}, {10000,10000,8,10000,10000,5,4}, {10000,10000,10000,4,5,10000,6}, {2,3,10000,10000,4,6,10000} }; // 建立MGraph對象 MGraph graph = new MGraph(verxs); // 建立最小樹 MinTree minTree = new MinTree(); minTree.createGraph(graph, verxs, data, weight); // 輸出 minTree.showGraph(graph); // 測試普利姆算法 minTree.prim(graph, 0); } }
7.克魯斯卡爾算法數組
/** * @desc 克魯斯卡爾算法 * 案例:公交車問題 * 1. 某城市新增7個站點,A,B,C,D,E,F,G,如今須要修路7個站點連通 * 2. 各個站點距離用連線表示,好比A-B距離12千米 * 3. 問:如何修路保證各個站點都能連通,而且總的修建公路總里程最短 * @Author xw * @Date 2019/10/8 */ public class KruskalCase { private static final int INF = Integer.MAX_VALUE; private char[] vertexs; private int[][] matrix; private int edgeNums; // 邊的數量 public KruskalCase(char[] vertexs,int[][] matrix ) { this.vertexs = vertexs; this.matrix = matrix; // 統計邊 for (int i = 0; i < vertexs.length; i++) { for (int j = i + 1; j < vertexs.length; j++) { // 每次少一條邊,因此是i+1 if (this.matrix[i][j] != INF) { edgeNums++; } } } } public static void main(String[] args) { char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; int[][] matrix = { /*A*//*B*//*C*//*D*//*E*//*F*//*G*/ /*A*/{ 0, 12, INF, INF, INF, 16, 14 }, /*B*/{ 12, 0, 10, INF, INF, 7, INF}, /*C*/{ INF, 10, 0, 3, 5, 6, INF }, /*D*/{ INF, INF, 3, 0, 4, INF, INF }, /*E*/{ INF, INF, 5, 4, 0, 2, 8 }, /*F*/{ 16, 7, 6, INF, 2, 0, 9 }, /*G*/{ 14, INF, INF, INF, 8, 9, 0 } }; // 建立KruskalCase對象實例 KruskalCase kruskalCase = new KruskalCase(vertexs, matrix); // kruskalCase.print(); kruskalCase.kruskal(); } }
8.迪傑斯特拉算法ide
/** * @desc 迪傑斯特拉算法 * 案例:最短路徑問題 * 1. 戰爭時期,勝利鄉有7個村莊(A,B,C,D,E,F,G),如今有6個郵差,從G點出發,須要分別把郵件分別送到A,B,C,D,E,F 六個村莊 * 2. 各個村莊的距離用邊線表示(權),好比A-B距離5千米 * 3. 問:如何計算最短距離 * * @Author xw * @Date 2019/10/8 */ public class DijkstraAlgorithm { public static void main(String[] args) { char[] vertex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; int[][] matrix = new int[vertex.length][vertex.length]; final int N = 65535; matrix[0] = new int[]{N,5,7,N,N,N,2}; matrix[1] = new int[]{5,N,N,9,N,N,3}; matrix[2] = new int[]{7,N,N,N,8,N,N}; matrix[3] = new int[]{N,9,N,N,N,4,N}; matrix[4] = new int[]{N,N,8,N,N,5,4}; matrix[5] = new int[]{N,N,N,4,5,N,6}; matrix[6] = new int[]{2,3,N,N,4,6,N}; // 建立Graph對象 Graph graph = new Graph(vertex, matrix); graph.showGraph(); // 測試迪傑斯特拉算法 graph.dsj(6); // G graph.showDijkstra(); } }
9.弗洛伊德算法測試
/** * @desc 弗洛伊德算法 * @Author xw * @Date 2019/10/8 */ public class FloydAlgorithm { public static void main(String[] args) { char[] vertex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; int[][] matrix = new int[vertex.length][vertex.length]; final int N = 65535; matrix[0] = new int[]{0, 5, 7, N, N, N, 2}; matrix[1] = new int[]{5, 0, N, 9, N, N, 3}; matrix[2] = new int[]{7, N, 0, N, 8, N, N}; matrix[3] = new int[]{N, 9, N, 0, N, 4, N}; matrix[4] = new int[]{N, N, 8, N, 0, 5, 4}; matrix[5] = new int[]{N, N, N, 4, 5, 0, 6}; matrix[6] = new int[]{2, 3, N, N, 4, 6, 0}; FloydGraph graph = new FloydGraph(vertex.length, matrix, vertex); graph.floyd(); graph.show(); } }
10.馬踏棋盤算法this
/** * @desc 馬踏棋盤算法 * @Author xw * @Date 2019/10/8 */ public class HorseChessboard { private static int X; // 棋盤的列數 private static int Y; // 棋盤的行數 //建立一個數組,標記棋盤的各個位置是否被訪問過 private static boolean visited[]; //使用一個屬性,標記是否棋盤的全部位置都被訪問 private static boolean finished; // 若是爲true,表示成功 public static void main(String[] args) { System.out.println("騎士周遊算法,開始運行~~"); //測試騎士周遊算法是否正確 X = 8; Y = 8; int row = 1; //馬兒初始位置的行,從1開始編號 int column = 1; //馬兒初始位置的列,從1開始編號 //建立棋盤 int[][] chessboard = new int[X][Y]; visited = new boolean[X * Y];//初始值都是false //測試一下耗時 long start = System.currentTimeMillis(); traversalChessboard(chessboard, row - 1, column - 1, 1); long end = System.currentTimeMillis(); System.out.println("共耗時: " + (end - start) + " 毫秒"); //輸出棋盤的最後狀況 for(int[] rows : chessboard) { for(int step: rows) { System.out.print(step + "\t"); } System.out.println(); } } }
gitee地址:https://gitee.com/linestyle007/jucdemo2
博客地址:https://linestyle007.gitee.io/
github地址:https://github.com/line007/jucdemo2