├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── algorithm │ │ └── xlb │ │ └── algorithm │ │ ├── AlgorithmApplication.java │ │ ├── bitset │ │ └── BitSetTest.java │ │ ├── cbo │ │ ├── DFSGreedy.java │ │ ├── Greedy.java │ │ ├── README.md │ │ └── VolcanoPlaner.java │ │ ├── dag │ │ ├── DAG.java │ │ ├── LinkedHashSetMultimap.java │ │ └── README.md │ │ ├── graph │ │ ├── ASearch.java │ │ ├── Dijkstra.java │ │ ├── Kruskal.java │ │ └── Prim.java │ │ └── leetcode │ │ └── regex │ │ └── RegexSolution.java └── resources │ └── application.properties └── test └── java └── com └── algorithm └── xlb └── algorithm ├── AlgorithmApplicationTests.java ├── DAGChainTest.java ├── DAGExecTest.java └── DAGTest.java /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | https://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.io.FileOutputStream; 23 | import java.io.IOException; 24 | import java.net.URL; 25 | import java.nio.channels.Channels; 26 | import java.nio.channels.ReadableByteChannel; 27 | import java.util.Properties; 28 | 29 | public class MavenWrapperDownloader { 30 | 31 | /** 32 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 33 | */ 34 | private static final String DEFAULT_DOWNLOAD_URL = 35 | "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar"; 36 | 37 | /** 38 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 39 | * use instead of the default one. 40 | */ 41 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 42 | ".mvn/wrapper/maven-wrapper.properties"; 43 | 44 | /** 45 | * Path where the maven-wrapper.jar will be saved to. 46 | */ 47 | private static final String MAVEN_WRAPPER_JAR_PATH = 48 | ".mvn/wrapper/maven-wrapper.jar"; 49 | 50 | /** 51 | * Name of the property which should be used to override the default download url for the wrapper. 52 | */ 53 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 54 | 55 | public static void main(String args[]) { 56 | System.out.println("- Downloader started"); 57 | File baseDirectory = new File(args[0]); 58 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 59 | 60 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 61 | // wrapperUrl parameter. 62 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 63 | String url = DEFAULT_DOWNLOAD_URL; 64 | if(mavenWrapperPropertyFile.exists()) { 65 | FileInputStream mavenWrapperPropertyFileInputStream = null; 66 | try { 67 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 68 | Properties mavenWrapperProperties = new Properties(); 69 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 70 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 71 | } catch (IOException e) { 72 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 73 | } finally { 74 | try { 75 | if(mavenWrapperPropertyFileInputStream != null) { 76 | mavenWrapperPropertyFileInputStream.close(); 77 | } 78 | } catch (IOException e) { 79 | // Ignore ... 80 | } 81 | } 82 | } 83 | System.out.println("- Downloading from: : " + url); 84 | 85 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 86 | if(!outputFile.getParentFile().exists()) { 87 | if(!outputFile.getParentFile().mkdirs()) { 88 | System.out.println( 89 | "- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 90 | } 91 | } 92 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 93 | try { 94 | downloadFileFromURL(url, outputFile); 95 | System.out.println("Done"); 96 | System.exit(0); 97 | } catch (Throwable e) { 98 | System.out.println("- Error downloading"); 99 | e.printStackTrace(); 100 | System.exit(1); 101 | } 102 | } 103 | 104 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 105 | URL website = new URL(urlString); 106 | ReadableByteChannel rbc; 107 | rbc = Channels.newChannel(website.openStream()); 108 | FileOutputStream fos = new FileOutputStream(destination); 109 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 110 | fos.close(); 111 | rbc.close(); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smartxing/algorithm/a44d4b809f76b0c2046bc8e88ad4212707ba60b7/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### [Task 任务调度算法 DAG 实现](https://github.com/smartxing/algorithm/blob/master/src/main/java/com/algorithm/xlb/algorithm/dag/README.md) 2 | ```text 3 | stage的划分,以及算子的优化 4 | ``` 5 | 6 | ### [贪心算法](https://github.com/smartxing/algorithm/blob/master/src/main/java/com/algorithm/xlb/algorithm/cbo/README.md) 7 | ```text 8 | calcite cbo其实就是贪心的,配合一些剪枝的技巧 ,并不是全局最优解 9 | 注意:calcite的代价优化都是需要自己实现过的, 10 | 1 实现统计 比如表的count 11 | 2 实现算子的代价,默认是按行数实现的 12 | ``` 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.1.7.RELEASE 9 | 10 | 11 | com.algorithm.xlb 12 | algorithm 13 | 0.0.1-SNAPSHOT 14 | algorithm 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | 34 | 35 | com.google.guava 36 | guava 37 | 28.1-jre 38 | 39 | 40 | 41 | commons-io 42 | commons-io 43 | 2.6 44 | 45 | 46 | 47 | org.apache.commons 48 | commons-lang3 49 | 3.9 50 | 51 | 52 | 53 | 54 | org.apache.commons 55 | commons-collections4 56 | 4.4 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/AlgorithmApplication.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AlgorithmApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AlgorithmApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/bitset/BitSetTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.bitset; 2 | 3 | import com.google.common.collect.Maps; 4 | 5 | import java.util.Arrays; 6 | import java.util.BitSet; 7 | import java.util.HashMap; 8 | 9 | /** 10 | * 11 | * @author xingliangbo 12 | * @version $Id: v 0.1 2019-09-10 11:13 xingliangbo Exp $ 13 | */ 14 | public class BitSetTest { 15 | 16 | public static void main(String[] args) { 17 | 18 | BitSet bitSet = new BitSet(6); 19 | // bitSet.set(1, false); 20 | bitSet.set(2, true); 21 | bitSet.set(3, true); 22 | 23 | System.out.println(bitSet.cardinality()); 24 | BitSet bitSet2 = new BitSet(6); 25 | bitSet2.set(1, true); 26 | bitSet2.set(2, true); 27 | // bitSet.and(bitSet2); 28 | // System.out.println("xx:" + bitSet); 29 | 30 | // bitSet.or(bitSet2); 31 | // System.out.println("xx:" + bitSet); 32 | //同值取0 异值取1 33 | // bitSet.xor(bitSet2); 34 | // System.out.println("xx:" + bitSet); 35 | //相同的取0 36 | bitSet.andNot(bitSet2); 37 | System.out.println("xx:" + bitSet); 38 | 39 | System.out.println(Integer.toBinaryString(-1)); 40 | int x = 0x7FFFFFFF; 41 | System.out.println(Integer.toBinaryString(x)); 42 | 43 | 44 | System.out.println(-1 & x); 45 | System.out.println(Integer.MAX_VALUE); 46 | System.out.println(Integer.MIN_VALUE); 47 | System.out.println(Integer.toBinaryString(-2147483648)); 48 | System.out.println("1111111111111111111111111111111".length()); 49 | HashMap objectObjectHashMap = Maps.newHashMap(); 50 | objectObjectHashMap.hashCode(); 51 | //111 => 11 52 | System.out.println("7 >> 1 = " + (7 >> 1)); 53 | //相当于除以2 54 | System.out.println("8 >> 1 = " + (8 >> 1)); 55 | //111 => 1110 + 7 +2 56 | System.out.println("7 << 1 = " + (7 << 1)); 57 | System.out.println("8 << 1 = " + (8 << 1)); 58 | //1000000...1 => 1000000...10 59 | System.out.println("-1 << 1 = " + (-1 << 1)); 60 | System.out.println("-1 >> 1 = " + (-1 >> 1)); 61 | //1000000...1 => 01000000...0 符号位也会移动 62 | System.out.println("-1 >> 1 = " + (-1 >>> 1) + " 2^31 " + Integer.MAX_VALUE); 63 | 64 | // System.out.println(bitSet); 65 | // System.out.println(Arrays.toString(bitSet.toByteArray())); 66 | // System.out.println(bitSet.get(3)); 67 | // 68 | // System.out.println((-1 & 0x7FFFFFFF)); 69 | // 70 | // System.out.println(Integer.toBinaryString(-1)); 71 | // System.out.println(Integer.toBinaryString(1)); 72 | // int x = 0x7FFFFFFF; 73 | // System.out.println(x); 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/cbo/DFSGreedy.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.cbo; 2 | 3 | import com.google.common.base.Joiner; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | import java.util.Stack; 8 | 9 | /** 10 | * 贪心算法: 每次选取最大的 ,寻找相对最优解 11 | * DFS算法实现 12 | * 13 | * 可以用A*搜索算法是实现 14 | * f = g + h 15 | * g => 其实点到目标点的代价 16 | * h => 目标点到终点的代价 17 | * 领f = Max() 寻找最大的价值 18 | * 19 | * A*其实是基于BFS的 如下是基于DFS的 20 | * 21 | * @author xingliangbo 22 | * @version $Id: v 0.1 2019-09-04 20:12 xingliangbo Exp $ 23 | */ 24 | public class DFSGreedy { 25 | 26 | 27 | /** 28 | * 如果你要寻找到全局最优解 ,其实需要回朔所有的子问题解 选出最优的解 29 | * 相对最优解实现只需要DFS每次按照最大的选取: 30 | * 构造二维树组 31 | * eg x1 代表解的第一位 ,x2第二位 32 | * x1 x2 x2 x4 .... 33 | * 10 10 34 | * 9 9 35 | * 7 7 36 | * 4 4 37 | * 2 2 38 | */ 39 | public static void main(String[] args) { 40 | DFSGreedy greedy = new DFSGreedy(); 41 | Integer[] coins = new Integer[]{2, 4, 6, 8}; 42 | Integer target = 17; 43 | greedy.findMaxResult(coins,target); 44 | System.out.println("--------------------------"); 45 | coins = new Integer[]{2 ,4 ,7 ,9 ,10}; 46 | target = 16; 47 | greedy.findMaxResult(coins,target); 48 | System.out.println("--------------------------"); 49 | coins = new Integer[]{2 ,4 ,7 ,9 ,10}; 50 | target = 15; 51 | greedy.findMaxResult(coins,target); 52 | coins = new Integer[]{2 ,4 ,7 ,9 ,10}; 53 | target = 17; 54 | greedy.findMaxResult(coins,target); 55 | 56 | 57 | } 58 | 59 | /** 60 | * DFS相对最优解 61 | */ 62 | public void findMaxResult(Integer[] coins,Integer target) { 63 | Arrays.sort(coins, Collections.reverseOrder()); 64 | int weight = target / coins[coins.length - 1] + 1; 65 | int hight = coins.length; 66 | int[][] path = new int[weight][hight];//初始化值都是0 67 | Stack stack = new Stack(); 68 | //初始化素组 69 | findByDfs(stack, path, coins, target, 0); 70 | StringBuilder sb = new StringBuilder(); 71 | sb.append("coins ").append("("+Joiner.on(",").join(coins)+")").append(" target: " + target); 72 | if(stack.isEmpty()){ 73 | sb.append(" 无解"); 74 | System.out.println(sb.toString()); 75 | }else { 76 | sb.append(" 本次相对最优解:"); 77 | Pair[] p = new Pair[stack.size()]; 78 | stack.toArray(p); 79 | for (int i = 0; i < p.length; i++) { 80 | sb.append(p[i].v +" "); 81 | } 82 | // for (int i = p.length-1; i >= 0; i--) { 83 | // sb.append(p[i].v +" "); 84 | // } 85 | System.out.println(sb.toString()); 86 | } 87 | 88 | 89 | } 90 | 91 | 92 | public void findByDfs(Stack stack, int[][] path, Integer[] coins, Integer target, int x) { 93 | 94 | for (int y = 0; y < path[x].length; y++) { 95 | //找到第一个 为用过的数字 且 比 目标数字要小 96 | //System.out.println("target " + target + " 坐标 ( " + x + " , " + y + ") v : " + coins[y]); 97 | if (path[x][y] == 0 && target >= coins[y]) { 98 | target = target - coins[y]; 99 | stack.push(new Pair(x, y, coins[y])); 100 | //System.out.println("选择了 " + coins[y] + " target " + target + " (" + x + " , " + y + ")"); 101 | path[x][y] = 1;//标记已使用 102 | if (target != 0) { 103 | findByDfs(stack, path, coins, target, x + 1); 104 | } else { 105 | //System.out.println("找到相对最优化解"); 106 | } 107 | return; 108 | } else if (y == path[x].length - 1) {//当前最后一个了 还是没找到 109 | //回到上一步 110 | if(checkIsNotResult(path,x-1)){//发现上一步都已经全部用过了 任务已经无解了 111 | stack.clear(); 112 | return; 113 | } 114 | for (int i = 0; i < y; i++) { 115 | path[x][i]=0; //设置未使用过 116 | } 117 | 118 | Pair point = stack.pop(); 119 | //System.out.println("pop " + point.v + "target " + target + " (" + point.x + " , " + point.y + ")"); 120 | target = target + point.v; 121 | findByDfs(stack, path, coins, target, x - 1); 122 | } 123 | 124 | 125 | } 126 | } 127 | 128 | public boolean checkIsNotResult(int[][] path, int x) { 129 | for (int i = 0; i < path[x].length; i++) { 130 | if (path[x][i] == 0) { 131 | return false; 132 | } 133 | } 134 | return true; 135 | } 136 | 137 | 138 | public class Pair { 139 | int x; 140 | int y; 141 | int v; 142 | 143 | public Pair(final int x, final int y, final int v) { 144 | this.x = x; 145 | this.y = y; 146 | this.v = v; 147 | } 148 | 149 | } 150 | 151 | 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/cbo/Greedy.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.cbo; 2 | 3 | import com.google.common.collect.Lists; 4 | 5 | import java.util.Arrays; 6 | import java.util.Collections; 7 | import java.util.List; 8 | 9 | /** 10 | * 贪心算法: 每次选取最大的 11 | * 12 | * 问题: 举个列子 比如有 1 5 10 20 硬币 如果需要凑到37块怎么凑 而且硬币数最少 13 | * 14 | * 1 第一步剪支 选择最优的 即选择最大的 20 15 | * 2 选了20 还差17 在选最大的 10 16 | * 3 还差7块 ,在选择最大的5 17 | * 4 还差2块 ,只能选择1 2 18 | * 所以贪心算法最终结果是 20 10 5 1 1 19 | * 20 | * 不考虑 每次选择max 找不到解 ,如何考虑找不到解需要DFS 搜索 详见 DFSGreedy.java 21 | * @author xingliangbo 22 | * @version $Id: v 0.1 2019-09-04 20:12 xingliangbo Exp $ 23 | */ 24 | public class Greedy { 25 | 26 | 27 | public List find() { 28 | //定义硬币 29 | Integer[] coins = new Integer[]{1, 2, 5, 10, 20, 50, 100}; 30 | //目标 需要38 31 | Integer target = 625; 32 | Arrays.sort(coins, Collections.reverseOrder()); 33 | 34 | return findMax(coins, target); 35 | 36 | } 37 | 38 | public List findMax(Integer[] coins, Integer target) { 39 | 40 | List result = Lists.newArrayList(); 41 | for (int j = 0; j < coins.length; j++) { 42 | if (coins[j] <= target) { //每次寻找最大的max 43 | Integer count = target / coins[j]; 44 | target = target % coins[j]; 45 | for (int k = 0; k < count; k++) { 46 | result.add(coins[j]); 47 | } 48 | } 49 | } 50 | return result; 51 | 52 | } 53 | 54 | 55 | public static void main(String[] args) { 56 | Greedy greedy = new Greedy(); 57 | System.out.println(greedy.find()); 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/cbo/README.md: -------------------------------------------------------------------------------- 1 | #### 贪心算法 & 动态规划 2 | ```text 3 | 贪心算法: 4 | 每个阶段的最优状态都是由上一个阶段的最优状态得到的->贪心 5 | 6 | 举个列子 比如有 1 5 10 20 硬币 如果需要凑到37块怎么凑 而且硬币数最少 7 | 8 | 1 第一步剪支 选择最优的 即选择最大的 20 9 | 2 选了20 还差17 在选最大的 10 10 | 3 还差7块 ,在选择最大的5 11 | 4 还差2块 ,只能选择1 1 12 | 13 | 结果是 20 10 5 1 1 14 | eg:MinCount.java 15 | 16 | 17 | 18 | 换个币比如 19 | 2 ,4 ,7 ,9 ,10 要凑成16 20 | 按照贪心算法 21 | 10 + 4 + 2 很显然需要3个 22 | 而 最优的可能直接是 9 + 7 2个了 23 | 显然 贪心算法不一定找的是最优解,只是找的相对最优解 24 | calcite cbo其实就是贪心的,配合一些剪枝的技巧 ,并不是全局最优解 25 | 注意:calcite的代价优化都是需要自己实现过的, 26 | 1 实现统计 比如表的count 27 | 2 实现算子的代价,默认是按行数实现的 28 | 29 | 算法实现: DFS => 寻找到相对最优的解 先自己想想? 30 | 详见: 31 | 32 | 如果你要寻找到全局最优解 ,其实需要回朔所有的子问题解 选出最优的解,所以搜索的路径会很大 33 | 相对最优解实现只需要DFS每次按照最大的选取: 34 | eg x1 代表解的第一位 ,x2第二位 35 | x1 x2 x2 x4 .... 36 | 10 10 37 | 9 9 38 | 7 7 39 | 4 4 40 | 2 2 41 | 42 | 这样就是一个2维素组了 这样就很简单了 DFS 43 | 实现 DFSGreedy.java 44 | 45 | 46 | 47 | 如果实现全局最优解了? 后续补充 48 | 基于DFS 49 | 基于BFS 50 | 51 | ``` 52 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/cbo/VolcanoPlaner.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.cbo; 2 | 3 | /** 4 | * 5 | * cbo 代价优化算法 6 | * @author xingliangbo 7 | * @version $Id: v 0.1 2019-09-04 10:12 xingliangbo Exp $ 8 | */ 9 | public class VolcanoPlaner { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/dag/DAG.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.dag; 2 | 3 | import org.apache.commons.collections4.CollectionUtils; 4 | 5 | import com.google.common.collect.Lists; 6 | import com.google.common.collect.Sets; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Collections; 10 | import java.util.Iterator; 11 | import java.util.LinkedHashSet; 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.Set; 16 | import java.util.concurrent.atomic.AtomicInteger; 17 | import java.util.function.Consumer; 18 | import java.util.stream.Collectors; 19 | 20 | /** 21 | * 22 | * @author xingliangbo 23 | * @version $Id: v 0.1 2019-09-03 15:21 xingliangbo Exp $ 24 | */ 25 | public final class DAG { 26 | 27 | 28 | private final LinkedHashSetMultimap outDegree; 29 | private final LinkedHashSetMultimap inDegree; 30 | 31 | public DAG(final LinkedHashSetMultimap outDegree, final LinkedHashSetMultimap inDegree) { 32 | this.outDegree = outDegree; 33 | this.inDegree = inDegree; 34 | } 35 | 36 | /** 37 | * 拓扑排序检测 是否有环 38 | */ 39 | public boolean isCircularity() { 40 | Map inDegree = getObjectAtomicIntegerMap(); 41 | //入度为0的节点 42 | Set sources = getSources(); 43 | LinkedList queue = new LinkedList(); 44 | queue.addAll(sources); 45 | while (!queue.isEmpty()) { 46 | Object o = queue.removeFirst(); 47 | outDegree.get(o) 48 | .forEach(so -> { 49 | if (inDegree.get(so).decrementAndGet() == 0) { 50 | queue.add(so); 51 | } 52 | }); 53 | } 54 | return inDegree.values().stream().filter(x -> x.intValue() > 0).count() > 0; 55 | } 56 | 57 | 58 | private void chain_(Set sources, final LinkedHashSetMultimap foutChain, final LinkedHashSetMultimap finChain) { 59 | sources.forEach(sourceNode -> { 60 | 61 | ArrayList maxStage = Lists.newArrayList(); 62 | findMaxStage(sourceNode, maxStage); 63 | if (maxStage.size() > 1) { //存在需要合并的stage 64 | addVertex(foutChain, finChain, maxStage);//添加一个新节点 65 | Object o = maxStage.get(maxStage.size() - 1); //最后一个节点 66 | reChain_(foutChain, finChain, maxStage, o); 67 | } 68 | if (maxStage.size() == 1) { 69 | //不存在需要合并的stage 70 | addVertex(foutChain, finChain, sourceNode);//添加一个新节点 71 | Set subNodes = outDegree.get(sourceNode); 72 | addSubNodeage(foutChain, finChain, sourceNode, subNodes); 73 | } 74 | }); 75 | } 76 | 77 | private void addSubNodeage(final LinkedHashSetMultimap foutChain, final LinkedHashSetMultimap finChain, 78 | final Object sourceNode, final Set subNodes) { 79 | if (CollectionUtils.isNotEmpty(subNodes)) { //多个出度 80 | subNodes.forEach(snode -> { 81 | addEdge(foutChain, finChain, sourceNode, snode); 82 | }); 83 | chain_(subNodes, foutChain, finChain); 84 | } else { //最后一个节点了 把节点添加进去 即可 85 | addVertex(foutChain, finChain, sourceNode); 86 | } 87 | } 88 | 89 | private void reChain_(final LinkedHashSetMultimap foutChain, final LinkedHashSetMultimap finChain, 90 | ArrayList maxStage, Object o) { 91 | Set set = outDegree.get(o); //最后一个节点的子节点 92 | Object header = maxStage.get(0); //第一个stage节点 93 | //处理父节点 94 | Set parentSet = finChain.get(header); 95 | //下面操作就是相当于 链表中添加一个节点 A -> B ==> A -> C -> B 先删掉老的A->B 添加新的A->C 在添加新的C->B 96 | if (CollectionUtils.isNotEmpty(parentSet)) { 97 | parentSet.forEach(h -> { 98 | //删除老的边 99 | removeEage(foutChain, finChain, h, header); 100 | //添加新的表 101 | addEdge(foutChain, finChain, h, maxStage); 102 | }); 103 | } 104 | addSubNodeage(foutChain, finChain, maxStage, set); 105 | } 106 | 107 | /** 108 | * 寻找最大的stage 109 | */ 110 | public void findMaxStage(Object o, List maxStage) { 111 | maxStage.add(o); 112 | Set setOut = outDegree.get(o); 113 | if (setOut.size() == 1) { 114 | Object subNode = setOut.iterator().next(); 115 | if (inDegree.get(subNode).size() == 1) { 116 | findMaxStage(subNode, maxStage); 117 | } 118 | } 119 | } 120 | 121 | 122 | /** 123 | * stage 划分 124 | * eg: 125 | * 126 | * -> B -> C -> E -> F -> B -> C,E,F 127 | * A / => A / A -> B -> C -> D == A,B,C -> D 128 | * -> D -> D \E \ E 129 | */ 130 | public DAG chain() { 131 | Set sources = getSources(); 132 | final LinkedHashSetMultimap outDegreeChain = new LinkedHashSetMultimap(); 133 | final LinkedHashSetMultimap inDegreeChain = new LinkedHashSetMultimap(); 134 | chain_(sources, outDegreeChain, inDegreeChain); 135 | return new DAG(outDegreeChain, inDegreeChain); 136 | } 137 | 138 | 139 | public void execute(Consumer consumer) { 140 | Map inDegree = getObjectAtomicIntegerMap(); 141 | //入度为0的节点 142 | Set sources = getSources(); 143 | execute_(sources, inDegree, consumer); 144 | } 145 | 146 | private Map getObjectAtomicIntegerMap() { 147 | Set set = inDegree.keySet(); 148 | //入度表 149 | return set.stream().collect(Collectors 150 | .toMap(k -> k, k -> new AtomicInteger(this.inDegree.get(k).size()))); 151 | } 152 | 153 | 154 | public void execute_(Set set, Map inDegree, Consumer consumer) { 155 | exec(set, consumer); 156 | Set nextSet = Sets.newLinkedHashSet(); 157 | set.forEach(o -> { 158 | outDegree.get(o).forEach(so -> { 159 | if (inDegree.get(so).decrementAndGet() == 0) { 160 | nextSet.add(so); 161 | } 162 | }); 163 | }); 164 | if (CollectionUtils.isNotEmpty(nextSet)) { 165 | execute_(nextSet, inDegree, consumer); 166 | } 167 | } 168 | 169 | 170 | private void exec(Set set, Consumer consumer) { 171 | consumer.accept(set); 172 | } 173 | 174 | 175 | public boolean addEdge(Object origin, Object target) { 176 | if (hasPath(target, origin)) { 177 | return false; 178 | } 179 | addEdgeWithNoCheck(origin, target); 180 | return true; 181 | } 182 | 183 | public boolean addEdgeWithNoCheck(Object origin, Object target) { 184 | outDegree.put(origin, target); 185 | outDegree.put(target, null); 186 | inDegree.put(target, origin); 187 | inDegree.put(origin, null); 188 | return true; 189 | } 190 | 191 | 192 | private boolean addEdge(LinkedHashSetMultimap fOut, LinkedHashSetMultimap fIn, Object origin, Object target) { 193 | fOut.put(origin, target); 194 | fIn.put(target, origin); 195 | return true; 196 | } 197 | 198 | public boolean removeEage(LinkedHashSetMultimap fOut, LinkedHashSetMultimap fIn, Object origin, Object target) { 199 | fOut.remove(origin, target); 200 | if (CollectionUtils.isEmpty(fOut.get(origin))) { 201 | fOut.removeAll(origin); 202 | } 203 | fIn.remove(target, origin); 204 | if (CollectionUtils.isEmpty(fIn.get(target))) { 205 | fIn.removeAll(target); 206 | } 207 | return true; 208 | } 209 | 210 | 211 | public void addVertex(Object vertex) { 212 | outDegree.put(vertex, null); 213 | inDegree.put(vertex, null); 214 | } 215 | 216 | private void addVertex(LinkedHashSetMultimap fOut, LinkedHashSetMultimap fIn, Object vertex) { 217 | fOut.put(vertex, null); 218 | fIn.put(vertex, null); 219 | } 220 | 221 | 222 | public void removeVertex(Object vertex) { 223 | Set targets = outDegree.removeAll(vertex); 224 | for (Iterator it = targets.iterator(); it.hasNext(); ) { 225 | inDegree.remove(it.next(), vertex); 226 | } 227 | Set origins = inDegree.removeAll(vertex); 228 | for (Iterator it = origins.iterator(); it.hasNext(); ) { 229 | outDegree.remove(it.next(), vertex); 230 | } 231 | } 232 | 233 | 234 | public Set getSources() { 235 | return computeZeroEdgeVertices(inDegree); 236 | } 237 | 238 | 239 | public Set getSinks() { 240 | return computeZeroEdgeVertices(outDegree); 241 | } 242 | 243 | private Set computeZeroEdgeVertices(LinkedHashSetMultimap map) { 244 | Set candidates = map.keySet(); 245 | Set roots = new LinkedHashSet(candidates.size()); 246 | for (Iterator it = candidates.iterator(); it.hasNext(); ) { 247 | Object candidate = it.next(); 248 | if (map.get(candidate).isEmpty()) { 249 | roots.add(candidate); 250 | } 251 | } 252 | return roots; 253 | } 254 | 255 | public Set getChildren(Object vertex) { 256 | return Collections.unmodifiableSet(outDegree.get(vertex)); 257 | } 258 | 259 | private boolean hasPath(Object start, Object end) { 260 | if (start == end) { 261 | return true; 262 | } 263 | Set children = outDegree.get(start); 264 | for (Iterator it = children.iterator(); it.hasNext(); ) { 265 | if (hasPath(it.next(), end)) { 266 | return true; 267 | } 268 | } 269 | return false; 270 | } 271 | 272 | public static DAG create() { 273 | return new DAG(new LinkedHashSetMultimap(), new LinkedHashSetMultimap()); 274 | } 275 | 276 | 277 | public String toString() { 278 | return "OutDegree: " + outDegree.toString() + " InDegree: " + inDegree.toString(); 279 | } 280 | } -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/dag/LinkedHashSetMultimap.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.dag; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.google.common.collect.Sets; 5 | 6 | import java.util.Collections; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | /** 11 | * 12 | * @author xingliangbo 13 | * @version $Id: v 0.1 2019-09-03 15:21 xingliangbo Exp $ 14 | */ 15 | public class LinkedHashSetMultimap { 16 | 17 | 18 | private final Map map = Maps.newLinkedHashMap(); 19 | 20 | 21 | public void put(Object key, Object val) { 22 | Set values = (Set) map.get(key); 23 | if (values == null) { 24 | values = Sets.newLinkedHashSet(); 25 | map.put(key, values); 26 | } 27 | if (val != null) { 28 | values.add(val); 29 | } 30 | } 31 | 32 | 33 | public Set get(Object key) { 34 | Set values = (Set) map.get(key); 35 | return values == null ? Collections.EMPTY_SET : values; 36 | } 37 | 38 | public Set keySet() { 39 | return map.keySet(); 40 | } 41 | 42 | 43 | public Set removeAll(Object key) { 44 | Set values = (Set) map.remove(key); 45 | return values == null ? Collections.EMPTY_SET : values; 46 | } 47 | 48 | 49 | public void remove(Object key, Object val) { 50 | Set values = (Set) map.get(key); 51 | if (values != null) { 52 | values.remove(val); 53 | } 54 | } 55 | 56 | 57 | public String toString() { 58 | return map.toString(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/dag/README.md: -------------------------------------------------------------------------------- 1 | ### Task 任务调度算法 DAG 实现 2 | 3 | ##### 1 有向图的构建 4 | ```java 5 | DAG dag = new DAG(); 6 | dag.addVertex("A"); 7 | dag.addVertex("B"); 8 | dag.addVertex("C"); 9 | dag.addVertex("D"); 10 | dag.addEdge("A", "B"); 11 | dag.addEdge("A", "C"); 12 | System.out.println(dag); 13 | 14 | ``` 15 | ##### 2 拓扑排序检测图中是否有环 16 | ```java 17 | public boolean isCircularity() { 18 | Set set = inDegree.keySet(); 19 | //入度表 20 | Map inDegree = set.stream().collect(Collectors 21 | .toMap(k -> k, k -> new AtomicInteger(this.inDegree.get(k).size()))); 22 | //入度为0的节点 23 | Set sources = getSources(); 24 | LinkedList queue = new LinkedList(); 25 | queue.addAll(sources); 26 | while (!queue.isEmpty()) { 27 | Object o = queue.removeFirst(); 28 | outDegree.get(o) 29 | .forEach(so -> { 30 | if (inDegree.get(so).decrementAndGet() == 0) { 31 | queue.add(so); 32 | } 33 | }); 34 | } 35 | return inDegree.values().stream().filter(x -> x.intValue() > 0).count() > 0; 36 | } 37 | ``` 38 | 39 | ##### 4 stage优化 40 | ```text 41 | eg 42 | 如果任务存在如下的关系 , task1 执行完后执行 task2 ,task2 执行完后执行task3 ... 43 | Task1 -> Task2 -> Task3 -> Task4 44 | 这些task 本来就要串行执行的 可以把这些task 打包在一块 减少线程上下文的切换 45 | 46 | eg : 复杂一点的DAG: 47 | /** 48 | * H 49 | * \ 50 | * G 51 | * \ 52 | * A -> B 53 | * \ 54 | * C- D -E - F-> J 55 | * 56 | * 57 | * 58 | * 优化后得 ==> 59 | * 60 | * (H,G) 61 | * \ 62 | * A -> B 63 | * \ 64 | * (C,D,E) - (F,J) 65 | * 66 | */ 67 | 68 | 详见chain方法: 关键代码如下 69 | 70 | private void chain_(Set sources, final LinkedHashSetMultimap foutChain, final LinkedHashSetMultimap finChain) { 71 | sources.forEach(sourceNode -> { 72 | 73 | ArrayList maxStage = Lists.newArrayList(); 74 | findMaxStage(sourceNode, maxStage); 75 | if (maxStage.size() > 1) { //存在需要合并的stage 76 | addVertex(foutChain, finChain, maxStage);//添加一个新节点 77 | Object o = maxStage.get(maxStage.size() - 1); //最后一个节点 78 | reChain_(foutChain, finChain, maxStage, o); 79 | } 80 | if (maxStage.size() == 1) { 81 | //不存在需要合并的stage 82 | addVertex(foutChain, finChain, sourceNode);//添加一个新节点 83 | Set subNodes = outDegree.get(sourceNode); 84 | addSubNodeage(foutChain, finChain, sourceNode, subNodes); 85 | } 86 | }); 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 4 测试DAG 执行 94 | 95 | 测试程序: 详见 DAGExecTest 96 | 1 新建一个task 只打印一句话 97 | public static class Task implements Runnable { 98 | 99 | private String taskName; 100 | 101 | public Task(final String taskName) { 102 | this.taskName = taskName; 103 | } 104 | 105 | @Override public void run() { 106 | try { 107 | Thread.sleep(2000); 108 | } catch (InterruptedException e) { 109 | e.printStackTrace(); 110 | } 111 | System.out.println("i am running my name is " + taskName + " finish ThreadID: " + Thread.currentThread().getId()); 112 | } 113 | 114 | public String getTaskName() { 115 | return taskName; 116 | } 117 | 118 | @Override public String toString() { 119 | return taskName; 120 | } 121 | } 122 | 2 构建DAG 123 | DAG dag = DAG.create(); 124 | Task a = new Task("a"); 125 | Task b = new Task("b"); 126 | Task c = new Task("c"); 127 | Task d = new Task("d"); 128 | Task e = new Task("e"); 129 | Task f = new Task("f"); 130 | Task g = new Task("g"); 131 | Task h = new Task("h"); 132 | Task j = new Task("j"); 133 | dag.addVertex(a); 134 | dag.addVertex(b); 135 | dag.addVertex(c); 136 | dag.addVertex(d); 137 | dag.addVertex(e); 138 | dag.addVertex(f); 139 | dag.addVertex(g); 140 | dag.addVertex(h); 141 | dag.addVertex(j); 142 | dag.addEdge(h, g); 143 | dag.addEdge(g, b); 144 | dag.addEdge(a, b); 145 | dag.addEdge(b, f); 146 | dag.addEdge(c, d); 147 | dag.addEdge(d, e); 148 | dag.addEdge(e, f); 149 | dag.addEdge(f, j); 150 | 构建完成后如图 151 | * H 152 | * \ 153 | * G 154 | * \ 155 | * A -> B 156 | * \ 157 | * C- D -E - F-> J 158 | 159 | 3 stage 切分 160 | DAG chain = dag.chain(); 161 | 执行完图入下: 162 | * (H,G) 163 | * \ 164 | * A -> B 165 | * \ 166 | * (C,D,E) - (F,J) 167 | 168 | 4 执行 DAG DAGExecTest 最终结果打印如下如下: 169 | 170 | 可以发现有3个Stage stage1 包含3个task task分别在不同的线程里面执行 171 | 其中c-d-e g-c f-j是经过优化的在同一个线程里面执行,减少了不必要的上下文切换 172 | 173 | i am running my name is a finish ThreadID: 10 174 | i am running my name is c finish ThreadID: 11 175 | i am running my name is h finish ThreadID: 12 176 | i am running my name is d finish ThreadID: 11 177 | i am running my name is g finish ThreadID: 12 178 | i am running my name is e finish ThreadID: 11 179 | stage 结束 : task detached:a, task chain c-d-e task chain h-g 180 | ----------------------------------------------- 181 | i am running my name is b finish ThreadID: 14 182 | stage 结束 : task detached:b, 183 | ----------------------------------------------- 184 | i am running my name is f finish ThreadID: 11 185 | i am running my name is j finish ThreadID: 11 186 | stage 结束 : task chain f-j 187 | 测试执行关键代码如下: 188 | chain.execute(col -> { 189 | Set set = (Set) col; 190 | List completableFutures = Lists.newArrayList(); 191 | StringBuilder sb = new StringBuilder(); 192 | set.stream().forEach(x -> { 193 | if (x instanceof Task) { 194 | CompletableFuture future = CompletableFuture.runAsync((Task) x, executorService); 195 | completableFutures.add(future); 196 | sb.append(" task detached:" + ((Task) x).getTaskName()).append(","); 197 | } 198 | if (x instanceof List) { 199 | List taskList = (List) x; 200 | CompletableFuture future = CompletableFuture.runAsync(()-> 201 | taskList.forEach(Task::run)); 202 | completableFutures.add(future); 203 | sb.append( 204 | " task chain " + Joiner.on("-").join(taskList.stream().map(Task::getTaskName).collect(Collectors.toList()))); 205 | } 206 | }); 207 | CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()])).join(); 208 | System.out.println("stage 结束 : " + sb.toString()); 209 | System.out.println("-----------------------------------------------"); 210 | }); 211 | 212 | mail:787069354@qq.com 213 | ``` 214 | 215 | 216 | 217 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/graph/ASearch.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.graph; 2 | 3 | /** 4 | * 5 | * A*搜索算法 6 | * 7 | * Dijkstra 8 | * 9 | * f = g + h 10 | * g => 起点移动到目标格的移动代价 11 | * h=> 从目标格 移动到 终点的代价 12 | * 13 | * @author xingliangbo 14 | * @version $Id: v 0.1 2019-09-09 19:47 xingliangbo Exp $ 15 | */ 16 | public class ASearch { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/graph/Dijkstra.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.graph; 2 | 3 | import com.google.common.base.Strings; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * 9 | * 最小路径之Dijkstra算法 10 | * @author xingliangbo 11 | * @version $Id: v 0.1 2019-09-09 16:36 xingliangbo Exp $ 12 | */ 13 | public class Dijkstra { 14 | 15 | /** 16 | * 2 --3-- 4 17 | * 1/ | / | \15 18 | * / 9 4 13 19 | * 1 | / 6 20 | * 12\ / /4 21 | * 3 --5-- 5 22 | * 23 | * 0 1 2 3 4 5 24 | * 0 0 1 12 999999 999999 999999 25 | * 1 999999 0 9 3 999999 999999 26 | * 2 999999 999999 0 999999 5 999999 27 | * 3 999999 999999 4 0 3 5 28 | * 4 999999 999999 999999 999999 0 4 29 | * 5 999999 999999 999999 999999 999999 0 30 | * 31 | * 32 | */ 33 | public int[][] init() { 34 | 35 | int[][] graph = new int[6][6]; 36 | int inf = 999999; //用inf 存储一个我们认为的正无穷值 37 | for (int i = 0; i < graph.length; i++) { 38 | for (int j = 0; j < graph[i].length; j++) { 39 | if (i == j) { 40 | graph[i][j] = 0;//自己到自己 肯定是0 41 | } else { 42 | graph[i][j] = inf;//默认值 43 | } 44 | } 45 | } 46 | graph[0][1] = 1;//默认值 47 | graph[0][2] = 12;//默认值 48 | graph[1][2] = 9;//默认值 49 | graph[1][3] = 3;//默认值 50 | graph[2][4] = 5;//默认值 51 | graph[3][2] = 4;//默认值 52 | graph[3][4] = 13;//默认值 53 | graph[3][5] = 15;//默认值 54 | graph[4][5] = 4;//默认值 55 | return graph; 56 | } 57 | 58 | 59 | 60 | public void compute(int[][] graph) { 61 | int[] dis = new int[6]; 62 | int[] flag = new int[6]; 63 | int inf = 999999; 64 | 65 | for (int i = 0; i < 6; i++) { 66 | flag[i] = 0; 67 | dis[i] = graph[0][i]; 68 | } 69 | //原点代表以及在dis 集合中了 70 | flag[0] = 1; 71 | dis[0] = 0; 72 | System.out.println("初始最小路径: 从原点0 到各节点的路径" + Arrays.toString(dis)); 73 | 74 | //遍历,每次找出一个顶点点最短路径 75 | int k = 0; 76 | for (int i = 1; i < 6; i++) { 77 | int min = inf; 78 | 79 | //寻找最短路径 80 | for (int j = 0; j < 6; j++) { 81 | if (flag[j] == 0 && dis[j] < min) {// 82 | k = j; 83 | min = dis[j]; 84 | } 85 | } 86 | flag[k] = 1; 87 | 88 | //以上求出了原点到k的距离是 min 89 | for (int j = 0; j < 6; j++) { 90 | //k到 j距离 = 原点到k的距离 + k到j距离 91 | int len = graph[k][j] == inf ? inf : min + graph[k][j]; 92 | //原点到j距离小于 原点到k的距离 + k到j的距离 跟新 原点到j的距离最小值为 dis[j] 93 | if (flag[j] == 0 && len < dis[j]) { 94 | dis[j] = len; 95 | } 96 | } 97 | System.out.println("正在寻找从原点0 "+ i +" dis " + Arrays.toString(dis) + " flag " + Arrays.toString(flag) ); 98 | 99 | } 100 | 101 | System.out.println("最终计算: 从原点 到i点的路径" + Arrays.toString(dis)); 102 | } 103 | 104 | 105 | public void print(int[][] graph) { 106 | String tab = Strings.repeat(" ", 10); 107 | StringBuilder sb = new StringBuilder(); 108 | sb.append(tab + " "); 109 | for (int i = 0; i < 6; i++) { 110 | String v = i + Strings.repeat(" ", 6 - (i + "").length()); 111 | sb.append(v).append(tab); 112 | } 113 | sb.append("\n\t"); 114 | for (int i = 0; i < graph.length; i++) { 115 | sb.append(i).append(tab); 116 | for (int j = 0; j < graph[i].length; j++) { 117 | String v = graph[i][j] + Strings.repeat(" ", 6 - (graph[i][j] + "").length()); 118 | sb.append(v).append(tab); 119 | } 120 | sb.append("\n\t"); 121 | } 122 | System.out.println(sb.toString()); 123 | } 124 | 125 | 126 | 127 | 128 | public static void main(String[] args) { 129 | Dijkstra dijkstra = new Dijkstra(); 130 | int[][] graph = dijkstra.init(); 131 | dijkstra.print(graph);//打印图 132 | dijkstra.compute(graph); 133 | 134 | } 135 | 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/graph/Kruskal.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.graph; 2 | 3 | /** 4 | * 5 | * 最小生成树 6 | * @author xingliangbo 7 | * @version $Id: v 0.1 2019-09-10 10:59 xingliangbo Exp $ 8 | */ 9 | public class Kruskal { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/graph/Prim.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.graph; 2 | 3 | /** 4 | * 最小生成树 5 | * 6 | * @author xingliangbo 7 | * @version $Id: v 0.1 2019-09-10 10:58 xingliangbo Exp $ 8 | */ 9 | public class Prim { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/algorithm/xlb/algorithm/leetcode/regex/RegexSolution.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm.leetcode.regex; 2 | 3 | /** 4 | * isMatch 递归 isMatch2 动态规划 5 | * https://leetcode-cn.com/problems/regular-expression-matching/ 6 | * @author xingliangbo 7 | * @version $Id: v 0.1 2019-09-06 11:51 xingliangbo Exp $ 8 | */ 9 | public class RegexSolution { 10 | 11 | 12 | /** 13 | * text = abc pattern = a*b 14 | * *是0个的时候 a*b = b => (b 匹配 abc) 递归 15 | * 匹配 16 | * *是多个时候 a 匹配 a 且 (bc 匹配 a*b)递归 17 | */ 18 | public static boolean isMatch(String text, String pattern) { 19 | 20 | if (pattern.isEmpty()) { 21 | return text.isEmpty(); 22 | } 23 | //判断首字符是否符合匹配 24 | boolean isFirstMatch = !text.isEmpty() && text.charAt(0) == pattern.charAt(0) || pattern.charAt(0) == '.'; 25 | //处理* 存在*的话有2中情况 1 中 0个 , 1种最大匹配n个 26 | if (pattern.length() >= 2 && pattern.charAt(1) == '*') { 27 | 28 | return isMatch(text, pattern.substring(2)) //如果是0个* 29 | || 30 | (!text.isEmpty() && isFirstMatch && isMatch(text.substring(1), pattern));//匹配最大个* 31 | } else { 32 | return isFirstMatch && isMatch(text.substring(1), pattern.substring(1)); 33 | } 34 | } 35 | 36 | 37 | /** 38 | * 39 | * eg : aaa 匹配 a* 40 | * __________________ 41 | * | | "" | a | a | 42 | * |"" | __ | __| __ | 43 | * | a | __ | __| __ | 44 | * | * | __ | __| __ | 45 | * 46 | * 47 | * 如果s1的第 i 个字符和s2的第 j 个字符相同,或者s2的第 j 个字符为 “.” 48 | *f[i][j] = f[i - 1][j - 1] 49 | * 如果s2的第 j 个字符为 * 50 | * 若s2的第 j 个字符匹配 0 次第 j - 1 个字符 51 | * f[i][j] = f[i][j - 2] 比如(ab, abc*) 52 | * 若s2的第 j 个字符匹配至少 1 次第 j - 1 个字符, 53 | * f[i][j] = f[i - 1][j] and s1[i] == s2[j - 1] or s[j - 1] == '.' 54 | * 这里注意不是 f[i - 1][j - 1], 举个例子就明白了 (abbb, ab*) f[4][3] = f[3][3] 55 | */ 56 | public static boolean isMatch2(String s, String p) { 57 | int m = s.length(), n = p.length(); 58 | boolean[][] f = new boolean[m + 1][n + 1]; 59 | 60 | f[0][0] = true; 61 | for (int i = 2; i <= n; i++) { 62 | //如果匹配0个* 63 | f[0][i] = f[0][i - 2] && p.charAt(i - 1) == '*'; 64 | } 65 | for (int i = 1; i <= m; i++) { 66 | for (int j = 1; j <= n; j++) { 67 | if (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.') { 68 | f[i][j] = f[i - 1][j - 1]; 69 | } 70 | if (p.charAt(j - 1) == '*') { 71 | f[i][j] = f[i][j - 2] || 72 | f[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.'); 73 | } 74 | } 75 | } 76 | 77 | return f[m][n]; 78 | 79 | 80 | } 81 | 82 | 83 | public static void main(String[] args) { 84 | System.out.println(isMatch2("aaa", "a*")); 85 | System.out.println(isMatch2("aaaB", "a*B")); 86 | System.out.println(isMatch2("abcd", ".*B")); 87 | System.out.println(isMatch2("abcdB", ".*B")); 88 | } 89 | 90 | } 91 | 92 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/test/java/com/algorithm/xlb/algorithm/AlgorithmApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class AlgorithmApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/algorithm/xlb/algorithm/DAGChainTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm; 2 | 3 | import com.algorithm.xlb.algorithm.dag.DAG; 4 | 5 | import org.junit.Assert; 6 | import org.junit.Test; 7 | 8 | /** 9 | * 10 | * @author xingliangbo 11 | * @version $Id: v 0.1 2019-09-03 16:52 xingliangbo Exp $ 12 | */ 13 | public class DAGChainTest { 14 | 15 | /** 16 | * A -> B -> C D ==> A,B,C D 17 | */ 18 | @Test 19 | public void testDag() { 20 | DAG dag = DAG.create(); 21 | dag.addVertex("A"); 22 | dag.addVertex("B"); 23 | dag.addVertex("C"); 24 | dag.addVertex("D"); 25 | dag.addEdge("A", "B"); 26 | dag.addEdge("B", "C"); 27 | System.out.println(dag); 28 | System.out.println("入度为0 的节点 : " + dag.getSources()); 29 | System.out.println("拓扑排序检测是否有环 : " + dag.isCircularity()); 30 | DAG chainDag = dag.chain(); 31 | System.out.println(chainDag); 32 | System.out.println("chain入度为0 的节点 : " + chainDag.getSources()); 33 | System.out.println("chain拓扑排序检测是否有环 : " + chainDag.isCircularity()); 34 | Assert.assertTrue(chainDag.toString().equals("OutDegree: {[A, B, C]=[], D=[]} InDegree: {[A, B, C]=[], D=[]}")); 35 | } 36 | 37 | 38 | /** 39 | * A -> B -> C 40 | * \ \ 41 | * D - >E ->F 42 | * 43 | * ==> 44 | * 45 | * (A,B) -> C 46 | * \ \ 47 | * D - > (E,F) 48 | * 49 | */ 50 | @Test 51 | public void testDag2() { 52 | DAG dag = DAG.create(); 53 | dag.addVertex("A"); 54 | dag.addVertex("B"); 55 | dag.addVertex("C"); 56 | dag.addVertex("D"); 57 | dag.addVertex("E"); 58 | dag.addVertex("F"); 59 | dag.addVertex("G"); 60 | dag.addEdge("A", "B"); 61 | dag.addEdge("B", "C"); 62 | dag.addEdge("B", "D"); 63 | dag.addEdge("C", "E"); 64 | dag.addEdge("D", "E"); 65 | dag.addEdge("E", "F"); 66 | System.out.println(dag); 67 | System.out.println("入度为0 的节点 : " + dag.getSources()); 68 | System.out.println("拓扑排序检测是否有环 : " + dag.isCircularity()); 69 | DAG chainDag = dag.chain(); 70 | System.out.println(chainDag); 71 | System.out.println("chain入度为0 的节点 : " + chainDag.getSources()); 72 | System.out.println("chain拓扑排序检测是否有环 : " + chainDag.isCircularity()); 73 | Assert.assertTrue(chainDag.toString().equals("OutDegree: {[A, B]=[C, D], [E, F]=[], C=[[E, F]], D=[[E, F]], G=[]} InDegree: {[A, B]=[], C=[[A, B]], D=[[A, B]], [E, F]=[C, D], G=[]}")); 74 | } 75 | 76 | 77 | 78 | /** 79 | * G 80 | * \ 81 | * A -> B -> C 82 | * \ \ 83 | * D - >E ->F 84 | * 85 | * ==> 86 | * 87 | * (A,B) -> C 88 | * \ \ 89 | * D - > (E,F) 90 | * 91 | */ 92 | @Test 93 | public void testDag3() { 94 | DAG dag = DAG.create(); 95 | dag.addVertex("A"); 96 | dag.addVertex("B"); 97 | dag.addVertex("C"); 98 | dag.addVertex("D"); 99 | dag.addVertex("E"); 100 | dag.addVertex("F"); 101 | dag.addVertex("G"); 102 | dag.addEdge("A", "B"); 103 | dag.addEdge("B", "C"); 104 | dag.addEdge("B", "D"); 105 | dag.addEdge("C", "E"); 106 | dag.addEdge("D", "E"); 107 | dag.addEdge("E", "F"); 108 | dag.addEdge("G", "B"); 109 | System.out.println(dag); 110 | System.out.println("入度为0 的节点 : " + dag.getSources()); 111 | System.out.println("拓扑排序检测是否有环 : " + dag.isCircularity()); 112 | DAG chainDag = dag.chain(); 113 | System.out.println(chainDag); 114 | System.out.println("chain入度为0 的节点 : " + chainDag.getSources()); 115 | System.out.println("chain拓扑排序检测是否有环 : " + chainDag.isCircularity()); 116 | Assert.assertTrue(chainDag.toString().equals("OutDegree: {A=[B], B=[C, D], [E, F]=[], C=[[E, F]], D=[[E, F]], G=[B]} InDegree: {A=[], B=[A, G], C=[B], D=[B], [E, F]=[C, D], G=[]}")); 117 | } 118 | 119 | 120 | 121 | 122 | /** 123 | * H 124 | * \ 125 | * G 126 | * \ 127 | * A -> B 128 | * \ 129 | * C- D -E - F-> J 130 | * 131 | * 132 | * 133 | * ==> 134 | * 135 | * (H,G) 136 | * \ 137 | * A -> B 138 | * \ 139 | * (C,D,E) - (F,J) 140 | * 141 | */ 142 | @Test 143 | public void testDag4() { 144 | DAG dag = DAG.create(); 145 | dag.addVertex("A"); 146 | dag.addVertex("B"); 147 | dag.addVertex("C"); 148 | dag.addVertex("D"); 149 | dag.addVertex("E"); 150 | dag.addVertex("F"); 151 | dag.addVertex("G"); 152 | dag.addVertex("H"); 153 | dag.addVertex("J"); 154 | dag.addEdge("H", "G"); 155 | dag.addEdge("G", "B"); 156 | dag.addEdge("A", "B"); 157 | dag.addEdge("B", "F"); 158 | dag.addEdge("C", "D"); 159 | dag.addEdge("D", "E"); 160 | dag.addEdge("E", "F"); 161 | dag.addEdge("F", "J"); 162 | System.out.println(dag); 163 | System.out.println("入度为0 的节点 : " + dag.getSources()); 164 | System.out.println("拓扑排序检测是否有环 : " + dag.isCircularity()); 165 | DAG chainDag = dag.chain(); 166 | System.out.println(chainDag); 167 | System.out.println("chain入度为0 的节点 : " + chainDag.getSources()); 168 | System.out.println("chain拓扑排序检测是否有环 : " + chainDag.isCircularity()); 169 | Assert.assertTrue(chainDag.toString().equals("OutDegree: {A=[B], [F, J]=[], B=[[F, J]], [C, D, E]=[[F, J]], [H, G]=[B]} InDegree: {A=[], B=[A, [H, G]], [F, J]=[B, [C, D, E]], [C, D, E]=[], [H, G]=[]}")); 170 | } 171 | 172 | 173 | /** 174 | * A -> B 175 | * \ 176 | * C- D -E - F-> J 177 | * 178 | * 179 | * 180 | * ==> 181 | 182 | * (A,B) 183 | * \ 184 | * (C,D,E) - (F,J) 185 | * 186 | */ 187 | @Test 188 | public void testDag5() { 189 | DAG dag = DAG.create(); 190 | dag.addVertex("A"); 191 | dag.addVertex("B"); 192 | dag.addVertex("C"); 193 | dag.addVertex("D"); 194 | dag.addVertex("E"); 195 | dag.addVertex("F"); 196 | dag.addVertex("G"); 197 | dag.addVertex("H"); 198 | dag.addVertex("J"); 199 | dag.addEdge("A", "B"); 200 | dag.addEdge("B", "F"); 201 | dag.addEdge("C", "D"); 202 | dag.addEdge("D", "E"); 203 | dag.addEdge("E", "F"); 204 | dag.addEdge("F", "J"); 205 | System.out.println(dag); 206 | System.out.println("入度为0 的节点 : " + dag.getSources()); 207 | System.out.println("拓扑排序检测是否有环 : " + dag.isCircularity()); 208 | DAG chainDag = dag.chain(); 209 | System.out.println(chainDag); 210 | System.out.println("chain入度为0 的节点 : " + chainDag.getSources()); 211 | System.out.println("chain拓扑排序检测是否有环 : " + chainDag.isCircularity()); 212 | Assert.assertTrue(chainDag.toString().equals("OutDegree: {A=[B], [F, J]=[], B=[[F, J]], [C, D, E]=[[F, J]], [H, G]=[B]} InDegree: {A=[], B=[A, [H, G]], [F, J]=[B, [C, D, E]], [C, D, E]=[], [H, G]=[]}")); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/test/java/com/algorithm/xlb/algorithm/DAGExecTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm; 2 | 3 | import com.algorithm.xlb.algorithm.dag.DAG; 4 | import com.google.common.base.Joiner; 5 | import com.google.common.collect.Lists; 6 | 7 | import java.util.List; 8 | import java.util.Set; 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | import java.util.stream.Collectors; 13 | 14 | /** 15 | * 16 | * @author xingliangbo 17 | * @version $Id: v 0.1 2019-09-03 19:06 xingliangbo Exp $ 18 | */ 19 | public class DAGExecTest { 20 | 21 | 22 | public static void main(String[] args) { 23 | 24 | ExecutorService executorService = Executors.newFixedThreadPool(10); 25 | 26 | DAG dag = DAG.create(); 27 | Task a = new Task("a"); 28 | Task b = new Task("b"); 29 | Task c = new Task("c"); 30 | Task d = new Task("d"); 31 | Task e = new Task("e"); 32 | Task f = new Task("f"); 33 | Task g = new Task("g"); 34 | Task h = new Task("h"); 35 | Task j = new Task("j"); 36 | dag.addVertex(a); 37 | dag.addVertex(b); 38 | dag.addVertex(c); 39 | dag.addVertex(d); 40 | dag.addVertex(e); 41 | dag.addVertex(f); 42 | dag.addVertex(g); 43 | dag.addVertex(h); 44 | dag.addVertex(j); 45 | dag.addEdge(h, g); 46 | dag.addEdge(g, b); 47 | dag.addEdge(a, b); 48 | dag.addEdge(b, f); 49 | dag.addEdge(c, d); 50 | dag.addEdge(d, e); 51 | dag.addEdge(e, f); 52 | dag.addEdge(f, j); 53 | DAG chain = dag.chain(); 54 | /** 55 | * H 56 | * \ 57 | * G 58 | * \ 59 | * A -> B 60 | * \ 61 | * C- D -E - F-> J 62 | * 63 | * 64 | * 65 | * ==> 66 | * 67 | * (H,G) 68 | * \ 69 | * A -> B 70 | * \ 71 | * (C,D,E) - (F,J) 72 | * 73 | */ 74 | System.out.println(chain); 75 | 76 | 77 | chain.execute(col -> { 78 | Set set = (Set) col; 79 | List completableFutures = Lists.newArrayList(); 80 | StringBuilder sb = new StringBuilder(); 81 | set.stream().forEach(x -> { 82 | if (x instanceof Task) { 83 | CompletableFuture future = CompletableFuture.runAsync((Task) x, executorService); 84 | completableFutures.add(future); 85 | sb.append(" task detached:" + ((Task) x).getTaskName()).append(","); 86 | } 87 | if (x instanceof List) { 88 | List taskList = (List) x; 89 | CompletableFuture future = CompletableFuture.runAsync(()-> 90 | taskList.forEach(Task::run)); 91 | completableFutures.add(future); 92 | sb.append( 93 | " task chain " + Joiner.on("-").join(taskList.stream().map(Task::getTaskName).collect(Collectors.toList()))); 94 | } 95 | }); 96 | CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()])).join(); 97 | System.out.println("stage 结束 : " + sb.toString()); 98 | System.out.println("-----------------------------------------------"); 99 | }); 100 | } 101 | 102 | 103 | public static class Task implements Runnable { 104 | 105 | private String taskName; 106 | 107 | public Task(final String taskName) { 108 | this.taskName = taskName; 109 | } 110 | 111 | @Override public void run() { 112 | try { 113 | Thread.sleep(2000); 114 | } catch (InterruptedException e) { 115 | e.printStackTrace(); 116 | } 117 | System.out.println("i am running my name is " + taskName + " finish ThreadID: " + Thread.currentThread().getId()); 118 | } 119 | 120 | public String getTaskName() { 121 | return taskName; 122 | } 123 | 124 | @Override public String toString() { 125 | return taskName; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/test/java/com/algorithm/xlb/algorithm/DAGTest.java: -------------------------------------------------------------------------------- 1 | package com.algorithm.xlb.algorithm; 2 | 3 | import com.algorithm.xlb.algorithm.dag.DAG; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * 9 | * @author xingliangbo 10 | * @version $Id: v 0.1 2019-09-03 16:31 xingliangbo Exp $ 11 | */ 12 | public class DAGTest { 13 | 14 | @Test 15 | public void testDag() { 16 | DAG dag = DAG.create(); 17 | dag.addVertex("A"); 18 | dag.addVertex("B"); 19 | dag.addVertex("C"); 20 | dag.addVertex("D"); 21 | dag.addEdge("A", "B"); 22 | dag.addEdge("A", "C"); 23 | System.out.println(dag); 24 | System.out.println("入度为0 的节点 : " + dag.getSources()); 25 | System.out.println("拓扑排序检测是否有环 : " + dag.isCircularity()); 26 | } 27 | 28 | /** 29 | * A 30 | * / \ 31 | * B C 32 | * | // 33 | * D 34 | * | 35 | * E 36 | */ 37 | @Test 38 | public void testIsCircularity() { 39 | DAG dag = DAG.create(); 40 | dag.addVertex("A"); 41 | dag.addVertex("B"); 42 | dag.addVertex("C"); 43 | dag.addVertex("D"); 44 | dag.addVertex("E"); 45 | dag.addEdgeWithNoCheck("A", "B"); 46 | dag.addEdgeWithNoCheck("A", "C"); 47 | dag.addEdgeWithNoCheck("B", "D"); 48 | dag.addEdgeWithNoCheck("C", "D"); 49 | dag.addEdgeWithNoCheck("D", "C"); 50 | dag.addEdgeWithNoCheck("D", "E"); 51 | System.out.println(dag); 52 | System.out.println("入度为0 的节点 : " + dag.getSources()); 53 | System.out.println("拓扑排序检测是否有环 : " + dag.isCircularity()); 54 | } 55 | } 56 | --------------------------------------------------------------------------------