├── .gitignore ├── README.md ├── algorithm ├── backtracking │ ├── MatrixPath.java │ ├── NQueen.java │ └── SumCombinationInArray.java ├── divideconquer │ ├── BigNumMultiply.java │ └── BinarySearch.java └── dp │ ├── LongestCommonSubSequence.java │ └── LongestCommonSubString.java ├── graph ├── BreadthFirstSearch.java ├── DepthFirstSearch.java ├── Digraph数据类型.cpp ├── Digraph数据类型.java ├── Digraph有向图可达性.cpp ├── Digraph有向图强连通分量的Kosaraju算法.cpp ├── Digraph有向图拓扑排序.cpp ├── Digraph有向图是否有环.cpp ├── Digraph有向图顶点排序.cpp ├── Graph广度优先搜索.cpp ├── Graph广度优先搜索查找图中路径.cpp ├── Graph数据类型.cpp ├── Graph数据结构.java ├── Graph深度优先搜索.cpp ├── Graph深度优先搜索判断是否是二分图.cpp ├── Graph深度优先搜索判断是否是无环图.cpp ├── Graph深度优先搜索找出图中所有的连通分量.cpp ├── Graph深度优先搜索查找图中路径.cpp ├── KosarajuSCC-强连通分量.java ├── TopologicalSort-拓扑排序.java ├── 最小生成树的Kruskal算法.cpp ├── 最小生成树的Prim算法.cpp ├── 最短路径的Dijkstra算法.cpp └── 最短路径的加权有向图数据结构.cpp ├── other ├── ObjectPool.cpp └── skip_list.cpp ├── search ├── bianry_search.cpp ├── bianry_search更多扩展.cpp ├── hash.cpp ├── hash.h ├── hash_test.cpp ├── rbtree.cpp ├── rbtree.h ├── rbtree_test.cpp └── 二叉查找树.cpp ├── sort ├── sort_bubble.cpp ├── sort_heap.cpp ├── sort_insert.cpp ├── sort_merge.cpp ├── sort_quick.cpp ├── sort_radix.cpp ├── sort_select.cpp └── sort_shell.cpp └── string ├── string_LSD_sort.cpp ├── string_huffman.cpp ├── string_kmp.cpp └── 单词查找树.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # other 26 | .idea 27 | *.iml 28 | target/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | > This Repository contains data structure and algorithm. I will add code files to it slowly. 3 | 4 | graph: 5 | 关于图的各种数据结构和算法 6 | 7 | search: 8 | 关于查找的各种数据结构和算法(二分查找/二叉排序树/红黑树/哈希表) 9 | 10 | sort: 11 | 关于各种排序算法 12 | 13 | string: 14 | 关于字符串的各种算法 15 | 16 | other: 17 | 其他的一些数据结构 18 | -------------------------------------------------------------------------------- /algorithm/backtracking/MatrixPath.java: -------------------------------------------------------------------------------- 1 | package backtracking; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | /** 8 | * 矩阵中寻找某条路径 9 | * 比如矩阵:[a b t g 10 | * c f c s 11 | * j d e h] 12 | * 路径:b f c e 13 | */ 14 | public class MatrixPath { 15 | 16 | public static void main(String[] args) { 17 | List> matrix = new ArrayList<>(); 18 | matrix.add(new ArrayList<>(Arrays.asList("a b t g".split(" ")))); 19 | matrix.add(new ArrayList<>(Arrays.asList("c f c s".split(" ")))); 20 | matrix.add(new ArrayList<>(Arrays.asList("j d e h".split(" ")))); 21 | 22 | boolean hasPath = new MatrixPath().hasPath(matrix, "bfce"); 23 | System.out.println(hasPath); 24 | } 25 | 26 | /** 27 | * 回溯法:首先任意一个点都有可能成为起点,所以要获得任意一点的坐标(位于第几行,第几列) 28 | * 其次要有一个数组记录这个点是否被访问过,同时要有一个指针来记录字符串中字符的位置。 29 | * 当某个点成为合法的起点时,即这个点与字符串中第一个字符相等,则可以继续朝上下左右搜索下一个点; 30 | * 如果这个点不能成为合法的起点,则恢复现场(这个点没有被访问过且字符串指针后退) 31 | */ 32 | private boolean hasPath(List> matrix, String str) { 33 | boolean[][] visited = new boolean[matrix.size()][matrix.get(0).size()]; 34 | 35 | for (int i = 0; i < matrix.size(); i++) { 36 | for (int j = 0; j < matrix.get(i).size(); j++) { 37 | if (isPath(matrix, i, j, visited, str)) { 38 | return true; 39 | } 40 | } 41 | } 42 | 43 | return false; 44 | } 45 | 46 | private int index = 0; 47 | private boolean isPath(List> matrix, int i, int j, boolean[][] visited, String str) { 48 | if (index == str.length()) { 49 | return true; 50 | } 51 | 52 | boolean flag = false; 53 | if (i >= 0 && j >= 0 && i < matrix.size() && j < matrix.get(i).size() && 54 | !visited[i][j] && matrix.get(i).get(j).equals(String.valueOf(str.charAt(index)))) { 55 | index++; 56 | visited[i][j] = true; 57 | 58 | flag = isPath(matrix, i + 1, j, visited, str) || 59 | isPath(matrix, i - 1, j, visited, str) || 60 | isPath(matrix, i, j + 1, visited, str) || 61 | isPath(matrix, i, j - 1, visited, str); 62 | if (!flag) { 63 | index--; 64 | visited[i][j] = false; 65 | } 66 | } 67 | 68 | return flag; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /algorithm/backtracking/NQueen.java: -------------------------------------------------------------------------------- 1 | package backtracking; 2 | 3 | import javafx.util.Pair; 4 | 5 | import java.util.LinkedList; 6 | 7 | /** 8 | * N皇后问题 9 | */ 10 | public class NQueen { 11 | 12 | public static void main(String[] args) { 13 | // 8皇后问题,8皇后的解共有92个 14 | new NQueen().recall(0, 8, new LinkedList<>()); 15 | } 16 | 17 | private int num = 0; 18 | 19 | /** 20 | * 回溯法求N皇后问题 21 | */ 22 | private void recall(int i, int end, LinkedList> list) { 23 | if (list.size() == end) { 24 | System.out.println(++num + " " + list); 25 | return; 26 | } else if (i >= end) { 27 | return; 28 | } 29 | 30 | for (int j = 0; j < end; j++) { 31 | if (!listIsValid(list, i, j)) { 32 | continue; 33 | } 34 | 35 | list.addLast(new Pair<>(i, j)); 36 | recall(i + 1, end, list); 37 | list.removeLast(); 38 | } 39 | } 40 | 41 | /** 42 | * 约束条件(皇后不能处于同一行、不能处于同一列、不能同一个斜线上) 43 | */ 44 | private boolean listIsValid(LinkedList> list, int x, int y) { 45 | boolean flag = true; 46 | 47 | for (Pair pair : list) { 48 | if (pair.getKey() == x || pair.getValue() == y || Math.abs(x - pair.getKey()) == Math.abs(y - pair.getValue())) { 49 | flag = false; 50 | break; 51 | } 52 | } 53 | 54 | return flag; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /algorithm/backtracking/SumCombinationInArray.java: -------------------------------------------------------------------------------- 1 | package backtracking; 2 | 3 | import java.util.Arrays; 4 | import java.util.LinkedList; 5 | 6 | /** 7 | * 求数组中和为固定值的所有组合 8 | */ 9 | public class SumCombinationInArray { 10 | 11 | public static void main(String[] args) { 12 | LinkedList list = new LinkedList<>(Arrays.asList(1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 7)); 13 | 14 | /* 15 | * 1. 数组为从小到大排序 16 | * 2. 求list中和为10的所有组合 17 | */ 18 | new SumCombinationInArray().recall(list, 0, 0, 10, new LinkedList<>()); 19 | } 20 | 21 | /** 22 | * 回溯法 求数组中和为固定值的组合 23 | */ 24 | private void recall(LinkedList list, int start, int current, int target, LinkedList tmpList) { 25 | if (start >= list.size()) { 26 | return; 27 | } 28 | if (current + list.get(start) > target) { 29 | return; 30 | } 31 | 32 | current += list.get(start); 33 | tmpList.addLast(list.get(start)); 34 | if (current == target) { 35 | System.out.println(tmpList); 36 | } 37 | 38 | recall(list, start + 1, current, target, tmpList); 39 | 40 | tmpList.removeLast(); 41 | current -= list.get(start); 42 | 43 | int i = start + 1; 44 | while (i < list.size() && (int)list.get(i) == list.get(start)) { 45 | i++; 46 | } 47 | 48 | recall(list, i, current, target, tmpList); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /algorithm/divideconquer/BigNumMultiply.java: -------------------------------------------------------------------------------- 1 | package divideconquer; 2 | 3 | import java.util.Random; 4 | 5 | /** 6 | * 分治法 - 大数相乘 7 | * 8 | * @author xiangnan 9 | */ 10 | public class BigNumMultiply { 11 | 12 | public static void main(String[] args) { 13 | for (int i = 0; i < 10; i++) { 14 | int x = new Random().nextInt(9000) + 1000; 15 | int y = new Random().nextInt(9000) + 1000; 16 | 17 | assert x * y == new BigNumMultiply().multiply(x, y); 18 | } 19 | } 20 | 21 | private long multiply(long x, long y) { 22 | int n = Math.min(String.valueOf(x).length(), String.valueOf(y).length()); 23 | 24 | if (x == 0 || y == 0 || n == 0) { 25 | return 0; 26 | } else if (n == 1) { 27 | return x * y; 28 | } else { 29 | int power = n / 2; 30 | long a = x / (long) Math.pow(10, power); 31 | long b = x - a * (long) Math.pow(10, power); 32 | long c = y / (long) Math.pow(10, power); 33 | long d = y - c * (long) Math.pow(10, power); 34 | 35 | long ac = multiply(a, c); 36 | long bd = multiply(b, d); 37 | long abcd = multiply(b, c) + multiply(a, d); 38 | return ac * (long) Math.pow(10, n) + abcd * (long) Math.pow(10, power) + bd; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /algorithm/divideconquer/BinarySearch.java: -------------------------------------------------------------------------------- 1 | package divideconquer; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * 二分查找 8 | * 9 | * @author xiangnan 10 | */ 11 | public class BinarySearch { 12 | 13 | public static void main(String[] args) { 14 | List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 15 | System.out.println(new BinarySearch().search(list, 6)); 16 | } 17 | 18 | /** 19 | * while (low <= high)不能改为<,否则的话条件判断不完整,比如: 20 | * a[3] = {1, 3, 5};待查找的键为5,此时在(low < high)条件下就会找不到 21 | * 因为low和high相等时,指向元素5,但是此时条件不成立,没有进入while()中 22 | * 23 | * @param list 数组 24 | * @param num 待查找的值 25 | * @return 找到为该键在数组中的下标,否则为-1 26 | */ 27 | private int search(List list, int num) { 28 | int left = 0; 29 | int right = list.size() - 1; 30 | 31 | while (left <= right) { 32 | int mid = (left + right) / 2; 33 | if (num == list.get(mid)) { 34 | return mid; 35 | } else if (num < list.get(mid)) { 36 | right = mid - 1; 37 | } else { 38 | left = mid + 1; 39 | } 40 | } 41 | 42 | return -1; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /algorithm/dp/LongestCommonSubSequence.java: -------------------------------------------------------------------------------- 1 | package dp; 2 | 3 | /** 4 | * 动态规划 - 最长公共子序列 5 | * 最长公共子序列(Longest Common SubSequence,LongestCommonSubSequence),顾名思义,是指在所有的子序列中最长的那一个。 6 | * 注意,子序列可以不连续,比如cnblogs和belong,序列bo都是二者的子序列。 7 | * 8 | * @author xiangnan 9 | */ 10 | public class LongestCommonSubSequence { 11 | 12 | public static void main(String[] args) { 13 | System.out.println(new LongestCommonSubSequence().lcs("1A2C3D4B56".toCharArray(), "B1D23CA45B6A".toCharArray())); 14 | } 15 | 16 | private int lcs(char[] a, char[] b) { 17 | int al = a.length; 18 | int bl = b.length; 19 | 20 | int[][] array = new int[al+1][bl+1]; 21 | for (int i = 1; i <= al; i++) { 22 | for (int j = 1; j <= bl; j++) { 23 | if (a[i-1] == b[j-1]) { 24 | array[i][j] = array[i-1][j-1] + 1; 25 | } else { 26 | array[i][j] = Math.max(array[i-1][j-1], Math.max(array[i][j-1], array[i-1][j])); 27 | } 28 | } 29 | } 30 | 31 | return array[al][bl]; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /algorithm/dp/LongestCommonSubString.java: -------------------------------------------------------------------------------- 1 | package dp; 2 | 3 | /** 4 | * 动态规划 - 最长公共子串 5 | * 两个字符串,求出它们之间最长的相同子字符串的长度。 6 | * 7 | * @author xiangnan 8 | */ 9 | public class LongestCommonSubString { 10 | 11 | public static void main(String[] args) { 12 | System.out.println(new LongestCommonSubString().lcs("1AB2345CD".toCharArray(), "12345EF".toCharArray())); 13 | } 14 | 15 | private int lcs(char[] a, char[] b) { 16 | int al = a.length; 17 | int bl = b.length; 18 | 19 | int max = 0; 20 | int[][] array = new int[al+1][bl+1]; 21 | for (int i = 1; i <= al; i++) { 22 | for (int j = 1; j <= bl; j++) { 23 | if (a[i-1] == b[j-1]) { 24 | array[i][j] = array[i-1][j-1] + 1; 25 | } else { 26 | array[i][j] = 0; 27 | } 28 | 29 | max = Math.max(max, array[i][j]); 30 | } 31 | } 32 | 33 | return max; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /graph/BreadthFirstSearch.java: -------------------------------------------------------------------------------- 1 | package graph; 2 | 3 | 4 | import java.util.ArrayDeque; 5 | import java.util.ArrayList; 6 | import java.util.Deque; 7 | import java.util.List; 8 | 9 | public class BreadthFirstSearch { 10 | 11 | // ---------------------------------- Instance Variables 12 | 13 | // 无向图 14 | Digraph graph; 15 | 16 | // 广度优先搜索后的顶点顺序 17 | List sorted = new ArrayList(); 18 | 19 | // ---------------------------------- Constructors 20 | 21 | public BreadthFirstSearch(Digraph graph, int node) { 22 | if (node >= graph.getVertaxs()) { 23 | return; 24 | } 25 | 26 | this.graph = graph; 27 | // boolean数组默认都置为false,所以不用专门初始化 28 | boolean []marked = new boolean[graph.getVertaxs()]; 29 | bfs(node, marked); 30 | } 31 | 32 | // ---------------------------------- Public Methods 33 | 34 | public List getSorted() { 35 | return new ArrayList(sorted); 36 | } 37 | 38 | // ---------------------------------- Private Methods 39 | 40 | private void bfs(int node, boolean []marked) { 41 | Deque deque = new ArrayDeque(); 42 | 43 | marked[node] = true; 44 | sorted.add(node); 45 | deque.addLast(node); 46 | while (deque.size() > 0) { 47 | int vertax = deque.pollFirst(); 48 | List list = this.graph.adj(vertax); 49 | for (Integer ele : list) { 50 | if (!marked[ele]) { 51 | marked[ele] = true; 52 | sorted.add(ele); 53 | deque.addLast(ele); 54 | } 55 | } 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /graph/DepthFirstSearch.java: -------------------------------------------------------------------------------- 1 | package graph; 2 | 3 | 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | /** 8 | * 深度优先搜索 9 | */ 10 | public class DepthFirstSearch { 11 | 12 | // ---------------------------------- Instance Variables 13 | 14 | // 无向图 15 | Digraph graph; 16 | 17 | // 深度优先搜索后的顶点顺序 18 | List sorted = new ArrayList(); 19 | 20 | // ---------------------------------- Constructors 21 | 22 | public DepthFirstSearch(Digraph graph, int node) { 23 | if (node >= graph.getVertaxs()) { 24 | return; 25 | } 26 | 27 | this.graph = graph; 28 | // boolean数组默认都置为false,所以不用专门初始化 29 | boolean []marked = new boolean[graph.getVertaxs()]; 30 | dfs(node, marked); 31 | } 32 | 33 | // ---------------------------------- Public Methods 34 | 35 | public List getSorted() { 36 | return new ArrayList(sorted); 37 | } 38 | 39 | // ---------------------------------- Private Methods 40 | 41 | private void dfs(int node, boolean []marked) { 42 | if (marked[node]) { 43 | return; 44 | } 45 | 46 | marked[node] = true; 47 | sorted.add(node); 48 | List nodes = this.graph.adj(node); 49 | for (int i = 0; i < nodes.size(); i++) { 50 | dfs(nodes.get(i), marked); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /graph/Digraph数据类型.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | class Digraph 7 | { 8 | public: 9 | Digraph(size_t nvertax) : arr(nvertax), vertaxs(nvertax), edges(0) {} 10 | void addEdge(size_t a, size_t b); 11 | void removeEdge(size_t a, size_t b); 12 | void addVertax(size_t v); 13 | void removeVertax(size_t v); 14 | Digraph reverse() const; 15 | 16 | vector adj(size_t v) const; 17 | void showAdj(size_t v) const; 18 | void showDigraph() const; 19 | 20 | size_t edge() const { return edges; } 21 | size_t vertax() const { return vertaxs; } 22 | size_t arrSize() const { return arr.size(); } 23 | 24 | private: 25 | vector> arr; 26 | size_t vertaxs; 27 | size_t edges; 28 | }; 29 | 30 | int main(void) 31 | { 32 | Digraph graph(5); 33 | 34 | graph.addEdge(0, 1); 35 | graph.addEdge(0, 2); 36 | graph.addEdge(1, 3); 37 | graph.addEdge(2, 3); 38 | graph.addEdge(3, 4); 39 | graph.addEdge(4, 2); 40 | 41 | cout << graph.vertax() << endl; 42 | cout << graph.edge() << endl; 43 | graph.showDigraph(); 44 | cout << endl; 45 | 46 | Digraph g = graph.reverse(); 47 | cout << g.vertax() << endl; 48 | cout << g.edge() << endl; 49 | g.showDigraph(); 50 | 51 | return 0; 52 | } 53 | 54 | 55 | void Digraph::addEdge(size_t a, size_t b) 56 | { 57 | if (!(a < vertax() && b < vertax())) 58 | return; 59 | arr[a].push_back(b); 60 | edges++; 61 | } 62 | 63 | void Digraph::removeEdge(size_t a, size_t b) 64 | { 65 | if (!(a < vertax() && b < vertax())) 66 | return; 67 | 68 | vector::iterator iter = find(arr[a].begin(), arr[a].end(), b); 69 | if (iter != arr[a].end()) 70 | { 71 | arr[a].erase(iter); 72 | edges--; 73 | } 74 | } 75 | 76 | void Digraph::addVertax(size_t v) 77 | { 78 | if (v != arrSize()) 79 | return; 80 | arr.push_back(vector()); 81 | vertaxs++; 82 | } 83 | 84 | void Digraph::removeVertax(size_t v) 85 | { 86 | if (v >= arrSize()) 87 | return; 88 | vector::iterator iter; 89 | 90 | for (size_t i = 0; i < arrSize(); i++) 91 | { 92 | if (i == v) 93 | { 94 | edges -= arr[i].size(); // 减去头部是v的边的个数 95 | arr[i].clear(); 96 | vertaxs--; 97 | } 98 | else 99 | { 100 | iter = find(arr[i].begin(), arr[i].end(), v); 101 | if (iter != arr[i].end()) 102 | { 103 | arr[i].erase(iter); 104 | edges--; 105 | } 106 | } 107 | } 108 | } 109 | 110 | Digraph Digraph::reverse() const 111 | { 112 | Digraph graph(vertax()); 113 | vector vec; 114 | 115 | for (size_t i = 0; i < arrSize(); i++) 116 | { 117 | vec = adj(i); 118 | for (size_t j = 0; j < vec.size(); j++) 119 | { 120 | graph.addEdge(vec[j], i); // 取得该图的反向图 121 | } 122 | } 123 | 124 | return graph; 125 | } 126 | 127 | vector Digraph::adj(size_t v) const 128 | { 129 | if (v < arrSize()) 130 | return arr[v]; 131 | else 132 | vector(); 133 | } 134 | 135 | void Digraph::showAdj(size_t v) const 136 | { 137 | if (v >= arrSize()) 138 | return; 139 | 140 | vector vec = adj(v); 141 | for (size_t i = 0; i < vec.size(); i++) 142 | cout << vec[i] << " "; 143 | cout << endl; 144 | } 145 | 146 | void Digraph::showDigraph() const 147 | { 148 | for (size_t i = 0; i < arr.size(); i++) 149 | { 150 | cout << i << ": "; 151 | showAdj(i); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /graph/Digraph数据类型.java: -------------------------------------------------------------------------------- 1 | package graph; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Digraph { 7 | 8 | // ---------------------------------- Instance Variables 9 | 10 | // 邻接表List 11 | private List> array; 12 | 13 | // ---------------------------------- Constructors 14 | 15 | public Digraph() { 16 | this(8); 17 | } 18 | 19 | public Digraph(int nodes) { 20 | if (nodes < 8) { 21 | nodes = 8; 22 | } 23 | array = new ArrayList>(8); 24 | System.out.println(); 25 | for (int i = 0; i < nodes; i++) { 26 | array.add(new ArrayList()); 27 | } 28 | } 29 | 30 | // ---------------------------------- Public Methods 31 | 32 | /** 33 | * 往Digraph中添加一条边 34 | * @param a 节点a 35 | * @param b 节点b 36 | */ 37 | public void add(int a, int b) { 38 | if (a >= array.size() || b >= array.size()) { 39 | return; 40 | } 41 | 42 | array.get(a).add(b); 43 | array.get(b).add(a); 44 | } 45 | 46 | /** 47 | * 从Digraph中移除一条边 48 | * @param a 49 | * @param b 50 | */ 51 | public void remove(int a, int b) { 52 | if (a >= array.size() || b >= array.size()) { 53 | return; 54 | } 55 | 56 | array.get(a).remove(Integer.valueOf(b)); 57 | array.get(b).remove(Integer.valueOf(a)); 58 | } 59 | 60 | /** 61 | * Digraph中是否包含边(a, b) 62 | * @param a 63 | * @param b 64 | */ 65 | public boolean contains(int a, int b) { 66 | if (a >= array.size() || b >= array.size()) { 67 | return false; 68 | } 69 | 70 | return array.get(a).contains(b); 71 | } 72 | 73 | /** 74 | * 返回Digraph中顶点个数 75 | */ 76 | public int getVertaxs() { 77 | return array.size(); 78 | } 79 | 80 | /** 81 | * 返回Digraph中边的个数 82 | */ 83 | public int getEdges() { 84 | int edges = 0; 85 | 86 | for (List ele : array) { 87 | edges += ele.size(); 88 | } 89 | return edges >> 1; 90 | } 91 | /** 92 | * 返回某个顶点向关联的所有顶点 93 | */ 94 | public List adj(int a) { 95 | if (a >= array.size()) { 96 | return new ArrayList(); 97 | } 98 | 99 | return array.get(a); 100 | } 101 | 102 | @Override 103 | public String toString() { 104 | StringBuffer buffer = new StringBuffer(); 105 | for (int i = 0; i < array.size(); i++) { 106 | List ele = array.get(i); 107 | buffer.append(i + ": "); 108 | for (Integer node : ele) { 109 | buffer.append(node + " "); 110 | } 111 | buffer.append("\n"); 112 | } 113 | 114 | return buffer.toString(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /graph/Digraph有向图可达性.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | class Digraph 7 | { 8 | public: 9 | Digraph(size_t nvertax) : arr(nvertax), vertaxs(nvertax), edges(0) {} 10 | void addEdge(size_t a, size_t b); 11 | void removeEdge(size_t a, size_t b); 12 | void addVertax(size_t v); 13 | void removeVertax(size_t v); 14 | Digraph reverse() const; 15 | 16 | vector adj(size_t v) const; 17 | void showAdj(size_t v) const; 18 | void showDigraph() const; 19 | 20 | size_t edge() const { return edges; } 21 | size_t vertax() const { return vertaxs; } 22 | size_t arrSize() const { return arr.size(); } 23 | 24 | private: 25 | vector> arr; // 邻接表 26 | size_t vertaxs; // 顶点个数 27 | size_t edges; // 边的个数 28 | }; 29 | 30 | /// 使用深度优先遍历测试有向图的可达性 31 | class DirectedDFS 32 | { 33 | public: 34 | DirectedDFS(const Digraph &graph, size_t _start) : marked(graph.arrSize()), start(_start) 35 | { 36 | for (size_t i = 0; i < graph.arrSize(); i++) 37 | marked[i] = false; 38 | dfs(graph, start); 39 | } 40 | 41 | /// 节点v是可达的吗?起点start 42 | bool isDirected(size_t v) const { return (v < marked.size()) ? marked[v] : false; } 43 | 44 | private: 45 | void dfs(const Digraph &graph, size_t v) 46 | { 47 | marked[v] = true; 48 | 49 | vector vec = graph.adj(v); 50 | for (size_t i = 0; i < vec.size(); i++) 51 | { 52 | if (!marked[vec[i]]) 53 | dfs(graph, vec[i]); 54 | } 55 | } 56 | 57 | vector marked; 58 | size_t start; // 起点 59 | }; 60 | 61 | int main(void) 62 | { 63 | Digraph graph(5); 64 | 65 | graph.addEdge(0, 1); 66 | graph.addEdge(0, 2); 67 | graph.addEdge(1, 3); 68 | graph.addEdge(2, 3); 69 | //graph.addEdge(3, 4); 70 | graph.addEdge(4, 2); 71 | 72 | cout << graph.vertax() << endl; 73 | cout << graph.edge() << endl; 74 | graph.showDigraph(); 75 | cout << endl; 76 | 77 | DirectedDFS dir(graph, 0); 78 | 79 | cout << "0 -> 3: "; 80 | if (dir.isDirected(3)) 81 | cout << "true" << endl; 82 | else 83 | cout << "false" << endl; 84 | 85 | cout << "0 -> 4: "; 86 | if (dir.isDirected(4)) 87 | cout << "true" << endl; 88 | else 89 | cout << "false" << endl; 90 | 91 | return 0; 92 | } 93 | 94 | 95 | void Digraph::addEdge(size_t a, size_t b) 96 | { 97 | if (!(a < vertax() && b < vertax())) 98 | return; 99 | arr[a].push_back(b); 100 | edges++; 101 | } 102 | 103 | void Digraph::removeEdge(size_t a, size_t b) 104 | { 105 | if (!(a < vertax() && b < vertax())) 106 | return; 107 | 108 | vector::iterator iter = find(arr[a].begin(), arr[a].end(), b); 109 | if (iter != arr[a].end()) 110 | { 111 | arr[a].erase(iter); 112 | edges--; 113 | } 114 | } 115 | 116 | void Digraph::addVertax(size_t v) 117 | { 118 | if (v != arrSize()) 119 | return; 120 | arr.push_back(vector()); 121 | vertaxs++; 122 | } 123 | 124 | void Digraph::removeVertax(size_t v) 125 | { 126 | if (v >= arrSize()) 127 | return; 128 | vector::iterator iter; 129 | 130 | for (size_t i = 0; i < arrSize(); i++) 131 | { 132 | if (i == v) 133 | { 134 | edges -= arr[i].size(); // 减去头部是v的边的个数 135 | arr[i].clear(); 136 | vertaxs--; 137 | } 138 | else 139 | { 140 | iter = find(arr[i].begin(), arr[i].end(), v); 141 | if (iter != arr[i].end()) 142 | { 143 | arr[i].erase(iter); 144 | edges--; 145 | } 146 | } 147 | } 148 | } 149 | 150 | Digraph Digraph::reverse() const 151 | { 152 | Digraph graph(vertax()); 153 | vector vec; 154 | 155 | for (size_t i = 0; i < arrSize(); i++) 156 | { 157 | vec = adj(i); 158 | for (size_t j = 0; j < vec.size(); j++) 159 | { 160 | graph.addEdge(vec[j], i); // 取得该图的反向图 161 | } 162 | } 163 | 164 | return graph; 165 | } 166 | 167 | vector Digraph::adj(size_t v) const 168 | { 169 | if (v < arrSize()) 170 | return arr[v]; 171 | else 172 | vector(); 173 | } 174 | 175 | void Digraph::showAdj(size_t v) const 176 | { 177 | if (v >= arrSize()) 178 | return; 179 | 180 | vector vec = adj(v); 181 | for (size_t i = 0; i < vec.size(); i++) 182 | cout << vec[i] << " "; 183 | cout << endl; 184 | } 185 | 186 | void Digraph::showDigraph() const 187 | { 188 | for (size_t i = 0; i < arr.size(); i++) 189 | { 190 | cout << i << ": "; 191 | showAdj(i); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /graph/Digraph有向图强连通分量的Kosaraju算法.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class Digraph 8 | { 9 | public: 10 | Digraph(size_t nvertax) : arr(nvertax), vertaxs(nvertax), edges(0) {} 11 | void addEdge(size_t a, size_t b); 12 | void removeEdge(size_t a, size_t b); 13 | void addVertax(size_t v); 14 | void removeVertax(size_t v); 15 | Digraph reverse() const; 16 | 17 | vector adj(size_t v) const; 18 | void showAdj(size_t v) const; 19 | void showDigraph() const; 20 | 21 | size_t edge() const { return edges; } 22 | size_t vertax() const { return vertaxs; } 23 | size_t arrSize() const { return arr.size(); } 24 | 25 | private: 26 | vector> arr; // 邻接表 27 | size_t vertaxs; // 顶点个数 28 | size_t edges; // 边的个数 29 | }; 30 | 31 | /// 使用深度优先遍历在有向图中寻找有向环 32 | class DirectedCycle 33 | { 34 | public: 35 | DirectedCycle(const Digraph &graph) : marked(graph.arrSize()), edgeto(graph.arrSize()), on_stack(graph.arrSize()) 36 | { 37 | for (size_t i = 0; i < graph.arrSize(); i++) 38 | marked[i] = on_stack[i] = false; 39 | for (size_t i = 0; i < graph.arrSize(); i++) 40 | { 41 | if (!marked[i]) 42 | dfs(graph, i); 43 | } 44 | } 45 | 46 | bool hasCycle() const { return !sta.empty(); } 47 | stack cycle() const { return sta; } 48 | 49 | private: 50 | void dfs(const Digraph &graph, size_t v) 51 | { 52 | on_stack[v] = true; 53 | marked[v] = true; 54 | 55 | vector vec = graph.adj(v); 56 | for (size_t i = 0; i < vec.size(); i++) 57 | { 58 | if (this->hasCycle()) 59 | return; 60 | else if (!marked[vec[i]]) 61 | { 62 | edgeto[vec[i]] = v; 63 | dfs(graph, vec[i]); 64 | } 65 | else if (on_stack[vec[i]]) 66 | { 67 | for (size_t x = v; x != vec[i]; x = edgeto[x]) 68 | sta.push(x); 69 | sta.push(vec[i]); 70 | sta.push(v); 71 | } 72 | } 73 | on_stack[v] = false; 74 | } 75 | 76 | vector marked; 77 | vector edgeto; 78 | vector on_stack; 79 | stack sta; 80 | }; 81 | 82 | /// 有向图中基于深度优先遍历的顶点排序,保证图中没有有向环 83 | class DepthFirstOrder 84 | { 85 | public: 86 | DepthFirstOrder(const Digraph &graph) : marked(graph.arrSize()) 87 | { 88 | for (size_t i = 0; i < marked.size(); i++) 89 | marked[i] = false; 90 | for (size_t i = 0; i < graph.arrSize(); i++) 91 | { 92 | if (!marked[i]) 93 | dfs(graph, i); 94 | } 95 | } 96 | 97 | vector getPre() const { return pre; } 98 | vector getPost() const { return post; } 99 | stack getReversePost() const { return reverse_post; } 100 | 101 | private: 102 | void dfs(const Digraph &graph, size_t v) 103 | { 104 | marked[v] = true; 105 | pre.push_back(v); 106 | 107 | vector vec = graph.adj(v); 108 | for (size_t i = 0; i < vec.size(); i++) 109 | { 110 | if (!marked[vec[i]]) 111 | dfs(graph, vec[i]); 112 | } 113 | post.push_back(v); 114 | reverse_post.push(v); 115 | } 116 | 117 | vector marked; 118 | vector pre; // 所有顶点的前序排列 119 | vector post; // 所有顶点的后序排列 120 | stack reverse_post; // 所有顶点的逆后序排列 121 | }; 122 | 123 | /// 计算强连通分量的Kosaraju算法 124 | class KosarajuSCC 125 | { 126 | public: 127 | KosarajuSCC(const Digraph &graph) : marked(graph.arrSize()), id(graph.arrSize()), count(0) 128 | { 129 | for (size_t i = 0; i < marked.size(); i++) 130 | marked[i] = false; 131 | 132 | DepthFirstOrder dforder(graph); 133 | stack sta = dforder.getReversePost(); 134 | while (!sta.empty()) 135 | { 136 | size_t v = sta.top(); 137 | sta.pop(); 138 | if (!marked[v]) 139 | { 140 | dfs(graph, v); 141 | count++; 142 | } 143 | } 144 | } 145 | 146 | bool strongConnected(int v, int w) const { return id[v] == id[w]; } 147 | size_t getId(size_t v) const { return id[v]; } 148 | size_t getCount() const { return count; } 149 | 150 | private: 151 | void dfs(const Digraph &graph, size_t v) 152 | { 153 | marked[v] = true; 154 | id[v] = count; 155 | 156 | vector vec = graph.adj(v); 157 | for (size_t i = 0; i < vec.size(); i++) 158 | { 159 | if (!marked[vec[i]]) 160 | dfs(graph, vec[i]); 161 | } 162 | } 163 | 164 | vector marked; 165 | vector id; 166 | size_t count; 167 | }; 168 | 169 | int main(void) 170 | { 171 | Digraph graph(13); 172 | 173 | graph.addEdge(0, 1); graph.addEdge(0, 5); graph.addEdge(0, 6); 174 | graph.addEdge(2, 0); graph.addEdge(2, 3); 175 | graph.addEdge(3, 5); 176 | graph.addEdge(5, 4); 177 | graph.addEdge(6, 4); graph.addEdge(6, 9); 178 | graph.addEdge(7, 6); 179 | graph.addEdge(8, 7); 180 | graph.addEdge(9, 10); graph.addEdge(9, 11); graph.addEdge(9, 12); 181 | graph.addEdge(11, 12); 182 | 183 | cout << graph.vertax() << endl; 184 | cout << graph.edge() << endl; 185 | graph.showDigraph(); 186 | cout << endl; 187 | 188 | DepthFirstOrder dep(graph); 189 | stack sta = dep.getReversePost(); 190 | while (!sta.empty()) 191 | { 192 | cout << sta.top() << " "; 193 | sta.pop(); 194 | } 195 | cout << endl; 196 | 197 | KosarajuSCC kosa(graph); 198 | cout << kosa.getCount() << endl; 199 | 200 | return 0; 201 | } 202 | 203 | 204 | void Digraph::addEdge(size_t a, size_t b) 205 | { 206 | if (!(a < vertax() && b < vertax())) 207 | return; 208 | arr[a].push_back(b); 209 | edges++; 210 | } 211 | 212 | void Digraph::removeEdge(size_t a, size_t b) 213 | { 214 | if (!(a < vertax() && b < vertax())) 215 | return; 216 | 217 | vector::iterator iter = find(arr[a].begin(), arr[a].end(), b); 218 | if (iter != arr[a].end()) 219 | { 220 | arr[a].erase(iter); 221 | edges--; 222 | } 223 | } 224 | 225 | void Digraph::addVertax(size_t v) 226 | { 227 | if (v != arrSize()) 228 | return; 229 | arr.push_back(vector()); 230 | vertaxs++; 231 | } 232 | 233 | void Digraph::removeVertax(size_t v) 234 | { 235 | if (v >= arrSize()) 236 | return; 237 | vector::iterator iter; 238 | 239 | for (size_t i = 0; i < arrSize(); i++) 240 | { 241 | if (i == v) 242 | { 243 | edges -= arr[i].size(); // 减去头部是v的边的个数 244 | arr[i].clear(); 245 | vertaxs--; 246 | } 247 | else 248 | { 249 | iter = find(arr[i].begin(), arr[i].end(), v); 250 | if (iter != arr[i].end()) 251 | { 252 | arr[i].erase(iter); 253 | edges--; 254 | } 255 | } 256 | } 257 | } 258 | 259 | Digraph Digraph::reverse() const 260 | { 261 | Digraph graph(vertax()); 262 | vector vec; 263 | 264 | for (size_t i = 0; i < arrSize(); i++) 265 | { 266 | vec = adj(i); 267 | for (size_t j = 0; j < vec.size(); j++) 268 | { 269 | graph.addEdge(vec[j], i); // 取得该图的反向图 270 | } 271 | } 272 | 273 | return graph; 274 | } 275 | 276 | vector Digraph::adj(size_t v) const 277 | { 278 | if (v < arrSize()) 279 | return arr[v]; 280 | else 281 | vector(); 282 | } 283 | 284 | void Digraph::showAdj(size_t v) const 285 | { 286 | if (v >= arrSize()) 287 | return; 288 | 289 | vector vec = adj(v); 290 | for (size_t i = 0; i < vec.size(); i++) 291 | cout << vec[i] << " "; 292 | cout << endl; 293 | } 294 | 295 | void Digraph::showDigraph() const 296 | { 297 | for (size_t i = 0; i < arr.size(); i++) 298 | { 299 | cout << i << ": "; 300 | showAdj(i); 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /graph/Digraph有向图拓扑排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class Digraph 8 | { 9 | public: 10 | Digraph(size_t nvertax) : arr(nvertax), vertaxs(nvertax), edges(0) {} 11 | void addEdge(size_t a, size_t b); 12 | void removeEdge(size_t a, size_t b); 13 | void addVertax(size_t v); 14 | void removeVertax(size_t v); 15 | Digraph reverse() const; 16 | 17 | vector adj(size_t v) const; 18 | void showAdj(size_t v) const; 19 | void showDigraph() const; 20 | 21 | size_t edge() const { return edges; } 22 | size_t vertax() const { return vertaxs; } 23 | size_t arrSize() const { return arr.size(); } 24 | 25 | private: 26 | vector> arr; // 邻接表 27 | size_t vertaxs; // 顶点个数 28 | size_t edges; // 边的个数 29 | }; 30 | 31 | /// 使用深度优先遍历在有向图中寻找有向环 32 | class DirectedCycle 33 | { 34 | public: 35 | DirectedCycle(const Digraph &graph) : marked(graph.arrSize()), edgeto(graph.arrSize()), on_stack(graph.arrSize()) 36 | { 37 | for (size_t i = 0; i < graph.arrSize(); i++) 38 | marked[i] = on_stack[i] = false; 39 | for (size_t i = 0; i < graph.arrSize(); i++) 40 | { 41 | if (!marked[i]) 42 | dfs(graph, i); 43 | } 44 | } 45 | 46 | bool hasCycle() const { return !sta.empty(); } 47 | stack cycle() const { return sta; } 48 | 49 | private: 50 | void dfs(const Digraph &graph, size_t v) 51 | { 52 | on_stack[v] = true; 53 | marked[v] = true; 54 | 55 | vector vec = graph.adj(v); 56 | for (size_t i = 0; i < vec.size(); i++) 57 | { 58 | if (this->hasCycle()) 59 | return; 60 | else if (!marked[vec[i]]) 61 | { 62 | edgeto[vec[i]] = v; 63 | dfs(graph, vec[i]); 64 | } 65 | else if (on_stack[vec[i]]) 66 | { 67 | for (size_t x = v; x != vec[i]; x = edgeto[x]) 68 | sta.push(x); 69 | sta.push(vec[i]); 70 | sta.push(v); 71 | } 72 | } 73 | on_stack[v] = false; 74 | } 75 | 76 | vector marked; 77 | vector edgeto; 78 | vector on_stack; 79 | stack sta; 80 | }; 81 | 82 | /// 有向图中基于深度优先遍历的顶点排序,保证图中没有有向环 83 | class DepthFirstOrder 84 | { 85 | public: 86 | DepthFirstOrder(const Digraph &graph) : marked(graph.arrSize()) 87 | { 88 | for (size_t i = 0; i < marked.size(); i++) 89 | marked[i] = false; 90 | for (size_t i = 0; i < graph.arrSize(); i++) 91 | { 92 | if (!marked[i]) 93 | dfs(graph, i); 94 | } 95 | } 96 | 97 | vector getPre() const { return pre; } 98 | vector getPost() const { return post; } 99 | stack getReversePost() const { return reverse_post; } 100 | 101 | private: 102 | void dfs(const Digraph &graph, size_t v) 103 | { 104 | marked[v] = true; 105 | pre.push_back(v); 106 | 107 | vector vec = graph.adj(v); 108 | for (size_t i = 0; i < vec.size(); i++) 109 | { 110 | if (!marked[vec[i]]) 111 | dfs(graph, vec[i]); 112 | } 113 | post.push_back(v); 114 | reverse_post.push(v); 115 | } 116 | 117 | vector marked; 118 | vector pre; // 所有顶点的前序排列 119 | vector post; // 所有顶点的后序排列 120 | stack reverse_post; // 所有顶点的逆后序排列 121 | }; 122 | 123 | /// 拓扑排序,借助于DepthFirstOrder来实现,保证图中没有环 124 | class Topological 125 | { 126 | public: 127 | Topological(const Digraph &graph) 128 | { 129 | DepthFirstOrder dfs(graph); 130 | 131 | stack sta = dfs.getReversePost(); 132 | while (!sta.empty()) 133 | { 134 | order.push_back(sta.top()); 135 | sta.pop(); 136 | } 137 | } 138 | 139 | vector getOrder() const { return order; } 140 | 141 | private: 142 | vector order; // 顶点的拓扑顺序 143 | }; 144 | 145 | int main(void) 146 | { 147 | Digraph graph(13); 148 | 149 | graph.addEdge(0, 1); graph.addEdge(0, 5); graph.addEdge(0, 6); 150 | graph.addEdge(2, 0); graph.addEdge(2, 3); 151 | graph.addEdge(3, 5); 152 | graph.addEdge(5, 4); 153 | graph.addEdge(6, 4); graph.addEdge(6, 9); 154 | graph.addEdge(7, 6); 155 | graph.addEdge(8, 7); 156 | graph.addEdge(9, 10); graph.addEdge(9, 11); graph.addEdge(9, 12); 157 | graph.addEdge(11, 12); 158 | 159 | cout << graph.vertax() << endl; 160 | cout << graph.edge() << endl; 161 | graph.showDigraph(); 162 | cout << endl; 163 | 164 | DirectedCycle cycle(graph); 165 | stack sta; 166 | 167 | if (cycle.hasCycle()) 168 | { 169 | cout << "graph has cycle" << endl; 170 | sta = cycle.cycle(); 171 | 172 | while (!sta.empty()) 173 | { 174 | cout << sta.top() << " "; 175 | sta.pop(); 176 | } 177 | cout << endl; 178 | } 179 | else 180 | cout << "graph hasn't cycle" << endl; 181 | 182 | Topological topo(graph); 183 | 184 | vector vec = topo.getOrder(); 185 | for (size_t i = 0; i < vec.size(); i++) 186 | cout << vec[i] << " "; 187 | cout << endl; 188 | 189 | return 0; 190 | } 191 | 192 | 193 | void Digraph::addEdge(size_t a, size_t b) 194 | { 195 | if (!(a < vertax() && b < vertax())) 196 | return; 197 | arr[a].push_back(b); 198 | edges++; 199 | } 200 | 201 | void Digraph::removeEdge(size_t a, size_t b) 202 | { 203 | if (!(a < vertax() && b < vertax())) 204 | return; 205 | 206 | vector::iterator iter = find(arr[a].begin(), arr[a].end(), b); 207 | if (iter != arr[a].end()) 208 | { 209 | arr[a].erase(iter); 210 | edges--; 211 | } 212 | } 213 | 214 | void Digraph::addVertax(size_t v) 215 | { 216 | if (v != arrSize()) 217 | return; 218 | arr.push_back(vector()); 219 | vertaxs++; 220 | } 221 | 222 | void Digraph::removeVertax(size_t v) 223 | { 224 | if (v >= arrSize()) 225 | return; 226 | vector::iterator iter; 227 | 228 | for (size_t i = 0; i < arrSize(); i++) 229 | { 230 | if (i == v) 231 | { 232 | edges -= arr[i].size(); // 减去头部是v的边的个数 233 | arr[i].clear(); 234 | vertaxs--; 235 | } 236 | else 237 | { 238 | iter = find(arr[i].begin(), arr[i].end(), v); 239 | if (iter != arr[i].end()) 240 | { 241 | arr[i].erase(iter); 242 | edges--; 243 | } 244 | } 245 | } 246 | } 247 | 248 | Digraph Digraph::reverse() const 249 | { 250 | Digraph graph(vertax()); 251 | vector vec; 252 | 253 | for (size_t i = 0; i < arrSize(); i++) 254 | { 255 | vec = adj(i); 256 | for (size_t j = 0; j < vec.size(); j++) 257 | { 258 | graph.addEdge(vec[j], i); // 取得该图的反向图 259 | } 260 | } 261 | 262 | return graph; 263 | } 264 | 265 | vector Digraph::adj(size_t v) const 266 | { 267 | if (v < arrSize()) 268 | return arr[v]; 269 | else 270 | vector(); 271 | } 272 | 273 | void Digraph::showAdj(size_t v) const 274 | { 275 | if (v >= arrSize()) 276 | return; 277 | 278 | vector vec = adj(v); 279 | for (size_t i = 0; i < vec.size(); i++) 280 | cout << vec[i] << " "; 281 | cout << endl; 282 | } 283 | 284 | void Digraph::showDigraph() const 285 | { 286 | for (size_t i = 0; i < arr.size(); i++) 287 | { 288 | cout << i << ": "; 289 | showAdj(i); 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /graph/Digraph有向图是否有环.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class Digraph 8 | { 9 | public: 10 | Digraph(size_t nvertax) : arr(nvertax), vertaxs(nvertax), edges(0) {} 11 | void addEdge(size_t a, size_t b); 12 | void removeEdge(size_t a, size_t b); 13 | void addVertax(size_t v); 14 | void removeVertax(size_t v); 15 | Digraph reverse() const; 16 | 17 | vector adj(size_t v) const; 18 | void showAdj(size_t v) const; 19 | void showDigraph() const; 20 | 21 | size_t edge() const { return edges; } 22 | size_t vertax() const { return vertaxs; } 23 | size_t arrSize() const { return arr.size(); } 24 | 25 | private: 26 | vector> arr; // 邻接表 27 | size_t vertaxs; // 顶点个数 28 | size_t edges; // 边的个数 29 | }; 30 | 31 | /// 使用深度优先遍历在有向图中寻找有向环 32 | class DirectedCycle 33 | { 34 | public: 35 | DirectedCycle(const Digraph &graph) : marked(graph.arrSize()), edgeto(graph.arrSize()), on_stack(graph.arrSize()) 36 | { 37 | for (size_t i = 0; i < graph.arrSize(); i++) 38 | marked[i] = on_stack[i] = false; 39 | for (size_t i = 0; i < graph.arrSize(); i++) 40 | { 41 | if (!marked[i]) 42 | dfs(graph, i); 43 | } 44 | } 45 | 46 | bool hasCycle() const { return !sta.empty(); } 47 | stack cycle() const { return sta; } 48 | 49 | private: 50 | void dfs(const Digraph &graph, size_t v) 51 | { 52 | on_stack[v] = true; 53 | marked[v] = true; 54 | 55 | vector vec = graph.adj(v); 56 | for (size_t i = 0; i < vec.size(); i++) 57 | { 58 | if (this->hasCycle()) 59 | return; 60 | else if (!marked[vec[i]]) 61 | { 62 | edgeto[vec[i]] = v; 63 | dfs(graph, vec[i]); 64 | } 65 | else if (on_stack[vec[i]]) 66 | { 67 | for (size_t x = v; x != vec[i]; x = edgeto[x]) 68 | sta.push(x); 69 | sta.push(vec[i]); 70 | sta.push(v); 71 | } 72 | } 73 | on_stack[v] = false; 74 | } 75 | 76 | vector marked; 77 | vector edgeto; 78 | vector on_stack; 79 | stack sta; 80 | }; 81 | 82 | int main(void) 83 | { 84 | Digraph graph(4); 85 | 86 | graph.addEdge(0, 1); 87 | graph.addEdge(1, 2); 88 | graph.addEdge(2, 3); 89 | graph.addEdge(3, 1); 90 | 91 | cout << graph.vertax() << endl; 92 | cout << graph.edge() << endl; 93 | graph.showDigraph(); 94 | cout << endl; 95 | 96 | DirectedCycle cycle(graph); 97 | stack sta; 98 | 99 | if (cycle.hasCycle()) 100 | { 101 | cout << "graph has cycle" << endl; 102 | sta = cycle.cycle(); 103 | 104 | while (!sta.empty()) 105 | { 106 | cout << sta.top() << " "; 107 | sta.pop(); 108 | } 109 | cout << endl; 110 | } 111 | else 112 | cout << "graph hasn't cycle" << endl; 113 | 114 | return 0; 115 | } 116 | 117 | 118 | void Digraph::addEdge(size_t a, size_t b) 119 | { 120 | if (!(a < vertax() && b < vertax())) 121 | return; 122 | arr[a].push_back(b); 123 | edges++; 124 | } 125 | 126 | void Digraph::removeEdge(size_t a, size_t b) 127 | { 128 | if (!(a < vertax() && b < vertax())) 129 | return; 130 | 131 | vector::iterator iter = find(arr[a].begin(), arr[a].end(), b); 132 | if (iter != arr[a].end()) 133 | { 134 | arr[a].erase(iter); 135 | edges--; 136 | } 137 | } 138 | 139 | void Digraph::addVertax(size_t v) 140 | { 141 | if (v != arrSize()) 142 | return; 143 | arr.push_back(vector()); 144 | vertaxs++; 145 | } 146 | 147 | void Digraph::removeVertax(size_t v) 148 | { 149 | if (v >= arrSize()) 150 | return; 151 | vector::iterator iter; 152 | 153 | for (size_t i = 0; i < arrSize(); i++) 154 | { 155 | if (i == v) 156 | { 157 | edges -= arr[i].size(); // 减去头部是v的边的个数 158 | arr[i].clear(); 159 | vertaxs--; 160 | } 161 | else 162 | { 163 | iter = find(arr[i].begin(), arr[i].end(), v); 164 | if (iter != arr[i].end()) 165 | { 166 | arr[i].erase(iter); 167 | edges--; 168 | } 169 | } 170 | } 171 | } 172 | 173 | Digraph Digraph::reverse() const 174 | { 175 | Digraph graph(vertax()); 176 | vector vec; 177 | 178 | for (size_t i = 0; i < arrSize(); i++) 179 | { 180 | vec = adj(i); 181 | for (size_t j = 0; j < vec.size(); j++) 182 | { 183 | graph.addEdge(vec[j], i); // 取得该图的反向图 184 | } 185 | } 186 | 187 | return graph; 188 | } 189 | 190 | vector Digraph::adj(size_t v) const 191 | { 192 | if (v < arrSize()) 193 | return arr[v]; 194 | else 195 | vector(); 196 | } 197 | 198 | void Digraph::showAdj(size_t v) const 199 | { 200 | if (v >= arrSize()) 201 | return; 202 | 203 | vector vec = adj(v); 204 | for (size_t i = 0; i < vec.size(); i++) 205 | cout << vec[i] << " "; 206 | cout << endl; 207 | } 208 | 209 | void Digraph::showDigraph() const 210 | { 211 | for (size_t i = 0; i < arr.size(); i++) 212 | { 213 | cout << i << ": "; 214 | showAdj(i); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /graph/Digraph有向图顶点排序.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class Digraph 8 | { 9 | public: 10 | Digraph(size_t nvertax) : arr(nvertax), vertaxs(nvertax), edges(0) {} 11 | void addEdge(size_t a, size_t b); 12 | void removeEdge(size_t a, size_t b); 13 | void addVertax(size_t v); 14 | void removeVertax(size_t v); 15 | Digraph reverse() const; 16 | 17 | vector adj(size_t v) const; 18 | void showAdj(size_t v) const; 19 | void showDigraph() const; 20 | 21 | size_t edge() const { return edges; } 22 | size_t vertax() const { return vertaxs; } 23 | size_t arrSize() const { return arr.size(); } 24 | 25 | private: 26 | vector> arr; // 邻接表 27 | size_t vertaxs; // 顶点个数 28 | size_t edges; // 边的个数 29 | }; 30 | 31 | /// 使用深度优先遍历在有向图中寻找有向环 32 | class DirectedCycle 33 | { 34 | public: 35 | DirectedCycle(const Digraph &graph) : marked(graph.arrSize()), edgeto(graph.arrSize()), on_stack(graph.arrSize()) 36 | { 37 | for (size_t i = 0; i < graph.arrSize(); i++) 38 | marked[i] = on_stack[i] = false; 39 | for (size_t i = 0; i < graph.arrSize(); i++) 40 | { 41 | if (!marked[i]) 42 | dfs(graph, i); 43 | } 44 | } 45 | 46 | bool hasCycle() const { return !sta.empty(); } 47 | stack cycle() const { return sta; } 48 | 49 | private: 50 | void dfs(const Digraph &graph, size_t v) 51 | { 52 | on_stack[v] = true; 53 | marked[v] = true; 54 | 55 | vector vec = graph.adj(v); 56 | for (size_t i = 0; i < vec.size(); i++) 57 | { 58 | if (this->hasCycle()) 59 | return; 60 | else if (!marked[vec[i]]) 61 | { 62 | edgeto[vec[i]] = v; 63 | dfs(graph, vec[i]); 64 | } 65 | else if (on_stack[vec[i]]) 66 | { 67 | for (size_t x = v; x != vec[i]; x = edgeto[x]) 68 | sta.push(x); 69 | sta.push(vec[i]); 70 | sta.push(v); 71 | } 72 | } 73 | on_stack[v] = false; 74 | } 75 | 76 | vector marked; 77 | vector edgeto; 78 | vector on_stack; 79 | stack sta; 80 | }; 81 | 82 | /// 有向图中基于深度优先遍历的顶点排序,保证图中没有有向环 83 | class DepthFirstOrder 84 | { 85 | public: 86 | DepthFirstOrder(const Digraph &graph) : marked(graph.arrSize()) 87 | { 88 | for (size_t i = 0; i < marked.size(); i++) 89 | marked[i] = false; 90 | for (size_t i = 0; i < graph.arrSize(); i++) 91 | { 92 | if (!marked[i]) 93 | dfs(graph, i); 94 | } 95 | } 96 | 97 | vector getPre() const { return pre; } 98 | vector getPost() const { return post; } 99 | stack getReversePost() const { return reverse_post; } 100 | 101 | private: 102 | void dfs(const Digraph &graph, size_t v) 103 | { 104 | marked[v] = true; 105 | pre.push_back(v); 106 | 107 | vector vec = graph.adj(v); 108 | for (size_t i = 0; i < vec.size(); i++) 109 | { 110 | if (!marked[vec[i]]) 111 | dfs(graph, vec[i]); 112 | } 113 | post.push_back(v); 114 | reverse_post.push(v); 115 | } 116 | 117 | vector marked; 118 | vector pre; // 所有顶点的前序排列 119 | vector post; // 所有顶点的后序排列 120 | stack reverse_post; // 所有顶点的逆后序排列 121 | }; 122 | 123 | int main(void) 124 | { 125 | Digraph graph(13); 126 | 127 | graph.addEdge(0, 1); graph.addEdge(0, 5); graph.addEdge(0, 6); 128 | graph.addEdge(2, 0); graph.addEdge(2, 3); 129 | graph.addEdge(3, 5); 130 | graph.addEdge(5, 4); 131 | graph.addEdge(6, 4); graph.addEdge(6, 9); 132 | graph.addEdge(7, 6); 133 | graph.addEdge(8, 7); 134 | graph.addEdge(9, 10); graph.addEdge(9, 11); graph.addEdge(9, 12); 135 | graph.addEdge(11, 12); 136 | 137 | cout << graph.vertax() << endl; 138 | cout << graph.edge() << endl; 139 | graph.showDigraph(); 140 | cout << endl; 141 | 142 | DirectedCycle cycle(graph); 143 | stack sta; 144 | 145 | if (cycle.hasCycle()) 146 | { 147 | cout << "graph has cycle" << endl; 148 | sta = cycle.cycle(); 149 | 150 | while (!sta.empty()) 151 | { 152 | cout << sta.top() << " "; 153 | sta.pop(); 154 | } 155 | cout << endl; 156 | } 157 | else 158 | cout << "graph hasn't cycle" << endl; 159 | 160 | DepthFirstOrder order(graph); 161 | 162 | cout << "pre: "; 163 | vector vec = order.getPre(); 164 | for (size_t i = 0; i < vec.size(); i++) 165 | cout << vec[i] << " "; 166 | cout << endl; 167 | 168 | cout << "post: "; 169 | vec = order.getPost(); 170 | for (size_t i = 0; i < vec.size(); i++) 171 | cout << vec[i] << " "; 172 | cout << endl; 173 | 174 | cout << "reverse_post: "; 175 | sta = order.getReversePost(); 176 | while (sta.size()) 177 | { 178 | cout << sta.top() << " "; 179 | sta.pop(); 180 | } 181 | cout << endl; 182 | 183 | return 0; 184 | } 185 | 186 | 187 | void Digraph::addEdge(size_t a, size_t b) 188 | { 189 | if (!(a < vertax() && b < vertax())) 190 | return; 191 | arr[a].push_back(b); 192 | edges++; 193 | } 194 | 195 | void Digraph::removeEdge(size_t a, size_t b) 196 | { 197 | if (!(a < vertax() && b < vertax())) 198 | return; 199 | 200 | vector::iterator iter = find(arr[a].begin(), arr[a].end(), b); 201 | if (iter != arr[a].end()) 202 | { 203 | arr[a].erase(iter); 204 | edges--; 205 | } 206 | } 207 | 208 | void Digraph::addVertax(size_t v) 209 | { 210 | if (v != arrSize()) 211 | return; 212 | arr.push_back(vector()); 213 | vertaxs++; 214 | } 215 | 216 | void Digraph::removeVertax(size_t v) 217 | { 218 | if (v >= arrSize()) 219 | return; 220 | vector::iterator iter; 221 | 222 | for (size_t i = 0; i < arrSize(); i++) 223 | { 224 | if (i == v) 225 | { 226 | edges -= arr[i].size(); // 减去头部是v的边的个数 227 | arr[i].clear(); 228 | vertaxs--; 229 | } 230 | else 231 | { 232 | iter = find(arr[i].begin(), arr[i].end(), v); 233 | if (iter != arr[i].end()) 234 | { 235 | arr[i].erase(iter); 236 | edges--; 237 | } 238 | } 239 | } 240 | } 241 | 242 | Digraph Digraph::reverse() const 243 | { 244 | Digraph graph(vertax()); 245 | vector vec; 246 | 247 | for (size_t i = 0; i < arrSize(); i++) 248 | { 249 | vec = adj(i); 250 | for (size_t j = 0; j < vec.size(); j++) 251 | { 252 | graph.addEdge(vec[j], i); // 取得该图的反向图 253 | } 254 | } 255 | 256 | return graph; 257 | } 258 | 259 | vector Digraph::adj(size_t v) const 260 | { 261 | if (v < arrSize()) 262 | return arr[v]; 263 | else 264 | vector(); 265 | } 266 | 267 | void Digraph::showAdj(size_t v) const 268 | { 269 | if (v >= arrSize()) 270 | return; 271 | 272 | vector vec = adj(v); 273 | for (size_t i = 0; i < vec.size(); i++) 274 | cout << vec[i] << " "; 275 | cout << endl; 276 | } 277 | 278 | void Digraph::showDigraph() const 279 | { 280 | for (size_t i = 0; i < arr.size(); i++) 281 | { 282 | cout << i << ": "; 283 | showAdj(i); 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /graph/Graph广度优先搜索.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class Graph 8 | { 9 | public: 10 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 11 | void addEdge(size_t a, size_t b); 12 | void removeEdge(size_t a, size_t b); 13 | void addVertax(size_t n); 14 | void removeVertax(size_t n); 15 | 16 | vector adj(size_t n) const; 17 | void showAdj(size_t n) const; 18 | void showGraph() const; 19 | 20 | size_t edge() const { return edges; } 21 | size_t vertax() const { return vertaxs; } 22 | 23 | private: 24 | vector> arr; 25 | size_t edges; 26 | size_t vertaxs; 27 | }; 28 | 29 | /// 广度优先遍历,以节点s开始广度优先遍历 30 | class BreadthFirstSearch 31 | { 32 | public: 33 | BreadthFirstSearch(Graph &graph, size_t s) : marked(graph.vertax()), count(0) 34 | { 35 | for (size_t i = 0; i < marked.size(); i++) 36 | marked[i] = false; 37 | queue que; 38 | 39 | que.push(s); 40 | marked[s] = true; 41 | count++; 42 | while (!que.empty()) 43 | { 44 | size_t v = que.front(); 45 | que.pop(); 46 | 47 | vector vec = graph.adj(v); 48 | for (size_t i = 0; i < vec.size(); i++) 49 | { 50 | if (!marked[vec[i]]) 51 | { 52 | que.push(vec[i]); 53 | marked[vec[i]] = true; 54 | count++; 55 | } 56 | } 57 | } 58 | } 59 | 60 | bool getMarked(size_t v) const { return marked[v]; } 61 | size_t getCount() const { return count; } 62 | 63 | private: 64 | vector marked; // 遍历标志数组 65 | size_t count; // 节点个数 66 | }; 67 | 68 | int main(void) 69 | { 70 | Graph graph(5); 71 | 72 | graph.addEdge(0, 1); 73 | graph.addEdge(3, 4); 74 | graph.addEdge(1, 3); 75 | graph.addEdge(0, 4); 76 | graph.addEdge(2, 3); 77 | graph.addEdge(0, 2); 78 | 79 | BreadthFirstSearch bfs(graph, 0); 80 | 81 | cout << bfs.getCount() << endl; 82 | 83 | return 0; 84 | } 85 | 86 | void Graph::addEdge(size_t a, size_t b) 87 | { 88 | if (!(a < arr.size() && b < arr.size())) 89 | return; 90 | 91 | arr[a].push_back(b); 92 | arr[b].push_back(a); 93 | edges++; // 无向图 94 | } 95 | 96 | void Graph::removeEdge(size_t a, size_t b) 97 | { 98 | if (!(a < arr.size() && b < arr.size())) 99 | return; 100 | 101 | vector::iterator iter; 102 | iter = find(arr[a].begin(), arr[a].end(), b); 103 | if (iter != arr[a].end()) 104 | { 105 | arr[a].erase(iter); 106 | //edges--; 107 | } 108 | 109 | iter = find(arr[b].begin(), arr[b].end(), a); 110 | if (iter != arr[b].end()) 111 | { 112 | arr[b].erase(iter); 113 | edges--; 114 | } 115 | } 116 | void Graph::addVertax(size_t n) 117 | { 118 | if (n != arr.size()) 119 | return; 120 | 121 | arr.push_back(vector()); 122 | vertaxs++; 123 | } 124 | 125 | void Graph::removeVertax(size_t n) 126 | { 127 | if (n >= arr.size()) 128 | return; 129 | 130 | while (!arr[n].empty()) 131 | removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了 132 | //arr.erase(arr.begin() + n); 133 | vertaxs--; 134 | } 135 | 136 | vector Graph::adj(size_t n) const 137 | { 138 | if (n < arr.size()) 139 | return arr[n]; 140 | else 141 | return vector(); 142 | 143 | } 144 | 145 | void Graph::showAdj(size_t n) const 146 | { 147 | if (n >= arr.size()) 148 | return; 149 | 150 | vector vec; 151 | vec = adj(n); 152 | for (size_t i = 0; i < vec.size(); i++) 153 | cout << vec[i] << " "; 154 | cout << endl; 155 | } 156 | 157 | void Graph::showGraph() const 158 | { 159 | for (size_t i = 0; i < arr.size(); i++) 160 | { 161 | cout << i << ": "; 162 | showAdj(i); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /graph/Graph广度优先搜索查找图中路径.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | class Graph 9 | { 10 | public: 11 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 12 | void addEdge(size_t a, size_t b); 13 | void removeEdge(size_t a, size_t b); 14 | void addVertax(size_t n); 15 | void removeVertax(size_t n); 16 | 17 | vector adj(size_t n) const; 18 | void showAdj(size_t n) const; 19 | void showGraph() const; 20 | 21 | size_t edge() const { return edges; } 22 | size_t vertax() const { return vertaxs; } 23 | 24 | private: 25 | vector> arr; 26 | size_t edges; 27 | size_t vertaxs; 28 | }; 29 | 30 | /// 广度优先搜索图中从一个顶点到其他所有顶点路径 31 | class BfsPaths 32 | { 33 | public: 34 | BfsPaths(const Graph &graph, size_t _start) : start(_start), paths(graph.vertax()), marked(graph.vertax()) 35 | { 36 | for (int i = 0; i < graph.vertax(); i++) 37 | marked[i] = false; 38 | bfs(graph); 39 | } 40 | 41 | stack pathTo(size_t v) 42 | { 43 | stack sta; // 这里用栈保存结果更好 44 | 45 | for (size_t x = v; x != start; x = paths[x]) 46 | sta.push(x); 47 | sta.push(start); 48 | return sta; 49 | } 50 | void printPathTo(size_t v) 51 | { 52 | stack sta = pathTo(v); 53 | cout << start << "->" << v << ": "; 54 | while (!sta.empty()) 55 | { 56 | cout << sta.top() << " "; 57 | sta.pop(); 58 | } 59 | cout << endl; 60 | } 61 | 62 | private: 63 | void bfs(const Graph &graph) 64 | { 65 | queue que; 66 | vector vec; 67 | 68 | paths[start] = start; 69 | que.push(start); 70 | marked[start] = true; 71 | while (!que.empty()) 72 | { 73 | size_t v = que.front(); 74 | que.pop(); 75 | vec = graph.adj(v); 76 | 77 | for (int i = 0; i < vec.size(); i++) 78 | { 79 | if (!marked[vec[i]]) 80 | { 81 | paths[vec[i]] = v; 82 | que.push(vec[i]); 83 | marked[vec[i]] = true; 84 | } 85 | } 86 | } 87 | } 88 | 89 | size_t start; // 起点 90 | vector paths; // 到大该顶点已知路径上的最后一个顶点 91 | vector marked; // 到达该顶点的最短路径已知吗? 92 | }; 93 | 94 | int main(void) 95 | { 96 | Graph graph(5); 97 | 98 | graph.addEdge(0, 1); 99 | graph.addEdge(0, 2); 100 | graph.addEdge(1, 3); 101 | graph.addEdge(2, 3); 102 | graph.addEdge(3, 4); 103 | graph.addEdge(4, 0); 104 | 105 | BfsPaths path(graph, 0); 106 | 107 | path.printPathTo(1); 108 | path.printPathTo(2); 109 | path.printPathTo(3); 110 | path.printPathTo(4); 111 | 112 | return 0; 113 | } 114 | 115 | void Graph::addEdge(size_t a, size_t b) 116 | { 117 | if (!(a < arr.size() && b < arr.size())) 118 | return; 119 | 120 | arr[a].push_back(b); 121 | arr[b].push_back(a); 122 | edges++; // 无向图 123 | } 124 | 125 | void Graph::removeEdge(size_t a, size_t b) 126 | { 127 | if (!(a < arr.size() && b < arr.size())) 128 | return; 129 | 130 | vector::iterator iter; 131 | iter = find(arr[a].begin(), arr[a].end(), b); 132 | if (iter != arr[a].end()) 133 | { 134 | arr[a].erase(iter); 135 | //edges--; 136 | } 137 | 138 | iter = find(arr[b].begin(), arr[b].end(), a); 139 | if (iter != arr[b].end()) 140 | { 141 | arr[b].erase(iter); 142 | edges--; 143 | } 144 | } 145 | void Graph::addVertax(size_t n) 146 | { 147 | if (n != arr.size()) 148 | return; 149 | 150 | arr.push_back(vector()); 151 | vertaxs++; 152 | } 153 | 154 | void Graph::removeVertax(size_t n) 155 | { 156 | if (n >= arr.size()) 157 | return; 158 | 159 | while (!arr[n].empty()) 160 | removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了 161 | //arr.erase(arr.begin() + n); 162 | vertaxs--; 163 | } 164 | 165 | vector Graph::adj(size_t n) const 166 | { 167 | if (n < arr.size()) 168 | return arr[n]; 169 | else 170 | return vector(); 171 | 172 | } 173 | 174 | void Graph::showAdj(size_t n) const 175 | { 176 | if (n >= arr.size()) 177 | return; 178 | 179 | vector vec; 180 | vec = adj(n); 181 | for (size_t i = 0; i < vec.size(); i++) 182 | cout << vec[i] << " "; 183 | cout << endl; 184 | } 185 | 186 | void Graph::showGraph() const 187 | { 188 | for (size_t i = 0; i < arr.size(); i++) 189 | { 190 | cout << i << ": "; 191 | showAdj(i); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /graph/Graph数据类型.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | class Graph 7 | { 8 | public: 9 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 10 | void addEdge(size_t a, size_t b); 11 | void removeEdge(size_t a, size_t b); 12 | void addVertax(size_t n); 13 | void removeVertax(size_t n); 14 | 15 | vector adj(size_t n) const; 16 | void showAdj(size_t n) const; 17 | void showGraph() const; 18 | 19 | size_t edge() const { return edges; } 20 | size_t vertax() const { return vertaxs; } 21 | 22 | private: 23 | vector> arr; 24 | size_t edges; 25 | size_t vertaxs; 26 | }; 27 | 28 | int main(void) 29 | { 30 | Graph graph(5); 31 | 32 | graph.addEdge(0, 1); 33 | graph.addEdge(3, 4); 34 | graph.addEdge(1, 3); 35 | graph.addEdge(0, 4); 36 | graph.addEdge(2, 3); 37 | graph.addEdge(0, 2); 38 | 39 | cout << graph.vertax() << endl; 40 | cout << graph.edge() << endl; 41 | graph.showGraph(); 42 | 43 | graph.removeEdge(0, 4); 44 | cout << endl; 45 | cout << graph.vertax() << endl; 46 | cout << graph.edge() << endl; 47 | graph.showGraph(); 48 | 49 | graph.addVertax(5); 50 | cout << endl; 51 | cout << graph.vertax() << endl; 52 | cout << graph.edge() << endl; 53 | graph.showGraph(); 54 | 55 | graph.removeVertax(3); 56 | cout << endl; 57 | cout << graph.vertax() << endl; 58 | cout << graph.edge() << endl; 59 | graph.showGraph(); 60 | 61 | return 0; 62 | } 63 | 64 | void Graph::addEdge(size_t a, size_t b) 65 | { 66 | if (!(a < arr.size() && b < arr.size())) 67 | return; 68 | 69 | arr[a].push_back(b); 70 | arr[b].push_back(a); 71 | edges++; // 无向图 72 | } 73 | 74 | void Graph::removeEdge(size_t a, size_t b) 75 | { 76 | if (!(a < arr.size() && b < arr.size())) 77 | return; 78 | 79 | vector::iterator iter; 80 | iter = find(arr[a].begin(), arr[a].end(), b); 81 | if (iter != arr[a].end()) 82 | { 83 | arr[a].erase(iter); 84 | //edges--; 85 | } 86 | 87 | iter = find(arr[b].begin(), arr[b].end(), a); 88 | if (iter != arr[b].end()) 89 | { 90 | arr[b].erase(iter); 91 | edges--; 92 | } 93 | } 94 | void Graph::addVertax(size_t n) 95 | { 96 | if (n != arr.size()) 97 | return; 98 | 99 | arr.push_back(vector()); 100 | vertaxs++; 101 | } 102 | 103 | void Graph::removeVertax(size_t n) 104 | { 105 | if (n >= arr.size()) 106 | return; 107 | 108 | while (!arr[n].empty()) 109 | removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了 110 | //arr.erase(arr.begin() + n); 111 | vertaxs--; 112 | } 113 | 114 | vector Graph::adj(size_t n) const 115 | { 116 | if (n < arr.size()) 117 | return arr[n]; 118 | else 119 | return vector(); 120 | 121 | } 122 | 123 | void Graph::showAdj(size_t n) const 124 | { 125 | if (n >= arr.size()) 126 | return; 127 | 128 | vector vec; 129 | vec = adj(n); 130 | for (size_t i = 0; i < vec.size(); i++) 131 | cout << vec[i] << " "; 132 | cout << endl; 133 | } 134 | 135 | void Graph::showGraph() const 136 | { 137 | for (size_t i = 0; i < arr.size(); i++) 138 | { 139 | cout << i << ": "; 140 | showAdj(i); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /graph/Graph数据结构.java: -------------------------------------------------------------------------------- 1 | package graph; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 有向图 8 | */ 9 | public class Graph { 10 | 11 | // ---------------------------------- Instance Variable 12 | 13 | // 邻接表 14 | private List> array; 15 | 16 | // ---------------------------------- Constructors 17 | 18 | public Graph() { 19 | this(8); 20 | } 21 | 22 | public Graph(int size) { 23 | if (size <= 0) { 24 | size = 8; 25 | } 26 | 27 | array = new ArrayList<>(size); 28 | for (int i = 0; i < size; i++) { 29 | array.add(new ArrayList<>()); 30 | } 31 | } 32 | 33 | // ---------------------------------- Public Methods 34 | 35 | // 返回顶点个数 36 | public int getVertaxs() { 37 | return array.size(); 38 | } 39 | 40 | // 往有向图中添加边(a, b),方向 a -> b 41 | public void add(int a, int b) { 42 | if (a >= array.size() || b >= array.size()) { 43 | return; 44 | } 45 | 46 | array.get(a).add(b); 47 | } 48 | 49 | // 从图中移除边(a, b),方向 a -> b 50 | public void remove(int a, int b) { 51 | if (a >= array.size() || b >= array.size()) { 52 | return; 53 | } 54 | 55 | array.get(a).remove(Integer.valueOf(b)); 56 | } 57 | 58 | /** 59 | * 返回某个顶点关联的所有顶点 60 | * 61 | * 注意:返回的是邻接表的引用,进行通过该引用进行修改操作 62 | */ 63 | public List adj(int a) { 64 | if (a >= array.size()) { 65 | return new ArrayList<>(); 66 | } 67 | 68 | return array.get(a); 69 | } 70 | 71 | // 有向图中是否包含边(a, b),方向 a -> b 72 | public boolean contains(int a, int b) { 73 | if (a >= array.size() || b >= array.size()) { 74 | return false; 75 | } 76 | 77 | return array.get(a).contains(b); 78 | } 79 | 80 | @Override 81 | public String toString() { 82 | StringBuffer buffer = new StringBuffer(); 83 | 84 | for (int i = 0; i < array.size(); i++) { 85 | List ele = array.get(i); 86 | buffer.append(i + ": "); 87 | for (Integer node : ele) { 88 | buffer.append(node + " "); 89 | } 90 | buffer.append("\n"); 91 | } 92 | return buffer.toString(); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /graph/Graph深度优先搜索.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 深度优先搜索使用递归来实现的,在访问其中一个顶点时,将它标记为已访问,递归地访问它的所有没有被标记的邻居节点。 3 | */ 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | class Graph 10 | { 11 | public: 12 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 13 | void addEdge(size_t a, size_t b); 14 | void removeEdge(size_t a, size_t b); 15 | void addVertax(size_t n); 16 | void removeVertax(size_t n); 17 | 18 | vector adj(size_t n) const; 19 | void showAdj(size_t n) const; 20 | void showGraph() const; 21 | 22 | size_t edge() const { return edges; } 23 | size_t vertax() const { return vertaxs; } 24 | 25 | private: 26 | vector> arr; 27 | size_t edges; 28 | size_t vertaxs; 29 | }; 30 | 31 | /// 深度优先遍历,以节点s开始深度优先遍历 32 | class DepthFirstSearch 33 | { 34 | public: 35 | DepthFirstSearch(Graph &graph, size_t s) : marked(graph.vertax()), count(0) 36 | { 37 | for (size_t i = 0; i < marked.size(); i++) 38 | marked[i] = false; 39 | dfs(graph, s); 40 | } 41 | 42 | bool getMarked(size_t v) const { return marked[v]; } 43 | size_t getCount() const { return count; } 44 | 45 | private: 46 | vector marked; // 遍历标志数组 47 | size_t count; // 节点个数 48 | 49 | void dfs(Graph &graph, size_t v) 50 | { 51 | marked[v] = true; 52 | count++; 53 | 54 | vector vec = graph.adj(v); 55 | for (size_t i = 0; i < vec.size(); i++) 56 | { 57 | if (!marked[vec[i]]) 58 | dfs(graph, vec[i]); 59 | } 60 | } 61 | }; 62 | 63 | int main(void) 64 | { 65 | Graph graph(5); 66 | 67 | graph.addEdge(0, 1); 68 | graph.addEdge(3, 4); 69 | graph.addEdge(1, 3); 70 | graph.addEdge(0, 4); 71 | graph.addEdge(2, 3); 72 | graph.addEdge(0, 2); 73 | 74 | cout << graph.vertax() << endl; 75 | cout << graph.edge() << endl; 76 | graph.showGraph(); 77 | cout << endl; 78 | 79 | DepthFirstSearch dfs(graph, 0); 80 | 81 | cout << dfs.getCount() << endl; 82 | 83 | return 0; 84 | } 85 | 86 | void Graph::addEdge(size_t a, size_t b) 87 | { 88 | if (!(a < arr.size() && b < arr.size())) 89 | return; 90 | 91 | arr[a].push_back(b); 92 | arr[b].push_back(a); 93 | edges++; // 无向图 94 | } 95 | 96 | void Graph::removeEdge(size_t a, size_t b) 97 | { 98 | if (!(a < arr.size() && b < arr.size())) 99 | return; 100 | 101 | vector::iterator iter; 102 | iter = find(arr[a].begin(), arr[a].end(), b); 103 | if (iter != arr[a].end()) 104 | { 105 | arr[a].erase(iter); 106 | //edges--; 107 | } 108 | 109 | iter = find(arr[b].begin(), arr[b].end(), a); 110 | if (iter != arr[b].end()) 111 | { 112 | arr[b].erase(iter); 113 | edges--; 114 | } 115 | } 116 | void Graph::addVertax(size_t n) 117 | { 118 | if (n != arr.size()) 119 | return; 120 | 121 | arr.push_back(vector()); 122 | vertaxs++; 123 | } 124 | 125 | void Graph::removeVertax(size_t n) 126 | { 127 | if (n >= arr.size()) 128 | return; 129 | 130 | while (!arr[n].empty()) 131 | removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了 132 | //arr.erase(arr.begin() + n); 133 | vertaxs--; 134 | } 135 | 136 | vector Graph::adj(size_t n) const 137 | { 138 | if (n < arr.size()) 139 | return arr[n]; 140 | else 141 | return vector(); 142 | 143 | } 144 | 145 | void Graph::showAdj(size_t n) const 146 | { 147 | if (n >= arr.size()) 148 | return; 149 | 150 | vector vec; 151 | vec = adj(n); 152 | for (size_t i = 0; i < vec.size(); i++) 153 | cout << vec[i] << " "; 154 | cout << endl; 155 | } 156 | 157 | void Graph::showGraph() const 158 | { 159 | for (size_t i = 0; i < arr.size(); i++) 160 | { 161 | cout << i << ": "; 162 | showAdj(i); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /graph/Graph深度优先搜索判断是否是二分图.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | //#include 5 | #include 6 | using namespace std; 7 | 8 | class Graph 9 | { 10 | public: 11 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 12 | void addEdge(size_t a, size_t b); 13 | void removeEdge(size_t a, size_t b); 14 | void addVertax(size_t n); 15 | void removeVertax(size_t n); 16 | 17 | vector adj(size_t n) const; 18 | void showAdj(size_t n) const; 19 | void showGraph() const; 20 | 21 | size_t edge() const { return edges; } 22 | size_t vertax() const { return vertaxs; } 23 | 24 | private: 25 | vector> arr; 26 | size_t edges; 27 | size_t vertaxs; 28 | }; 29 | 30 | /// 使用深度优先遍历判断是否是二分图(双色问题,图中任意一条边的两个端点的颜色都不相同) 31 | class TwoColor 32 | { 33 | public: 34 | TwoColor(const Graph &graph) : marked(graph.vertax()), color(graph.vertax()), is_twocolor(false) 35 | { 36 | for (size_t i = 0; i < graph.vertax(); i++) 37 | marked[i] = color[i] = false; 38 | for (size_t i = 0; i < graph.vertax(); i++) 39 | { 40 | if (!marked[i]) 41 | dfs(graph, i); 42 | } 43 | } 44 | 45 | bool isTwoColor() const { return is_twocolor; } 46 | 47 | private: 48 | void dfs(const Graph &graph, size_t v) 49 | { 50 | marked[v] = true; 51 | 52 | vector vec = graph.adj(v); 53 | for (size_t i = 0; i < vec.size(); i++) 54 | { 55 | if (!marked[vec[i]]) 56 | { 57 | color[vec[i]] = !color[vec[i]]; 58 | dfs(graph, vec[i]); 59 | } 60 | else if (color[vec[i]] == color[v]) 61 | { 62 | is_twocolor = true; 63 | } 64 | } 65 | } 66 | 67 | vector marked; 68 | vector color; 69 | bool is_twocolor; 70 | }; 71 | 72 | int main(void) 73 | { 74 | Graph graph(3); 75 | 76 | graph.addEdge(0, 1); 77 | graph.addEdge(0, 2); 78 | //graph.addEdge(1, 2); // 取消注释就不是二分图了 79 | 80 | cout << "vertax: " << graph.vertax() << endl; 81 | cout << "edge: " << graph.edge() << endl; 82 | graph.showGraph(); 83 | cout << endl; 84 | 85 | TwoColor twoColor(graph); 86 | 87 | cout << "twoColor.isTwoColor(): "; 88 | if (twoColor.isTwoColor()) 89 | cout << "true" << endl; 90 | else 91 | cout << "false" << endl; 92 | 93 | return 0; 94 | } 95 | 96 | void Graph::addEdge(size_t a, size_t b) 97 | { 98 | if (!(a < arr.size() && b < arr.size())) 99 | return; 100 | 101 | arr[a].push_back(b); 102 | arr[b].push_back(a); 103 | edges++; // 无向图 104 | } 105 | 106 | void Graph::removeEdge(size_t a, size_t b) 107 | { 108 | if (!(a < arr.size() && b < arr.size())) 109 | return; 110 | 111 | vector::iterator iter; 112 | iter = find(arr[a].begin(), arr[a].end(), b); 113 | if (iter != arr[a].end()) 114 | { 115 | arr[a].erase(iter); 116 | //edges--; 117 | } 118 | 119 | iter = find(arr[b].begin(), arr[b].end(), a); 120 | if (iter != arr[b].end()) 121 | { 122 | arr[b].erase(iter); 123 | edges--; 124 | } 125 | } 126 | void Graph::addVertax(size_t n) 127 | { 128 | if (n != arr.size()) 129 | return; 130 | 131 | arr.push_back(vector()); 132 | vertaxs++; 133 | } 134 | 135 | void Graph::removeVertax(size_t n) 136 | { 137 | if (n >= arr.size()) 138 | return; 139 | 140 | while (!arr[n].empty()) 141 | removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了 142 | //arr.erase(arr.begin() + n); 143 | vertaxs--; 144 | } 145 | 146 | vector Graph::adj(size_t n) const 147 | { 148 | if (n < arr.size()) 149 | return arr[n]; 150 | else 151 | return vector(); 152 | 153 | } 154 | 155 | void Graph::showAdj(size_t n) const 156 | { 157 | if (n >= arr.size()) 158 | return; 159 | 160 | vector vec; 161 | vec = adj(n); 162 | for (size_t i = 0; i < vec.size(); i++) 163 | cout << vec[i] << " "; 164 | cout << endl; 165 | } 166 | 167 | void Graph::showGraph() const 168 | { 169 | for (size_t i = 0; i < arr.size(); i++) 170 | { 171 | cout << i << ": "; 172 | showAdj(i); 173 | } 174 | } -------------------------------------------------------------------------------- /graph/Graph深度优先搜索判断是否是无环图.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | //#include 5 | #include 6 | using namespace std; 7 | 8 | class Graph 9 | { 10 | public: 11 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 12 | void addEdge(size_t a, size_t b); 13 | void removeEdge(size_t a, size_t b); 14 | void addVertax(size_t n); 15 | void removeVertax(size_t n); 16 | 17 | vector adj(size_t n) const; 18 | void showAdj(size_t n) const; 19 | void showGraph() const; 20 | 21 | size_t edge() const { return edges; } 22 | size_t vertax() const { return vertaxs; } 23 | 24 | private: 25 | vector> arr; 26 | size_t edges; 27 | size_t vertaxs; 28 | }; 29 | 30 | /// 使用深度优先遍历判断是否是无环图 31 | class Cycle 32 | { 33 | public: 34 | Cycle(const Graph &graph) : marked(graph.vertax()), has_cycle(false) 35 | { 36 | for (size_t i = 0; i < graph.vertax(); i++) 37 | marked[i] = false; 38 | for (size_t i = 0; i < graph.vertax(); i++) 39 | { 40 | if (!marked[i]) 41 | dfs(graph, i, i); 42 | } 43 | } 44 | 45 | bool hasCycle() const { return has_cycle; } 46 | 47 | private: 48 | void dfs(const Graph &graph, size_t v, size_t u) 49 | { 50 | marked[v] = true; 51 | 52 | vector vec = graph.adj(v); 53 | for (size_t i = 0; i < vec.size(); i++) 54 | { 55 | if (!marked[vec[i]]) 56 | dfs(graph, vec[i], v); 57 | else if (vec[i] != u) // 无环图其实就是树,此时v是树中一个节点,其父节点为u,当marked[vec[i]]==true时,表示v的父节点一定为u,否则图中有环 58 | has_cycle = true; 59 | } 60 | } 61 | 62 | vector marked; 63 | bool has_cycle; 64 | }; 65 | 66 | int main(void) 67 | { 68 | Graph graph(13); 69 | 70 | graph.addEdge(0, 1); 71 | graph.addEdge(0, 2); 72 | graph.addEdge(0, 5); 73 | graph.addEdge(0, 6); 74 | //graph.addEdge(3, 4); 75 | graph.addEdge(3, 5); 76 | graph.addEdge(4, 5); 77 | //graph.addEdge(4, 6); 78 | 79 | graph.addEdge(7, 8); 80 | 81 | graph.addEdge(9, 10); 82 | graph.addEdge(9, 11); 83 | graph.addEdge(9, 12); 84 | //graph.addEdge(11, 12); 85 | // 把以上3个注释行取消就成为了有环图 86 | 87 | cout << "vertax: " << graph.vertax() << endl; 88 | cout << "edge: " << graph.edge() << endl; 89 | graph.showGraph(); 90 | cout << endl; 91 | 92 | Cycle cycle(graph); 93 | 94 | cout << "cycle.hasCycle(): "; 95 | if (cycle.hasCycle()) 96 | cout << "true" << endl; 97 | else 98 | cout << "false" << endl; 99 | 100 | return 0; 101 | } 102 | 103 | void Graph::addEdge(size_t a, size_t b) 104 | { 105 | if (!(a < arr.size() && b < arr.size())) 106 | return; 107 | 108 | arr[a].push_back(b); 109 | arr[b].push_back(a); 110 | edges++; // 无向图 111 | } 112 | 113 | void Graph::removeEdge(size_t a, size_t b) 114 | { 115 | if (!(a < arr.size() && b < arr.size())) 116 | return; 117 | 118 | vector::iterator iter; 119 | iter = find(arr[a].begin(), arr[a].end(), b); 120 | if (iter != arr[a].end()) 121 | { 122 | arr[a].erase(iter); 123 | //edges--; 124 | } 125 | 126 | iter = find(arr[b].begin(), arr[b].end(), a); 127 | if (iter != arr[b].end()) 128 | { 129 | arr[b].erase(iter); 130 | edges--; 131 | } 132 | } 133 | void Graph::addVertax(size_t n) 134 | { 135 | if (n != arr.size()) 136 | return; 137 | 138 | arr.push_back(vector()); 139 | vertaxs++; 140 | } 141 | 142 | void Graph::removeVertax(size_t n) 143 | { 144 | if (n >= arr.size()) 145 | return; 146 | 147 | while (!arr[n].empty()) 148 | removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了 149 | //arr.erase(arr.begin() + n); 150 | vertaxs--; 151 | } 152 | 153 | vector Graph::adj(size_t n) const 154 | { 155 | if (n < arr.size()) 156 | return arr[n]; 157 | else 158 | return vector(); 159 | 160 | } 161 | 162 | void Graph::showAdj(size_t n) const 163 | { 164 | if (n >= arr.size()) 165 | return; 166 | 167 | vector vec; 168 | vec = adj(n); 169 | for (size_t i = 0; i < vec.size(); i++) 170 | cout << vec[i] << " "; 171 | cout << endl; 172 | } 173 | 174 | void Graph::showGraph() const 175 | { 176 | for (size_t i = 0; i < arr.size(); i++) 177 | { 178 | cout << i << ": "; 179 | showAdj(i); 180 | } 181 | } -------------------------------------------------------------------------------- /graph/Graph深度优先搜索找出图中所有的连通分量.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | //#include 5 | #include 6 | using namespace std; 7 | 8 | class Graph 9 | { 10 | public: 11 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 12 | void addEdge(size_t a, size_t b); 13 | void removeEdge(size_t a, size_t b); 14 | void addVertax(size_t n); 15 | void removeVertax(size_t n); 16 | 17 | vector adj(size_t n) const; 18 | void showAdj(size_t n) const; 19 | void showGraph() const; 20 | 21 | size_t edge() const { return edges; } 22 | size_t vertax() const { return vertaxs; } 23 | 24 | private: 25 | vector> arr; 26 | size_t edges; 27 | size_t vertaxs; 28 | }; 29 | 30 | /// 使用深度优先搜索找出图中所有的连通分量 31 | class CC 32 | { 33 | public: 34 | CC(const Graph &graph) : marked(graph.vertax()), id(graph.vertax()), count(0) 35 | { 36 | for (size_t i = 0; i < graph.vertax(); i++) 37 | marked[i] = false; 38 | 39 | for (size_t i = 0; i < graph.vertax(); i++) 40 | { 41 | if (!marked[i]) 42 | { 43 | dfs(graph, i); 44 | ++count; 45 | } 46 | } 47 | } 48 | 49 | bool isConnect(size_t v, size_t w) const { return (v < id.size() && w < id.size()) ? (id[v] == id[w]) : false; } 50 | int getCount() const { return count; } 51 | int getId(size_t v) const { return (v < id.size()) ? id[v] : -1; } 52 | 53 | private: 54 | void dfs(const Graph &graph, size_t v) 55 | { 56 | marked[v] = true; 57 | id[v] = count; 58 | 59 | vector vec = graph.adj(v); 60 | for (size_t i = 0; i < vec.size(); i++) 61 | { 62 | if (!marked[vec[i]]) 63 | dfs(graph, vec[i]); 64 | } 65 | } 66 | 67 | vector marked; 68 | vector id; // 连通分量标志符数组 69 | int count; // 连通分量个数 70 | }; 71 | 72 | int main(void) 73 | { 74 | Graph graph(13); 75 | 76 | graph.addEdge(0, 1); 77 | graph.addEdge(0, 2); 78 | graph.addEdge(0, 5); 79 | graph.addEdge(0, 6); 80 | graph.addEdge(3, 4); 81 | graph.addEdge(3, 5); 82 | graph.addEdge(4, 5); 83 | graph.addEdge(4, 6); 84 | 85 | graph.addEdge(7, 8); 86 | 87 | graph.addEdge(9, 10); 88 | graph.addEdge(9, 11); 89 | graph.addEdge(9, 12); 90 | graph.addEdge(11, 12); 91 | 92 | cout << "vertax: " << graph.vertax() << endl; 93 | cout << "edge: " << graph.edge() << endl; 94 | graph.showGraph(); 95 | cout << endl; 96 | 97 | CC cc(graph); 98 | 99 | for (size_t i = 0; i < graph.vertax(); i++) 100 | cout << i << " id is " << cc.getId(i) << endl; 101 | 102 | cout << cc.getCount() << endl; 103 | cout << "(0, 4) is connect ? " << (cc.isConnect(0, 4) ? "true" : "false") << endl; 104 | cout << "(0, 7) is connect ? " << (cc.isConnect(0, 7) ? "true" : "false") << endl; 105 | cout << "(0, 9) is connect ? " << (cc.isConnect(0, 9) ? "true" : "false") << endl; 106 | cout << "(7, 8) is connect ? " << (cc.isConnect(7, 8) ? "true" : "false") << endl; 107 | cout << "(9, 12) is connect ? " << (cc.isConnect(9, 12) ? "true" : "false") << endl; 108 | 109 | return 0; 110 | } 111 | 112 | void Graph::addEdge(size_t a, size_t b) 113 | { 114 | if (!(a < arr.size() && b < arr.size())) 115 | return; 116 | 117 | arr[a].push_back(b); 118 | arr[b].push_back(a); 119 | edges++; // 无向图 120 | } 121 | 122 | void Graph::removeEdge(size_t a, size_t b) 123 | { 124 | if (!(a < arr.size() && b < arr.size())) 125 | return; 126 | 127 | vector::iterator iter; 128 | iter = find(arr[a].begin(), arr[a].end(), b); 129 | if (iter != arr[a].end()) 130 | { 131 | arr[a].erase(iter); 132 | //edges--; 133 | } 134 | 135 | iter = find(arr[b].begin(), arr[b].end(), a); 136 | if (iter != arr[b].end()) 137 | { 138 | arr[b].erase(iter); 139 | edges--; 140 | } 141 | } 142 | void Graph::addVertax(size_t n) 143 | { 144 | if (n != arr.size()) 145 | return; 146 | 147 | arr.push_back(vector()); 148 | vertaxs++; 149 | } 150 | 151 | void Graph::removeVertax(size_t n) 152 | { 153 | if (n >= arr.size()) 154 | return; 155 | 156 | while (!arr[n].empty()) 157 | removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了 158 | //arr.erase(arr.begin() + n); 159 | vertaxs--; 160 | } 161 | 162 | vector Graph::adj(size_t n) const 163 | { 164 | if (n < arr.size()) 165 | return arr[n]; 166 | else 167 | return vector(); 168 | 169 | } 170 | 171 | void Graph::showAdj(size_t n) const 172 | { 173 | if (n >= arr.size()) 174 | return; 175 | 176 | vector vec; 177 | vec = adj(n); 178 | for (size_t i = 0; i < vec.size(); i++) 179 | cout << vec[i] << " "; 180 | cout << endl; 181 | } 182 | 183 | void Graph::showGraph() const 184 | { 185 | for (size_t i = 0; i < arr.size(); i++) 186 | { 187 | cout << i << ": "; 188 | showAdj(i); 189 | } 190 | } -------------------------------------------------------------------------------- /graph/Graph深度优先搜索查找图中路径.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 基于深度优先搜索实现Paths,使用一个变量edgeTo[]数组记录路径,这个数组可以找到每个与s连通的 3 | 顶点回到s的路径。它会记住每个顶点到起点的路径,而不是记录当前顶点到起点的路径。 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | class Graph 12 | { 13 | public: 14 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 15 | void addEdge(size_t a, size_t b); 16 | void removeEdge(size_t a, size_t b); 17 | void addVertax(size_t n); 18 | void removeVertax(size_t n); 19 | 20 | vector adj(size_t n) const; 21 | void showAdj(size_t n) const; 22 | void showGraph() const; 23 | 24 | size_t edge() const { return edges; } 25 | size_t vertax() const { return vertaxs; } 26 | 27 | private: 28 | vector> arr; 29 | size_t edges; 30 | size_t vertaxs; 31 | }; 32 | 33 | /// Graph使用深度优先搜索查找图中路径 34 | class DepthFirstPaths 35 | { 36 | public: 37 | DepthFirstPaths(Graph &graph, size_t _s) : s(_s), edgeTo(graph.vertax()), marked(graph.vertax()) 38 | { 39 | for (size_t i = 0; i < graph.vertax(); i++) 40 | marked[i] = false; 41 | dfs(graph, s); 42 | } 43 | 44 | bool hasPathTo(size_t v) { return (v < marked.size()) ? marked[v] : false; } 45 | stack pathTo(size_t v) 46 | { 47 | stack sta; 48 | for (size_t x = v; x != this->s; x = edgeTo[x]) 49 | sta.push(x); 50 | sta.push(this->s); 51 | 52 | return sta; 53 | } 54 | 55 | private: 56 | size_t s; 57 | vector edgeTo; 58 | vector marked; 59 | 60 | void dfs(Graph &graph, size_t v) 61 | { 62 | marked[v] = true; 63 | 64 | vector vec = graph.adj(v); 65 | for (size_t i = 0; i < vec.size(); i++) 66 | { 67 | if (!marked[vec[i]]) 68 | { 69 | edgeTo[vec[i]] = v; 70 | dfs(graph, vec[i]); 71 | } 72 | } 73 | } 74 | }; 75 | 76 | int main(void) 77 | { 78 | Graph graph(5); 79 | 80 | graph.addEdge(0, 1); 81 | graph.addEdge(3, 4); 82 | graph.addEdge(1, 3); 83 | graph.addEdge(0, 4); 84 | graph.addEdge(2, 3); 85 | graph.addEdge(0, 2); 86 | 87 | cout << graph.vertax() << endl; 88 | cout << graph.edge() << endl; 89 | graph.showGraph(); 90 | cout << endl; 91 | 92 | DepthFirstPaths dfp(graph, 0); 93 | stack sta; 94 | 95 | // 打印所有的以0为起点的路径 96 | for (size_t i = 0; i < graph.vertax(); i++) 97 | { 98 | sta = dfp.pathTo(i); 99 | cout << "0->" << i << ": "; 100 | while (!sta.empty()) 101 | { 102 | cout << sta.top() << " "; 103 | sta.pop(); 104 | } 105 | cout << endl; 106 | } 107 | 108 | return 0; 109 | } 110 | 111 | void Graph::addEdge(size_t a, size_t b) 112 | { 113 | if (!(a < arr.size() && b < arr.size())) 114 | return; 115 | 116 | arr[a].push_back(b); 117 | arr[b].push_back(a); 118 | edges++; // 无向图 119 | } 120 | 121 | void Graph::removeEdge(size_t a, size_t b) 122 | { 123 | if (!(a < arr.size() && b < arr.size())) 124 | return; 125 | 126 | vector::iterator iter; 127 | iter = find(arr[a].begin(), arr[a].end(), b); 128 | if (iter != arr[a].end()) 129 | { 130 | arr[a].erase(iter); 131 | //edges--; 132 | } 133 | 134 | iter = find(arr[b].begin(), arr[b].end(), a); 135 | if (iter != arr[b].end()) 136 | { 137 | arr[b].erase(iter); 138 | edges--; 139 | } 140 | } 141 | void Graph::addVertax(size_t n) 142 | { 143 | if (n != arr.size()) 144 | return; 145 | 146 | arr.push_back(vector()); 147 | vertaxs++; 148 | } 149 | 150 | void Graph::removeVertax(size_t n) 151 | { 152 | if (n >= arr.size()) 153 | return; 154 | 155 | while (!arr[n].empty()) 156 | removeEdge(n, arr[n][0]); // 调用removeEdge函数,不用考虑分两次删除边了 157 | //arr.erase(arr.begin() + n); 158 | vertaxs--; 159 | } 160 | 161 | vector Graph::adj(size_t n) const 162 | { 163 | if (n < arr.size()) 164 | return arr[n]; 165 | else 166 | return vector(); 167 | 168 | } 169 | 170 | void Graph::showAdj(size_t n) const 171 | { 172 | if (n >= arr.size()) 173 | return; 174 | 175 | vector vec; 176 | vec = adj(n); 177 | for (size_t i = 0; i < vec.size(); i++) 178 | cout << vec[i] << " "; 179 | cout << endl; 180 | } 181 | 182 | void Graph::showGraph() const 183 | { 184 | for (size_t i = 0; i < arr.size(); i++) 185 | { 186 | cout << i << ": "; 187 | showAdj(i); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /graph/KosarajuSCC-强连通分量.java: -------------------------------------------------------------------------------- 1 | package graph; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * KosarajuSCC - 有向图强连通分量算法 8 | */ 9 | public class KosarajuSCC { 10 | 11 | // ---------------------------------- Instance Variables 12 | 13 | // 强连通分量个数 14 | private int strongConnection; 15 | 16 | // ---------------------------------- Construction 17 | 18 | public KosarajuSCC(Graph graph) { 19 | DepthFirstSearch depthFirstSearch = new DepthFirstSearch(graph); 20 | List list = depthFirstSearch.getSorted(); 21 | List sorted = new ArrayList<>(); 22 | for (int i = list.size() - 1; i >= 0; i--) { 23 | sorted.add(list.get(i)); 24 | } 25 | 26 | // 得到新的转置图graph2 27 | int nodes = graph.getVertaxs(); 28 | Graph graph2 = new Graph(nodes); 29 | for (int i = 0; i < nodes; i++) { 30 | List list2 = graph.adj(i); 31 | for (Integer ele : list2) { 32 | graph2.add(ele, i); 33 | } 34 | } 35 | 36 | System.out.println(list); 37 | System.out.println(sorted); 38 | boolean []marked = new boolean[graph2.getVertaxs()]; 39 | for (int i = 0; i < sorted.size(); i++) { 40 | int node = sorted.get(i); 41 | if (!marked[node]) { 42 | dfs(graph2, node, marked); 43 | strongConnection++; 44 | } 45 | } 46 | } 47 | 48 | // ---------------------------------- Public Methods 49 | 50 | public int getStrongConnection() { 51 | return strongConnection; 52 | } 53 | 54 | // ---------------------------------- Private Methods 55 | 56 | private void dfs(Graph graph, int node, boolean []marked) { 57 | marked[node] = true; 58 | List nodes = graph.adj(node); 59 | for (int i = 0; i < nodes.size(); i++) { 60 | if (!marked[nodes.get(i)]) { 61 | dfs(graph, nodes.get(i), marked); 62 | } 63 | } 64 | } 65 | 66 | } 67 | 68 | /** 69 | * 深度优先搜索 70 | */ 71 | class DepthFirstSearch { 72 | 73 | // ---------------------------------- Instance Variables 74 | 75 | // 有向图 76 | Graph graph; 77 | 78 | // 深度优先搜索后的顶点顺序 79 | List sorted = new ArrayList(); 80 | 81 | // ---------------------------------- Constructors 82 | 83 | public DepthFirstSearch(Graph graph) { 84 | this.graph = graph; 85 | // boolean数组默认都置为false,所以不用专门初始化 86 | boolean []marked = new boolean[graph.getVertaxs()]; 87 | 88 | for (int i = 0; i < marked.length; i++) { 89 | if (!marked[i]) { 90 | dfs(i, marked); 91 | } 92 | } 93 | } 94 | 95 | // ---------------------------------- Public Methods 96 | 97 | public List getSorted() { 98 | return new ArrayList (sorted); 99 | } 100 | 101 | // ---------------------------------- Private Methods 102 | 103 | private void dfs(int node, boolean []marked) { 104 | marked[node] = true; 105 | List nodes = this.graph.adj(node); 106 | for (int i = 0; i < nodes.size(); i++) { 107 | if (!marked[nodes.get(i)]) { 108 | dfs(nodes.get(i), marked); 109 | } 110 | } 111 | sorted.add(node); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /graph/TopologicalSort-拓扑排序.java: -------------------------------------------------------------------------------- 1 | package graph; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 有向图的拓扑排序 8 | */ 9 | public class TopologicalSort { 10 | 11 | // ---------------------------------- Instance Variable 12 | 13 | // 顶点的拓扑排序 14 | List order = new ArrayList<>(); 15 | 16 | // ---------------------------------- Constructors 17 | 18 | public TopologicalSort(Graph graph) { 19 | 20 | DepthFirstSearch depthFirstSearch = new DepthFirstSearch(graph); 21 | List dfsNodes = depthFirstSearch.getSorted(); 22 | System.out.println(dfsNodes); 23 | for (int i = dfsNodes.size() - 1; i >= 0; i--) { 24 | order.add(dfsNodes.get(i)); 25 | } 26 | } 27 | 28 | // ---------------------------------- Public Methods 29 | 30 | public List getOrder() { 31 | return order; 32 | } 33 | 34 | } 35 | 36 | /** 37 | * 深度优先搜索 38 | */ 39 | class DepthFirstSearch { 40 | 41 | // ---------------------------------- Instance Variables 42 | 43 | // 有向图 44 | Graph graph; 45 | 46 | // 深度优先搜索后的顶点顺序 47 | List sorted = new ArrayList(); 48 | 49 | // ---------------------------------- Constructors 50 | 51 | public DepthFirstSearch(Graph graph) { 52 | this.graph = graph; 53 | // boolean数组默认都置为false,所以不用专门初始化 54 | boolean []marked = new boolean[graph.getVertaxs()]; 55 | 56 | for (int i = 0; i < marked.length; i++) { 57 | if (!marked[i]) { 58 | dfs(i, marked); 59 | } 60 | } 61 | } 62 | 63 | // ---------------------------------- Public Methods 64 | 65 | public List getSorted() { 66 | return new ArrayList (sorted); 67 | } 68 | 69 | // ---------------------------------- Private Methods 70 | 71 | private void dfs(int node, boolean []marked) { 72 | if (marked[node]) { 73 | return; 74 | } 75 | 76 | marked[node] = true; 77 | List nodes = this.graph.adj(node); 78 | for (int i = 0; i < nodes.size(); i++) { 79 | if (!marked[nodes.get(i)]) { 80 | dfs(nodes.get(i), marked); 81 | } 82 | } 83 | sorted.add(node); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /graph/最小生成树的Kruskal算法.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Edge 10 | { 11 | public: 12 | Edge(size_t _v, size_t _w, double _weight) : v(_v), w(_w), weight(_weight) {} 13 | 14 | double getWeight() const { return weight; } 15 | size_t either() const { return v; } 16 | size_t other(size_t v) const 17 | { 18 | if (v == this->v) 19 | return this->w; 20 | else if (v == this->w) 21 | return this->v; 22 | else 23 | { 24 | cout << "error in Edge::other()" << endl; 25 | exit(1); 26 | } 27 | } 28 | void print() const{ cout << "(" << v << ", " << w << ", " << weight << ") "; } 29 | 30 | private: 31 | size_t v, w; // 两个顶点 32 | double weight; // 权重 33 | }; 34 | 35 | /// 加权无向图 36 | class EdgeWeithtedGraph 37 | { 38 | public: 39 | EdgeWeithtedGraph(size_t vertax_nums) : vertaxs(vertax_nums), edges(0), arr(vertax_nums) {} 40 | 41 | void addEdge(const Edge e); 42 | 43 | vector adj(size_t v) const { return v < arrSize() ? arr[v] : vector(); } 44 | vector allEdges() const; // 返回加权无向图的所有边 45 | size_t arrSize() const { return arr.size(); } 46 | size_t vertax() const { return vertaxs; } 47 | size_t edge() const { return edges; } 48 | void printVertax(size_t v) const; 49 | void printGraph() const; 50 | 51 | private: 52 | size_t vertaxs; // 顶点个数 53 | size_t edges; // 边的个数 54 | vector> arr; // 邻接表 55 | }; 56 | 57 | /// 无向图数据结构,用于测试Kruskal算法中的边是否能构成环 58 | class Graph 59 | { 60 | public: 61 | Graph(size_t n) : arr(n), edges(0), vertaxs(n) {} 62 | void addEdge(size_t a, size_t b) 63 | { 64 | if (!(a < arr.size() && b < arr.size())) 65 | return; 66 | 67 | arr[a].push_back(b); 68 | arr[b].push_back(a); 69 | edges++; 70 | } 71 | 72 | vector adj(size_t n) const 73 | { 74 | if (n < arr.size()) 75 | return arr[n]; 76 | else 77 | return vector(); 78 | } 79 | /// 返回顶点个数 80 | size_t vertax() const { return arr.size(); } 81 | 82 | private: 83 | vector> arr; // 邻接表 84 | size_t edges; // 边的个数 85 | size_t vertaxs; // 顶点个数 86 | }; 87 | 88 | /// 使用深度优先遍历判断Graph是否是无环图 89 | class Cycle 90 | { 91 | public: 92 | Cycle(const Graph &graph) : marked(graph.vertax()), has_cycle(false) 93 | { 94 | for (size_t i = 0; i < graph.vertax(); i++) 95 | marked[i] = false; 96 | for (size_t i = 0; i < graph.vertax(); i++) 97 | { 98 | if (!marked[i]) 99 | dfs(graph, i, i); 100 | } 101 | } 102 | 103 | bool hasCycle() const { return has_cycle; } 104 | 105 | private: 106 | void dfs(const Graph &graph, size_t v, size_t u) 107 | { 108 | marked[v] = true; 109 | 110 | vector vec = graph.adj(v); 111 | for (size_t i = 0; i < vec.size(); i++) 112 | { 113 | if (!marked[vec[i]]) 114 | dfs(graph, vec[i], v); 115 | else if (vec[i] != u) // 无环图其实就是树,此时v是树中一个节点,其父节点为u,当marked[vec[i]]==true时,表示v的父节点一定为u,否则图中有环 116 | has_cycle = true; 117 | } 118 | } 119 | 120 | vector marked; 121 | bool has_cycle; 122 | }; 123 | 124 | /// 判断最小生成树中是否有环,在Kruskal算法算法中被调用 125 | bool hasCycle(vector vec, size_t nvextax) 126 | { 127 | if (vec.size() == 0) 128 | return false; 129 | 130 | Graph graph(nvextax); 131 | for (size_t i = 0; i < vec.size(); i++) 132 | { 133 | size_t v = vec[i].either(); 134 | size_t w = vec[i].other(v); 135 | graph.addEdge(v, w); 136 | } 137 | 138 | Cycle cycle(graph); 139 | return cycle.hasCycle(); 140 | } 141 | 142 | /// 为了存放Kruskal算法过程中的边,这些边按照权值从小到大排列 143 | template 144 | struct greator 145 | { 146 | bool operator()(const T &x, const T &y) 147 | { 148 | return x.getWeight() < y.getWeight(); 149 | } 150 | }; 151 | 152 | /// 最小生成树的Kruskal算法 153 | class KruskalMST 154 | { 155 | public: 156 | KruskalMST(const EdgeWeithtedGraph &graph) 157 | { 158 | set> pq; // 计算过程保存边的set 159 | vector vec = graph.allEdges(); 160 | set::iterator miniter; 161 | 162 | for (size_t i = 0; i < vec.size(); i++) // 将所有的边存到pq中 163 | pq.insert(vec[i]); 164 | 165 | while (!pq.empty() && mst.size() < graph.arrSize() - 1) // graph.arrSize()可替换为变量 166 | { 167 | miniter = pq.begin(); 168 | 169 | mst.push_back(*miniter); 170 | if (hasCycle(mst, graph.arrSize())) 171 | removeEdge(*miniter); 172 | pq.erase(miniter); 173 | } 174 | } 175 | 176 | vector edges() const { return mst; } 177 | void printEdges() const 178 | { 179 | for (size_t i = 0; i < mst.size(); i++) 180 | { 181 | mst[i].print(); 182 | } 183 | cout << endl; 184 | } 185 | 186 | private: 187 | void removeEdge(Edge e) 188 | { 189 | size_t v = e.either(); 190 | size_t w = e.other(v); 191 | for (size_t i = 0; i < mst.size(); i++) 192 | { 193 | size_t iv = mst[i].either(); 194 | size_t iw = mst[i].other(iv); 195 | if (v == iv && w == iw) 196 | { 197 | mst.erase(mst.begin() + i); 198 | return; 199 | } 200 | } 201 | } 202 | 203 | vector mst; 204 | }; 205 | 206 | int main(void) 207 | { 208 | EdgeWeithtedGraph graph(8); 209 | 210 | graph.addEdge(Edge(0, 7, 0.16)); 211 | graph.addEdge(Edge(0, 2, 0.26)); 212 | graph.addEdge(Edge(0, 4, 0.38)); 213 | graph.addEdge(Edge(0, 6, 0.58)); 214 | graph.addEdge(Edge(1, 7, 0.19)); 215 | graph.addEdge(Edge(5, 7, 0.28)); 216 | graph.addEdge(Edge(2, 7, 0.34)); 217 | graph.addEdge(Edge(4, 7, 0.37)); 218 | graph.addEdge(Edge(1, 3, 0.29)); 219 | graph.addEdge(Edge(1, 5, 0.32)); 220 | graph.addEdge(Edge(1, 2, 0.36)); 221 | graph.addEdge(Edge(2, 3, 0.17)); 222 | graph.addEdge(Edge(6, 2, 0.40)); 223 | graph.addEdge(Edge(3, 6, 0.52)); 224 | graph.addEdge(Edge(4, 5, 0.35)); 225 | graph.addEdge(Edge(6, 4, 0.93)); 226 | 227 | cout << "arrSize: " << graph.arrSize() << endl; 228 | cout << "vertax: " << graph.vertax() << endl; 229 | cout << "edge: " << graph.edge() << endl; 230 | cout << "----------------" << endl; 231 | 232 | graph.printGraph(); 233 | cout << endl; 234 | 235 | // 输出无向图的所有边 236 | vector vec = graph.allEdges(); 237 | for (size_t i = 0; i < vec.size(); i++) 238 | vec[i].print(); 239 | cout << endl << endl; 240 | 241 | // Kruskal算法 242 | KruskalMST prim(graph); 243 | prim.printEdges(); 244 | 245 | return 0; 246 | } 247 | 248 | void EdgeWeithtedGraph::addEdge(const Edge e) 249 | { 250 | size_t v = e.either(); 251 | size_t w = e.other(v); 252 | if (!(v < arrSize() && w < arrSize())) 253 | return; 254 | 255 | arr[v].push_back(e); 256 | arr[w].push_back(e); 257 | this->edges++; 258 | } 259 | 260 | vector EdgeWeithtedGraph::allEdges() const 261 | { 262 | vector vec; 263 | 264 | for (size_t i = 0; i < arrSize(); i++) 265 | { 266 | for (size_t j = 0; j < arr[i].size(); j++) 267 | { 268 | if (arr[i][j].other(i) > i) // 所有边的权重各不不同,可以这样判断,每个边只保留一个 269 | vec.push_back(arr[i][j]); 270 | } 271 | } 272 | return vec; 273 | } 274 | 275 | void EdgeWeithtedGraph::printVertax(size_t v) const 276 | { 277 | if (v >= arrSize()) 278 | return; 279 | 280 | for (size_t i = 0; i < arr[v].size(); i++) 281 | arr[v][i].print(); 282 | cout << endl; 283 | } 284 | 285 | void EdgeWeithtedGraph::printGraph() const 286 | { 287 | for (size_t i = 0; i < arrSize(); i++) 288 | { 289 | cout << i << ": "; 290 | printVertax(i); 291 | } 292 | } -------------------------------------------------------------------------------- /graph/最小生成树的Prim算法.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Edge 10 | { 11 | public: 12 | Edge(size_t _v, size_t _w, double _weight) : v(_v), w(_w), weight(_weight) {} 13 | 14 | double getWeight() const { return weight; } 15 | size_t either() const { return v; } 16 | size_t other(size_t v) const 17 | { 18 | if (v == this->v) 19 | return this->w; 20 | else if (v == this->w) 21 | return this->v; 22 | else 23 | { 24 | cout << "error in Edge::other()" << endl; 25 | exit(1); 26 | } 27 | } 28 | void print() const{ cout << "(" << v << ", " << w << ", " << weight << ") "; } 29 | 30 | private: 31 | size_t v, w; // 两个顶点 32 | double weight; // 权重 33 | }; 34 | 35 | class EdgeWeithtedGraph 36 | { 37 | public: 38 | EdgeWeithtedGraph(size_t vertax_nums) : vertaxs(vertax_nums), edges(0), arr(vertax_nums) {} 39 | 40 | void addEdge(const Edge e); 41 | 42 | vector adj(size_t v) const { return v < arrSize() ? arr[v] : vector(); } 43 | vector allEdges() const; // 返回加权无向图的所有边 44 | size_t arrSize() const { return arr.size(); } 45 | size_t vertax() const { return vertaxs; } 46 | size_t edge() const { return edges; } 47 | void printVertax(size_t v) const; 48 | void printGraph() const; 49 | 50 | private: 51 | size_t vertaxs; // 顶点个数 52 | size_t edges; // 边的个数 53 | vector> arr; // 邻接表 54 | }; 55 | 56 | /// 为了存放Prim算法过程中的边,这些边按照权值从小到大排列 57 | template 58 | struct greator 59 | { 60 | bool operator()(const T &x, const T &y) 61 | { 62 | return x.getWeight() < y.getWeight(); 63 | } 64 | }; 65 | 66 | /// 最小生成树的Prim算法的延时实现 67 | class LazyPrimMST 68 | { 69 | public: 70 | LazyPrimMST(const EdgeWeithtedGraph &graph) : marked(graph.arrSize()) 71 | { 72 | if (graph.arrSize() == 0) // 防止为空图 73 | return; 74 | for (size_t i = 0; i < marked.size(); i++) 75 | marked[i] = false; 76 | 77 | visit(graph, 0); 78 | set::iterator miniter; 79 | while (!pq.empty()) 80 | { 81 | miniter = pq.begin(); 82 | size_t v = miniter->either(); 83 | size_t w = miniter->other(v); 84 | 85 | if (marked[v] && marked[w]) 86 | { 87 | pq.erase(miniter); 88 | continue; 89 | } 90 | 91 | mst.push_back(*miniter); 92 | pq.erase(miniter); 93 | if (!marked[v]) 94 | visit(graph, v); 95 | if (!marked[w]) 96 | visit(graph, w); 97 | } 98 | } 99 | 100 | vector edges() const { return mst; } 101 | void printEdges() const 102 | { 103 | for (size_t i = 0; i < mst.size(); i++) 104 | { 105 | mst[i].print(); 106 | } 107 | cout << endl; 108 | } 109 | 110 | private: 111 | void visit(const EdgeWeithtedGraph &graph, size_t v) 112 | { 113 | marked[v] = true; 114 | 115 | vector vec = graph.adj(v); 116 | for (size_t i = 0; i < vec.size(); i++) 117 | { 118 | if (!marked[vec[i].other(v)]) 119 | pq.insert(vec[i]); 120 | } 121 | } 122 | 123 | vector marked; 124 | vector mst; // 最小生成树的边 125 | set> pq; // 计算过程保存边的set 126 | }; 127 | 128 | int main(void) 129 | { 130 | EdgeWeithtedGraph graph(8); 131 | 132 | graph.addEdge(Edge(0, 7, 0.16)); 133 | graph.addEdge(Edge(0, 2, 0.26)); 134 | graph.addEdge(Edge(0, 4, 0.38)); 135 | graph.addEdge(Edge(0, 6, 0.58)); 136 | graph.addEdge(Edge(1, 7, 0.19)); 137 | graph.addEdge(Edge(5, 7, 0.28)); 138 | graph.addEdge(Edge(2, 7, 0.34)); 139 | graph.addEdge(Edge(4, 7, 0.37)); 140 | graph.addEdge(Edge(1, 3, 0.29)); 141 | graph.addEdge(Edge(1, 5, 0.32)); 142 | graph.addEdge(Edge(1, 2, 0.36)); 143 | graph.addEdge(Edge(2, 3, 0.17)); 144 | graph.addEdge(Edge(6, 2, 0.40)); 145 | graph.addEdge(Edge(3, 6, 0.52)); 146 | graph.addEdge(Edge(4, 5, 0.35)); 147 | graph.addEdge(Edge(6, 4, 0.93)); 148 | 149 | cout << "arrSize: " << graph.arrSize() << endl; 150 | cout << "vertax: " << graph.vertax() << endl; 151 | cout << "edge: " << graph.edge() << endl; 152 | cout << "----------------" << endl; 153 | 154 | graph.printGraph(); 155 | cout << endl; 156 | 157 | // 输出无向图的所有边 158 | vector vec = graph.allEdges(); 159 | for (size_t i = 0; i < vec.size(); i++) 160 | vec[i].print(); 161 | cout << endl << endl; 162 | 163 | // prim算法 164 | LazyPrimMST prim(graph); 165 | prim.printEdges(); 166 | 167 | return 0; 168 | } 169 | 170 | void EdgeWeithtedGraph::addEdge(const Edge e) 171 | { 172 | size_t v = e.either(); 173 | size_t w = e.other(v); 174 | if (!(v < arrSize() && w < arrSize())) 175 | return; 176 | 177 | arr[v].push_back(e); 178 | arr[w].push_back(e); 179 | this->edges++; 180 | } 181 | 182 | vector EdgeWeithtedGraph::allEdges() const 183 | { 184 | vector vec; 185 | 186 | for (size_t i = 0; i < arrSize(); i++) 187 | { 188 | for (size_t j = 0; j < arr[i].size(); j++) 189 | { 190 | if (arr[i][j].other(i) > i) // 所有边的权重各不不同,可以这样判断,每个边只保留一个 191 | vec.push_back(arr[i][j]); 192 | } 193 | } 194 | return vec; 195 | } 196 | 197 | void EdgeWeithtedGraph::printVertax(size_t v) const 198 | { 199 | if (v >= arrSize()) 200 | return; 201 | 202 | for (size_t i = 0; i < arr[v].size(); i++) 203 | arr[v][i].print(); 204 | cout << endl; 205 | } 206 | 207 | void EdgeWeithtedGraph::printGraph() const 208 | { 209 | for (size_t i = 0; i < arrSize(); i++) 210 | { 211 | cout << i << ": "; 212 | printVertax(i); 213 | } 214 | } -------------------------------------------------------------------------------- /graph/最短路径的Dijkstra算法.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | /// 加权有向边的数据结构 7 | class DirectedEdge 8 | { 9 | public: 10 | DirectedEdge(size_t _v, size_t _w, double _weight) : v(_v), w(_w), weights(_weight) { } 11 | DirectedEdge() : v(0), w(0), weights(DBL_MAX) { } // 默认构造函数 12 | 13 | size_t from() const { return v; } 14 | size_t to() const { return w; } 15 | double weight() const { return weights; } 16 | void print() const { cout << "(" << v << "->" << w << ": " << weights << ") "; } 17 | 18 | private: 19 | size_t v, w; 20 | double weights; 21 | }; 22 | 23 | /// 加权有向图的数据结构 24 | class EdgeWeightDigraph 25 | { 26 | public: 27 | EdgeWeightDigraph(size_t v) : vertax(v), edge(0), arr(v) {} 28 | 29 | void addEdge(const DirectedEdge &e); 30 | 31 | vector adj(size_t v) const; 32 | vector edges() const; 33 | size_t getVertax() const { return vertax; } 34 | size_t getEdge() const { return edge; } 35 | size_t getArrSize() const { return arr.size(); } 36 | 37 | void printAdj(size_t v) const; 38 | void printGraph() const; 39 | 40 | private: 41 | size_t vertax, edge; 42 | vector> arr; 43 | }; 44 | 45 | /// 最短路径的加权有向图Dijkstra算法 46 | /** 47 | Dijkstra算法能够解决边权重非负的加权有向图的单起点最短路径问题。 48 | Dijkstra算法和Prim算法比较:两种算法都会添加边的方式构造一棵树,Prim算法每次添加的都是离树最近的非树顶点, 49 | Dijkstra算法每次添加的都是离起点最近的非树顶点。它们都不需要marked[]数组,因为条件!marked[i]等价于 50 | 条件distTo[i]无穷大 51 | */ 52 | class DijkstraSP 53 | { 54 | public: 55 | DijkstraSP(EdgeWeightDigraph &graph, size_t s) : edgeTo(graph.getArrSize()), distTo(graph.getArrSize()) 56 | { 57 | for (size_t i = 0; i < graph.getArrSize(); i++) 58 | distTo[i] = DBL_MAX; // 默认无穷大 59 | distTo[s] = 0; 60 | 61 | que.push_back(pair(s, 0.0)); 62 | while (!que.empty()) 63 | { 64 | size_t v = que[0].first; 65 | que.erase(que.begin()); 66 | relax(graph, v); 67 | } 68 | } 69 | 70 | double getDistTo(size_t v) const { return (v < distTo.size()) ? distTo[v] : DBL_MAX; } 71 | bool hasPathTo(size_t v) const { return (v < distTo.size()) ? (distTo[v] != DBL_MAX) : false; } 72 | vector getPathTo() const { return edgeTo; } 73 | 74 | private: 75 | void relax(EdgeWeightDigraph &graph, size_t v) 76 | { 77 | vector vec = graph.adj(v); 78 | 79 | for (size_t i = 0; i < vec.size(); i++) 80 | { 81 | size_t w = vec[i].to(); 82 | 83 | // distTo[w]表示从s到w的最短路径的长度 84 | if (distTo[w] > distTo[v] + vec[i].weight()) 85 | { 86 | distTo[w] = distTo[v] + vec[i].weight(); 87 | edgeTo[w] = vec[i]; 88 | 89 | size_t index = queHasVertax(w); 90 | if (index != que.size()) // 队列中包含节点w 91 | que[index].second = distTo[w]; 92 | else 93 | que.push_back(pair(w, distTo[w])); 94 | } 95 | } 96 | } 97 | 98 | size_t queHasVertax(size_t v) 99 | { 100 | for (size_t i = 0; i < que.size(); i++) 101 | { 102 | if (que[i].first == v) 103 | return i; 104 | } 105 | return que.size(); 106 | } 107 | 108 | vector edgeTo; // edgeTo[]中元素所对应的的可达顶点构成了一棵最短路径树 109 | vector distTo; // distTo[]记录节点到起点的最短路径长度,初始化微无穷大 110 | vector> que; // 用vector来代替队列,队列pop相当于vec.erase(vec.begin())操作 111 | }; 112 | 113 | int main(void) 114 | { 115 | EdgeWeightDigraph graph(8); 116 | 117 | graph.addEdge(DirectedEdge(4, 5, 0.35)); 118 | graph.addEdge(DirectedEdge(5, 4, 0.35)); 119 | graph.addEdge(DirectedEdge(4, 7, 0.37)); 120 | graph.addEdge(DirectedEdge(5, 7, 0.28)); 121 | graph.addEdge(DirectedEdge(7, 5, 0.28)); 122 | graph.addEdge(DirectedEdge(5, 1, 0.32)); 123 | graph.addEdge(DirectedEdge(0, 4, 0.38)); 124 | graph.addEdge(DirectedEdge(0, 2, 0.26)); 125 | graph.addEdge(DirectedEdge(7, 3, 0.39)); 126 | graph.addEdge(DirectedEdge(1, 3, 0.29)); 127 | graph.addEdge(DirectedEdge(2, 7, 0.34)); 128 | graph.addEdge(DirectedEdge(6, 2, 0.40)); 129 | graph.addEdge(DirectedEdge(3, 6, 0.52)); 130 | graph.addEdge(DirectedEdge(6, 0, 0.58)); 131 | graph.addEdge(DirectedEdge(6, 4, 0.93)); 132 | 133 | cout << graph.getVertax() << endl; 134 | cout << graph.getEdge() << endl; 135 | cout << "-------------------" << endl; 136 | graph.printGraph(); 137 | cout << endl; 138 | 139 | // 输出起点0到图中所有点的最短路径的长度 140 | DijkstraSP dijk(graph, 0); 141 | for (size_t i = 0; i < graph.getArrSize(); i++) 142 | { 143 | cout << "0 -> " << i << ": " << dijk.getDistTo(i) << endl; 144 | } 145 | cout << endl; 146 | 147 | return 0; 148 | } 149 | 150 | void EdgeWeightDigraph::addEdge(const DirectedEdge &e) 151 | { 152 | if (e.from() >= getArrSize()) 153 | return; 154 | 155 | arr[e.from()].push_back(e); 156 | this->edge++; // 边的个数加1 157 | } 158 | 159 | vector EdgeWeightDigraph::adj(size_t v) const 160 | { 161 | if (v < getArrSize()) 162 | return arr[v]; 163 | else 164 | return vector(); // a blank vector 165 | } 166 | 167 | vector EdgeWeightDigraph::edges() const 168 | { 169 | vector vec; 170 | 171 | for (size_t i = 0; i < getArrSize(); i++) 172 | { 173 | for (size_t j = 0; j < arr[i].size(); j++) 174 | vec.push_back(arr[i][j]); 175 | } 176 | return vec; 177 | } 178 | 179 | void EdgeWeightDigraph::printAdj(size_t v) const 180 | { 181 | if (v >= getArrSize()) 182 | return; 183 | for (size_t i = 0; i < arr[v].size(); i++) 184 | arr[v][i].print(); 185 | cout << endl; 186 | } 187 | 188 | void EdgeWeightDigraph::printGraph() const 189 | { 190 | for (size_t i = 0; i < getArrSize(); i++) 191 | printAdj(i); 192 | } -------------------------------------------------------------------------------- /graph/最短路径的加权有向图数据结构.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | /// 加权有向边的数据结构 6 | class DirectedEdge 7 | { 8 | public: 9 | DirectedEdge(size_t _v, size_t _w, double _weight) : v(_v), w(_w), weights(_weight) { } 10 | 11 | size_t from() const { return v; } 12 | size_t to() const { return w; } 13 | double weight() const { return weights; } 14 | void print() const { cout << "(" << v << "->" << w << ": " << weights << ") "; } 15 | 16 | private: 17 | size_t v, w; // 两个顶点 18 | double weights; // 权重 19 | }; 20 | 21 | /// 加权有向图的数据结构 22 | class EdgeWeightDigraph 23 | { 24 | public: 25 | EdgeWeightDigraph(size_t v) : vertax(v), edge(0), arr(v) {} 26 | 27 | void addEdge(const DirectedEdge &e); 28 | 29 | vector adj(size_t v) const; 30 | vector edges() const; 31 | size_t getVertax() const { return vertax; } 32 | size_t getEdge() const { return edge; } 33 | size_t getArrSize() const { return arr.size(); } 34 | 35 | void printAdj(size_t v) const; 36 | void printGraph() const; 37 | 38 | private: 39 | size_t vertax, edge; // 顶点个数,边的个数 40 | vector> arr; // 临界表 41 | }; 42 | 43 | int main(void) 44 | { 45 | EdgeWeightDigraph graph(8); 46 | 47 | graph.addEdge(DirectedEdge(4, 5, 0.35)); 48 | graph.addEdge(DirectedEdge(5, 4, 0.35)); 49 | graph.addEdge(DirectedEdge(4, 7, 0.37)); 50 | graph.addEdge(DirectedEdge(5, 7, 0.28)); 51 | graph.addEdge(DirectedEdge(7, 5, 0.28)); 52 | graph.addEdge(DirectedEdge(5, 1, 0.32)); 53 | graph.addEdge(DirectedEdge(0, 4, 0.38)); 54 | graph.addEdge(DirectedEdge(0, 2, 0.26)); 55 | graph.addEdge(DirectedEdge(7, 3, 0.39)); 56 | graph.addEdge(DirectedEdge(1, 3, 0.29)); 57 | graph.addEdge(DirectedEdge(2, 7, 0.34)); 58 | graph.addEdge(DirectedEdge(6, 2, 0.40)); 59 | graph.addEdge(DirectedEdge(3, 6, 0.52)); 60 | graph.addEdge(DirectedEdge(6, 0, 0.58)); 61 | graph.addEdge(DirectedEdge(6, 4, 0.93)); 62 | 63 | cout << graph.getVertax() << endl; 64 | cout << graph.getEdge() << endl; 65 | cout << "-------------------" << endl; 66 | graph.printGraph(); 67 | 68 | return 0; 69 | } 70 | 71 | void EdgeWeightDigraph::addEdge(const DirectedEdge &e) 72 | { 73 | if (e.from() >= getArrSize()) 74 | return; 75 | 76 | arr[e.from()].push_back(e); 77 | this->edge++; // 边的个数加1 78 | } 79 | 80 | vector EdgeWeightDigraph::adj(size_t v) const 81 | { 82 | if (v < getArrSize()) 83 | return arr[v]; 84 | else 85 | return vector(); // a blank vector 86 | } 87 | 88 | vector EdgeWeightDigraph::edges() const 89 | { 90 | vector vec; 91 | 92 | for (size_t i = 0; i < getArrSize(); i++) 93 | { 94 | for (size_t j = 0; j < arr[i].size(); j++) 95 | vec.push_back(arr[i][j]); 96 | } 97 | return vec; 98 | } 99 | 100 | void EdgeWeightDigraph::printAdj(size_t v) const 101 | { 102 | if (v >= getArrSize()) 103 | return; 104 | for (size_t i = 0; i < arr[v].size(); i++) 105 | arr[v][i].print(); 106 | cout << endl; 107 | } 108 | 109 | void EdgeWeightDigraph::printGraph() const 110 | { 111 | for (size_t i = 0; i < getArrSize(); i++) 112 | printAdj(i); 113 | } 114 | -------------------------------------------------------------------------------- /other/ObjectPool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | class ObjectPool 9 | { 10 | public: 11 | ObjectPool(int chunkSize = defaultChunk) : chunkSize_(chunkSize) 12 | { 13 | if (chunkSize <= 0) { 14 | std::cout << "chunkSize <= 0" << endl; 15 | } 16 | else { 17 | allocChunk(defaultSize); 18 | } 19 | } 20 | 21 | ~ObjectPool() 22 | { 23 | deleteAllAllocList(); 24 | } 25 | 26 | // 获取一个对象,不要释放该对象,其由对象池类管理 27 | T &acquireObject() 28 | { 29 | if (freeQueue_.empty()) { 30 | allocChunk(chunkSize_); 31 | } 32 | T *obj = freeQueue_.front(); 33 | freeQueue_.pop(); 34 | return *obj; 35 | } 36 | 37 | // 释放一个对象到对象池 38 | void releaseObject(T &object) 39 | { 40 | freeQueue_.push(&object); 41 | } 42 | 43 | private: 44 | // Not allow 45 | ObjectPool(const ObjectPool &rhs); 46 | ObjectPool &operator=(const ObjectPool &rhs); 47 | 48 | void allocChunk(int size) 49 | { 50 | T *p = new T[size]; 51 | 52 | for (int i = 0; i < size; i++) { 53 | freeQueue_.push(&p[i]); 54 | } 55 | // 注意:申请内存是按块申请的,所以释放时也要按照块来释放 56 | allAllocList_.push_back(p); 57 | } 58 | 59 | void deleteAllAllocList() 60 | { 61 | for (int i = 0; i < allAllocList_.size(); i++) { 62 | delete []allAllocList_[i]; 63 | } 64 | } 65 | 66 | // 默认对象池大小为100 67 | static const int defaultSize = 100; 68 | // 默认块大小,即每次分配内存时的增量 69 | static const int defaultChunk = 10; 70 | 71 | int chunkSize_; 72 | // 空闲队列 73 | std::queue freeQueue_; 74 | // 已分配的内存 75 | std::vector allAllocList_; 76 | }; 77 | 78 | int main(int argc, char **args) 79 | { 80 | ObjectPool pool; 81 | 82 | int &a = pool.acquireObject(); 83 | pool.releaseObject(a); 84 | 85 | return 0; 86 | } -------------------------------------------------------------------------------- /other/skip_list.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | // note: 因为我们分配内存使用的是malloc,所以key和value的类型不要是STL中的容器, 9 | // 否则的话可能会出现问题(运行时错误) 10 | typedef int KeyType; 11 | typedef int ValueType; 12 | 13 | typedef struct node 14 | { 15 | KeyType key; // key值 16 | ValueType value; // value值 17 | struct node* next[1]; // 后继数组 18 | } Node; 19 | 20 | typedef struct skip_list 21 | { 22 | int level; // 层数 23 | Node **head; // 指向头结点 24 | } SkipList; 25 | 26 | #define MAX_LEVEL 6 27 | #define new_node(n) \ 28 | ((Node*)malloc(sizeof(Node)+(n)* sizeof(Node*))) 29 | 30 | static int RandomLevel() 31 | { 32 | int level = 1; 33 | 34 | while (rand() % 2) { 35 | level++; 36 | } 37 | level = (level > MAX_LEVEL ? MAX_LEVEL : level); 38 | return level; 39 | } 40 | 41 | // 创建节点 42 | static Node* CreateNode(int level, KeyType key, ValueType value) 43 | { 44 | Node* node = (Node *)malloc(sizeof(Node) + sizeof(Node*) * level); 45 | if (!node) { 46 | return NULL; 47 | } 48 | 49 | node->key = key; 50 | node->value = value; 51 | return node; 52 | } 53 | 54 | // 创建跳表 55 | SkipList* CreateSkipList() 56 | { 57 | SkipList *list = (SkipList*)malloc(sizeof(SkipList)); 58 | if (!list) { 59 | return NULL; 60 | } 61 | 62 | list->level = MAX_LEVEL; 63 | list->head = (Node **)malloc(sizeof(Node*) * MAX_LEVEL); 64 | if (!list->head) { 65 | free(list); 66 | return NULL; 67 | } 68 | // 将head的next数组初始化 69 | for (int i = 0; i < MAX_LEVEL; i++) { 70 | list->head[i] = NULL; 71 | } 72 | 73 | srand(time(NULL)); 74 | return list; 75 | } 76 | 77 | // 跳表插入操作 78 | // step1: 查找到在每层待插入位置,更新update数组 79 | // step2: 产生一个随机层数 80 | // step3: 从高层向下插入,与普通链表的插入完全相同 81 | bool Insert(SkipList* list, KeyType key, ValueType value) 82 | { 83 | 84 | // key需要插入在该跳表的第一个节点位置 85 | if (!list->head[0] || key < list->head[0]->key) { 86 | // level的大小不会超过 MAX_LEVEL 87 | int level = RandomLevel(); 88 | Node *temp = CreateNode(level - 1, key, value); 89 | if (!temp) { 90 | return false; 91 | } 92 | 93 | for (int i = level - 1; i >= 0; i--) { 94 | temp->next[i] = list->head[i]; 95 | list->head[i] = temp; 96 | } 97 | // 插入成功 98 | return true; 99 | } 100 | 101 | Node *update[MAX_LEVEL]; 102 | Node *p, *q; 103 | int i; 104 | 105 | for (i = 0; i < MAX_LEVEL; i++) { 106 | update[i] =list->head[i]; 107 | } 108 | 109 | i = list->level - 1; 110 | for (; i >= 0; i--) { 111 | p = q = update[i]; 112 | while (p && p->key < key) { 113 | q = p; 114 | p = p->next[i]; 115 | } 116 | update[i] = q; 117 | } 118 | if (p && p->key == key) { 119 | // 跳表中已存在该key 120 | p->value = value; 121 | return true; 122 | } 123 | 124 | // level的大小不会超过 MAX_LEVEL 125 | int level = RandomLevel(); 126 | Node *temp = CreateNode(level - 1, key, value); 127 | if (!temp) { 128 | return false; 129 | } 130 | 131 | // 逐层更新节点的指针,和普通链表插入一样 132 | for (i = level - 1; i >= 0; i--) { 133 | if (update[i]) { 134 | temp->next[i] = update[i]->next[i]; 135 | update[i]->next[i] = temp; 136 | } 137 | else { 138 | temp->next[i] = update[i]; 139 | } 140 | } 141 | return true; 142 | } 143 | 144 | // 跳表销毁操作 145 | void FreeSkipList(SkipList *list) 146 | { 147 | Node *node = list->head[0], *remove; 148 | 149 | while (node) { 150 | remove = node; 151 | node = node->next[0]; 152 | free(remove); 153 | } 154 | free(list->head); 155 | free(list); 156 | } 157 | 158 | #define SKIP_LIST_DEBUG 159 | #ifdef SKIP_LIST_DEBUG 160 | void PrintSkipList(const SkipList* list) 161 | { 162 | Node *node = list->head[0]; 163 | 164 | while (node) { 165 | std::cout << node->key << ": " << node->value << endl; 166 | node = node->next[0]; 167 | } 168 | } 169 | #endif 170 | 171 | int main(int argc, char** argv) 172 | { 173 | SkipList *list = CreateSkipList(); 174 | 175 | for (int i = 0; i < 100; i++) { 176 | Insert(list, 100 - i, i); 177 | } 178 | 179 | PrintSkipList(list); 180 | 181 | FreeSkipList(list); 182 | 183 | return 0; 184 | } 185 | -------------------------------------------------------------------------------- /search/bianry_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int binary_search(int a[], int length, int key); 6 | 7 | int main(void) 8 | { 9 | int a[6] = { 1, 2, 3, 4, 5, 6}; 10 | 11 | int index = binary_search(a, 6, 4); 12 | if (index != -1) 13 | cout << "find it, index = " << index << endl; 14 | else 15 | cout << "not find it" << endl; 16 | 17 | return 0; 18 | } 19 | 20 | /** 21 | * @brief 二分查找 22 | * @param [in] key:待查找的键 23 | * [in] a:查找数组 24 | * [in] length:数组长度 25 | * @return 找到为该键在数组中的下标,否则为-1 26 | * @note while (low <= high)不能改为<,否则的话条件判断不完整,比如: 27 | * a[3] = {1, 3, 5};待查找的键为5,此时在(low < high)条件下就会找不到 28 | * 因为low和high相等时,指向元素5,但是此时条件不成立,没有进入while()中 29 | */ 30 | int binary_search(int a[], int length, int key) 31 | { 32 | int left = 0; 33 | int right = length - 1; 34 | 35 | while (left <= right) 36 | { 37 | int mid = left + ((right - left) >> 1); 38 | if (key == a[mid]) 39 | return mid; 40 | else if (key < a[mid]) 41 | right = mid - 1; 42 | else 43 | left = mid + 1; 44 | } 45 | 46 | return -1; 47 | } -------------------------------------------------------------------------------- /search/bianry_search更多扩展.cpp: -------------------------------------------------------------------------------- 1 | // 以下是二分查找的各种变种 2 | // 查找第一个与key相等的值、最后一个与key相等的值、第一个等于或大于key的值、 3 | // 第一个大于key的值、最后一个小于或等于key的值、最后一个小于key的值 4 | // 参考链接:http://blog.chinaunix.net/uid-1844931-id-3337784.html 5 | 6 | #include 7 | using namespace std; 8 | 9 | int FindFirstEqual(int a[], int length, int key); 10 | int FindLastEqual(int a[], int length, int key); 11 | int FindFirstEqualLarger(int a[], int length, int key); 12 | int FindFirstLarger(int a[], int length, int key); 13 | int FindLastEqualSmaller(int a[], int length, int key); 14 | int FindLastSmaller(int a[], int length, int key); 15 | 16 | int main(void) 17 | { 18 | int a1[5] = { 1, 2, 2, 3, 4 }; 19 | int a2[5] = { 2, 2, 3, 4, 5 }; 20 | int a3[5] = { 1, 2, 3, 4, 4 }; 21 | 22 | cout << FindLastSmaller(a1, 5, 2) << endl; 23 | cout << FindLastSmaller(a2, 5, 2) << endl; 24 | cout << FindLastSmaller(a3, 5, 4) << endl; 25 | cout << FindLastSmaller(a1, 5, -3) << endl; 26 | cout << FindLastSmaller(a1, 5, 12) << endl; 27 | 28 | return 0; 29 | } 30 | 31 | /// 查找第一个与key相等的值 32 | int FindFirstEqual(int a[], int length, int key) 33 | { 34 | int left = 0; 35 | int right = length - 1; 36 | 37 | while (left <= right) 38 | { 39 | int mid = left + ((right - left) >> 1); 40 | if (key <= a[mid]) 41 | right = mid - 1; 42 | else 43 | left = mid + 1; 44 | } 45 | 46 | if (left < length && a[left] == key) 47 | return left; 48 | 49 | return -1; 50 | } 51 | 52 | /// 查找最后一个与key相等的值 53 | int FindLastEqual(int a[], int length, int key) 54 | { 55 | int left = 0; 56 | int right = length - 1; 57 | 58 | while (left <= right) 59 | { 60 | int mid = left + ((right - left) >> 1); 61 | if (key >= a[mid]) 62 | left = mid + 1; 63 | else 64 | right = mid - 1; 65 | } 66 | 67 | if (right >= 0 && a[right] == key) 68 | return right; 69 | 70 | return -1; 71 | } 72 | 73 | /// 查找第一个等于或大于key的值 74 | int FindFirstEqualLarger(int a[], int length, int key) 75 | { 76 | int left = 0; 77 | int right = length - 1; 78 | 79 | while (left <= right) 80 | { 81 | int mid = left + ((right - left) >> 1); 82 | if (key <= a[mid]) 83 | right = mid - 1; 84 | else 85 | left = mid + 1; 86 | } 87 | 88 | return left; 89 | } 90 | 91 | /// 查找第一个大于key的值 92 | int FindFirstLarger(int a[], int length, int key) 93 | { 94 | int left = 0; 95 | int right = length - 1; 96 | 97 | while (left <= right) 98 | { 99 | int mid = left + ((right - left) >> 1); 100 | if (key >= a[mid]) 101 | left = mid + 1; 102 | else 103 | right = mid - 1; 104 | } 105 | 106 | return left; 107 | } 108 | 109 | /// 查找最后一个等于或小于key的值 110 | int FindLastEqualSmaller(int a[], int length, int key) 111 | { 112 | int left = 0; 113 | int right = length - 1; 114 | 115 | while (left <= right) 116 | { 117 | int mid = left + ((right - left) >> 1); 118 | if (key >= a[mid]) 119 | left = mid + 1; 120 | else 121 | right = mid - 1; 122 | } 123 | 124 | return right; 125 | } 126 | 127 | /// 查找最后一个小于key的值 128 | int FindLastSmaller(int a[], int length, int key) 129 | { 130 | int left = 0; 131 | int right = length - 1; 132 | 133 | while (left <= right) 134 | { 135 | int mid = left + ((right - left) >> 1); 136 | if (key > a[mid]) 137 | left = mid + 1; 138 | else 139 | right = mid - 1; 140 | } 141 | 142 | return right; 143 | } -------------------------------------------------------------------------------- /search/hash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hash.h" 3 | 4 | Lhash::Lhash(int _capacity) : sizes(0) 5 | { 6 | if (_capacity <= CAPACITY_INIT) 7 | capacity = _capacity; 8 | else 9 | capacity = nextPrime(_capacity + 1); 10 | 11 | array = new LhashNode[capacity]; 12 | for (int i = 0; i < capacity; i++) 13 | { 14 | array[i].data = 0; 15 | array[i].next = NULL; 16 | } 17 | } 18 | 19 | Lhash::~Lhash() 20 | { 21 | for (int i = 0; i < capacity; i++) 22 | { 23 | if (array[i].next) 24 | removeList(array[i].next); 25 | } 26 | delete []array; 27 | } 28 | 29 | void Lhash::insert(DataType data) 30 | { 31 | int index = hash(data); 32 | LhashNode *phead = array[index].next; 33 | 34 | LhashNode *pnode = new LhashNode; 35 | pnode->data = data; 36 | pnode->next = NULL; 37 | 38 | if (!phead) // 此时对应的为空链表 39 | { 40 | array[index].next = pnode; 41 | array[index].data++; // 该链表中元素个数 42 | sizes++; // hash表中元素个数 43 | } 44 | else 45 | { 46 | LhashNode *pprev = &array[index]; // pprev为phead的前一个节点 47 | while (phead && phead->data < data) 48 | { 49 | pprev = phead; 50 | phead = phead->next; 51 | } 52 | 53 | // phead为NULL时pnode应插入到链表结尾,phead->data != data表示pnode应该插入phead前面 54 | if (!phead || phead->data != data) 55 | { 56 | pnode->next = phead; 57 | pprev->next = pnode; 58 | array[index].data++; 59 | sizes++; 60 | } 61 | } 62 | } 63 | 64 | void Lhash::remove(DataType data) 65 | { 66 | bool found = find(data); 67 | 68 | if (found) 69 | { 70 | int index = hash(data); 71 | LhashNode *pnode = &array[index]; 72 | while (pnode->next && pnode->next->data != data) 73 | pnode = pnode->next; 74 | 75 | LhashNode *ptmp = pnode->next; 76 | pnode->next = ptmp->next; 77 | delete ptmp; 78 | 79 | array[index].data--; 80 | sizes--; 81 | } 82 | } 83 | 84 | bool Lhash::find(DataType data) 85 | { 86 | int index = hash(data); 87 | 88 | LhashNode *pnode = array[index].next; 89 | while (pnode) 90 | { 91 | if (pnode->data == data) 92 | return true; 93 | else if (pnode->data > data) // 链表中元素按从小到大顺序排列 94 | return false; 95 | pnode = pnode->next; 96 | } 97 | 98 | return false; 99 | } 100 | 101 | void Lhash::print() const 102 | { 103 | for (int i = 0; i < capacity; i++) 104 | { 105 | std::cout << i << ": "; 106 | printList(array[i].next); 107 | } 108 | } 109 | 110 | void Lhash::removeList(LhashNode *phead) 111 | { 112 | LhashNode *pnode = phead; 113 | 114 | while (pnode) 115 | { 116 | LhashNode *ptmp = pnode->next; 117 | delete pnode; 118 | pnode = ptmp; 119 | } 120 | } 121 | 122 | void Lhash::printList(LhashNode *pnode) const 123 | { 124 | while (pnode) 125 | { 126 | std::cout << pnode->data << " "; 127 | pnode = pnode->next; 128 | } 129 | std::cout << std::endl; 130 | } 131 | 132 | int Lhash::nextPrime(int n) const 133 | { 134 | while (n) 135 | { 136 | bool isprime = true; 137 | for (int i = 2; i <= n/2; i++) 138 | { 139 | if (n % i == 0) 140 | { 141 | isprime = false; 142 | break; 143 | } 144 | } 145 | if (isprime) 146 | break; 147 | 148 | n++; 149 | } 150 | return n; 151 | } -------------------------------------------------------------------------------- /search/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_H 2 | #define HASH_H 3 | 4 | typedef int DataType; 5 | struct LhashNode 6 | { 7 | DataType data; 8 | LhashNode *next; 9 | }; 10 | 11 | /// Lhash才用的是分离连接法,对应一个链表的顺序为从小到大排列 12 | class Lhash 13 | { 14 | static const int CAPACITY_INIT = 23; // 初始化数组大小,一个素数 15 | public: 16 | Lhash(int _capacity = CAPACITY_INIT); 17 | ~Lhash(); 18 | 19 | void insert(DataType data); 20 | void remove(DataType data); 21 | // 存在data返回true,否则返回false 22 | bool find(DataType data); 23 | 24 | int size() const { return sizes; } 25 | void print() const; 26 | 27 | private: 28 | // 哈希函数 29 | int hash(int n) const { return (n % capacity); } 30 | // 释放一个链表 31 | void removeList(LhashNode *phead); 32 | // 打印一个链表 33 | void printList(LhashNode *phead) const; 34 | // 返回大于等于n的第一个素数 35 | int nextPrime(int n) const; 36 | 37 | int sizes; // hash表中元素个数 38 | int capacity; // hash表的数组大小 39 | LhashNode *array; // hash表的数组 40 | }; 41 | 42 | #endif -------------------------------------------------------------------------------- /search/hash_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hash.h" 3 | 4 | using namespace std; 5 | 6 | int main(void) 7 | { 8 | Lhash lhash; 9 | 10 | lhash.insert(12); 11 | lhash.insert(14); 12 | lhash.insert(145); 13 | lhash.insert(11); 14 | lhash.insert(14 + 46); 15 | lhash.insert(14 + 23); 16 | 17 | cout << "the hash size: " << lhash.size() << endl; 18 | lhash.print(); 19 | cout << endl; 20 | 21 | lhash.remove(14 + 23); 22 | lhash.remove(14 + 46); 23 | lhash.remove(14); 24 | cout << "the hash size: " << lhash.size() << endl; 25 | lhash.print(); 26 | cout << endl; 27 | 28 | if (lhash.find(14 + 23)) 29 | cout << "find it" << endl; 30 | else 31 | cout << "not find it" << endl; 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /search/rbtree.cpp: -------------------------------------------------------------------------------- 1 | #include "rbtree.h" 2 | #include 3 | 4 | Rbtree::Rbtree() : nil(new TreeNode(0, NULL)) 5 | { 6 | nil->color = BLACK; 7 | nil->sentinel = nil; 8 | nil->left = nil->right = nil->par = nil; 9 | 10 | root = nil; 11 | } 12 | 13 | Rbtree::~Rbtree() 14 | { 15 | if (root != nil) 16 | delete root; 17 | 18 | delete nil; // 释放哨兵节点内存 19 | } 20 | 21 | void Rbtree::insert(DataType data) 22 | { 23 | if (root == nil) 24 | { 25 | root = new TreeNode(data, nil); 26 | root->color = BLACK; 27 | nil->data++; 28 | } 29 | else 30 | { 31 | TreeNode *pnode = root; 32 | TreeNode *prevnode = pnode; // prenode是pnode的父节点,初始化为pnode 33 | while (pnode != nil) 34 | { 35 | prevnode = pnode; 36 | if (data < pnode->data) 37 | pnode = pnode->left; 38 | else if (data > pnode->data) 39 | pnode = pnode->right; 40 | else 41 | return; // 此时插入的节点rbtree中已经存在了 42 | } 43 | 44 | TreeNode *insertnode = new TreeNode(data, nil); 45 | nil->data++; 46 | 47 | insertnode->par = prevnode; 48 | if (data < prevnode->data) 49 | prevnode->left = insertnode; 50 | else 51 | prevnode->right = insertnode; 52 | 53 | if (prevnode->color == RED) 54 | insert_internal(insertnode); 55 | } 56 | } 57 | 58 | void Rbtree::remove(DataType data) 59 | { 60 | TreeNode *pz = find(data); 61 | if (pz == nil) 62 | return; 63 | 64 | TreeNode *px, *py; 65 | Color py_oldcolor; 66 | 67 | py = pz; 68 | py_oldcolor = py->color; 69 | if (pz->left == nil) 70 | { 71 | px = pz->right; 72 | transplant(pz, px); 73 | } 74 | else if (pz->right == nil) 75 | { 76 | px = pz->left; 77 | transplant(pz, px); 78 | } 79 | else 80 | { 81 | py = min(pz->right); 82 | py_oldcolor = py->color; 83 | px = py->right; 84 | 85 | if (py->par == pz) 86 | { 87 | px->par = py; 88 | } 89 | else 90 | { 91 | transplant(py, py->right); 92 | py->right = pz->right; 93 | py->right->par = py; 94 | } 95 | 96 | root = root; 97 | transplant(pz, py); 98 | py->left = pz->left; 99 | py->left->par = py; 100 | py->color = pz->color; 101 | } 102 | 103 | if (py_oldcolor == BLACK) 104 | remove_internal(px); 105 | 106 | pz->left = pz->right = nil; // 这样保证只是释放对应的一个节点,而不是释放以该节点为根节点的子树 107 | delete pz; // 删除一个节点的时候,节点数量会自动减少,nil->data-- 108 | } 109 | 110 | const TreeNode *Rbtree::find(DataType data) const 111 | { 112 | TreeNode *pnode = root; 113 | 114 | while (pnode != nil) 115 | { 116 | if (data < pnode->data) 117 | pnode = pnode->left; 118 | else if (data > pnode->data) 119 | pnode = pnode->right; 120 | else 121 | return pnode; 122 | } 123 | return nil; 124 | } 125 | 126 | void Rbtree::rotateLeft(TreeNode *px) 127 | { 128 | TreeNode *py = px->right; 129 | 130 | px->right = py->left; 131 | if (py->left != nil) 132 | py->left->par = px; 133 | 134 | py->par = px->par; 135 | if (px == root) 136 | root = py; 137 | else if (px == px->par->left) 138 | px->par->left = py; 139 | else 140 | px->par->right = py; 141 | 142 | px->par = py; 143 | py->left = px; 144 | } 145 | 146 | void Rbtree::rotateRight(TreeNode *px) 147 | { 148 | TreeNode *py = px->left; 149 | 150 | px->left = py->right; 151 | if (py->right != nil) 152 | py->right->par = px; 153 | 154 | py->par = px->par; 155 | if (px == root) 156 | root = py; 157 | else if (px == px->par->left) 158 | px->par->left = py; 159 | else 160 | px->par->right = py; 161 | 162 | px->par = py; 163 | py->right = px; 164 | } 165 | 166 | void Rbtree::insert_internal(TreeNode *px) 167 | { 168 | while (px->par->color == RED) 169 | { 170 | if (px->par == px->par->par->left) 171 | { 172 | TreeNode *py = px->par->par->right; 173 | 174 | // Case1: px uncle node py is red 175 | if (py->color == RED) 176 | { 177 | py->color = BLACK; 178 | px->par->color = BLACK; 179 | px->par->par->color = RED; 180 | px = px->par->par; 181 | } 182 | else 183 | { 184 | // Case2: px uncle node py is black, but px is right node 185 | if (px == px->right) 186 | { 187 | px = px->par; 188 | rotateLeft(px); 189 | } 190 | 191 | // Case3: px uncle node py is black, but px is left node 192 | px->par->color = BLACK; 193 | px->par->par->color = RED; 194 | rotateRight(px->par->par); 195 | } 196 | } 197 | else // px parent node is right node 198 | { 199 | TreeNode *py = px->par->par->left; 200 | 201 | if (py->color == RED) 202 | { 203 | py->color = BLACK; 204 | px->par->color = BLACK; 205 | px->par->par->color = RED; 206 | px = px->par->par; 207 | } 208 | else 209 | { 210 | if (px == px->par->left) 211 | { 212 | px = px->par; 213 | rotateRight(px); 214 | } 215 | 216 | px->par->color = BLACK; 217 | px->par->par->color = RED; 218 | rotateLeft(px->par->par); 219 | } 220 | } 221 | } 222 | 223 | root->color = BLACK; 224 | } 225 | 226 | /** 227 | * @brief 修复因删除操作而引起的红黑树性质破坏 228 | * @param [in] px:红黑树节点px 229 | * @return void 230 | * @note 在这四种情况中,1、2、3情况都不会引起px->par节点的左子树和右子树的黑节点路径长度变化 231 | * px节点所在的子树黑节点长度比px->par的另一个子树黑节点长度小1,在情况4中会修复该状况 232 | */ 233 | void Rbtree::remove_internal(TreeNode *px) 234 | { 235 | TreeNode *py = NULL; 236 | 237 | while (px != root && px->color == BLACK) 238 | { 239 | if (px == px->par->left) 240 | { 241 | py = px->par->right; 242 | if (py->color == RED) // 情况1:px的兄弟节点py是红色 243 | { 244 | py->color = BLACK; 245 | px->par->color = RED; 246 | rotateLeft(px->par); 247 | py = px->par->right; 248 | } 249 | 250 | if (py->left->color == BLACK && py->right->color == BLACK) //情况2:px的兄弟节点py是黑色,而且py的两个子节点都是黑色的 251 | { 252 | py->color = RED; 253 | px = px->par; 254 | } 255 | else 256 | { 257 | if (py->right->color == BLACK) // 情况3:px的兄弟节点w是黑色的,py的左孩子是红色的,py的右孩子是黑色的 258 | { 259 | py->left->color = BLACK; 260 | py->color = RED; 261 | rotateRight(py); 262 | py = px->par->right; 263 | } 264 | 265 | py->color = px->par->color; // 情况4:px的兄弟节点py是黑色的,且py的右孩子是红色的 266 | px->par->color = BLACK; 267 | py->right->color = BLACK; 268 | rotateLeft(px->par); 269 | px = root; 270 | } 271 | } 272 | else 273 | { 274 | py = px->par->left; 275 | if (py->color == RED) 276 | { 277 | py->color = BLACK; 278 | px->par->color = RED; 279 | rotateRight(px->par); 280 | py = px->par->left; 281 | } 282 | 283 | if (py->left->color == BLACK && py->right->color == BLACK) 284 | { 285 | py->color = RED; 286 | px = px->par; 287 | } 288 | else 289 | { 290 | if (py->left->color == BLACK) 291 | { 292 | py->right->color = BLACK; 293 | py->color = RED; 294 | rotateLeft(py); 295 | py = px->par->left; 296 | } 297 | 298 | py->color = px->par->color; 299 | px->par->color = BLACK; 300 | py->left->color = BLACK; 301 | rotateRight(px->par); 302 | px = root; 303 | } 304 | } 305 | } 306 | px->color = BLACK; 307 | } 308 | 309 | void Rbtree::print_internal(TreeNode *pnode) const 310 | { 311 | if (pnode != nil) 312 | { 313 | print_internal(pnode->left); 314 | std::cout << pnode->data; 315 | std::cout << (pnode->color == BLACK ? " black" : " red") << std::endl; 316 | print_internal(pnode->right); 317 | } 318 | } 319 | 320 | TreeNode *Rbtree::min(TreeNode *pnode) const 321 | { 322 | while (pnode->left != nil) 323 | pnode = pnode->left; 324 | return pnode; 325 | } -------------------------------------------------------------------------------- /search/rbtree.h: -------------------------------------------------------------------------------- 1 | #ifndef RBTREE_H 2 | #define RBTREE_H 3 | 4 | #include 5 | 6 | typedef int DataType; 7 | enum Color { RED, BLACK }; 8 | 9 | class TreeNode 10 | { 11 | public: 12 | Color color; 13 | DataType data; 14 | TreeNode *left; 15 | TreeNode *right; 16 | TreeNode *par; // 父节点 17 | TreeNode *sentinel; // 哨兵节点 18 | 19 | TreeNode(DataType _data, TreeNode *_sentinel) : color(RED), data(_data) 20 | { 21 | sentinel = _sentinel; 22 | left = right = par = _sentinel; 23 | } 24 | ~TreeNode() 25 | { 26 | if (left != sentinel) 27 | delete left; 28 | if (right != sentinel) 29 | delete right; 30 | 31 | sentinel->data--; // 树中的节点个数 32 | //std::cout << "remove node ok" << std::endl; // 显示释放节点记录 33 | } 34 | }; 35 | 36 | class Rbtree 37 | { 38 | public: 39 | Rbtree(); 40 | ~Rbtree(); 41 | 42 | void insert(DataType data); 43 | void remove(DataType data); 44 | 45 | const TreeNode *find(DataType data) const; 46 | TreeNode *find(DataType data) { return const_cast(((const Rbtree *)this)->find(data)); } 47 | int size() const { return nil->data; } 48 | void print() const { print_internal(root); } 49 | 50 | private: 51 | // 左旋操作和右旋操作 52 | void rotateLeft(TreeNode *pnode); 53 | void rotateRight(TreeNode *pnode); 54 | 55 | // 插入后的修正函数 56 | void insert_internal(TreeNode *pnode); 57 | // 删除后的修正函数 58 | void remove_internal(TreeNode *pnode); 59 | // 调整两个节点关系,其中一个替换另一个,newnode要替换oldnode,在删除节点操作中用到 60 | void transplant(TreeNode *oldnode, TreeNode *newnode) 61 | { 62 | if (oldnode->par == nil) // 此时oldnode为根节点 63 | root = newnode; 64 | else if (oldnode == oldnode->par->left) 65 | oldnode->par->left = newnode; 66 | else 67 | oldnode->par->right = newnode; 68 | 69 | newnode->par = oldnode->par; 70 | } 71 | 72 | void print_internal(TreeNode *pnode) const; 73 | TreeNode *min(TreeNode *pnode) const; 74 | 75 | TreeNode *root; // 根节点 76 | TreeNode *nil; // 哨兵节点,nil.data作为rbtree的节点个数 77 | }; 78 | 79 | #endif -------------------------------------------------------------------------------- /search/rbtree_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rbtree.h" 3 | 4 | using namespace std; 5 | 6 | int main(void) 7 | { 8 | Rbtree tree; 9 | 10 | tree.insert(200); 11 | tree.insert(1); 12 | tree.insert(12); 13 | 14 | tree.insert(10); 15 | tree.insert(23); 16 | 17 | tree.insert(14); 18 | tree.insert(39); 19 | tree.insert(59); 20 | 21 | tree.insert(69); 22 | tree.insert(30); 23 | tree.insert(25); 24 | 25 | cout << "size: " << tree.size() << endl; 26 | tree.print(); 27 | cout << endl; 28 | 29 | tree.remove(25); 30 | tree.remove(69); 31 | tree.remove(30); 32 | tree.remove(23); 33 | cout << "size: " << tree.size() << endl; 34 | tree.print(); 35 | cout << endl; 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /search/二叉查找树.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | typedef int DataType; 5 | 6 | class TreeNode 7 | { 8 | public: 9 | DataType data; 10 | TreeNode *left; 11 | TreeNode *right; 12 | 13 | TreeNode(DataType _data) : data(_data), left(NULL), right(NULL) {} 14 | ~TreeNode() 15 | { 16 | if (left) 17 | delete left; 18 | if (right) 19 | delete right; 20 | 21 | } 22 | }; 23 | 24 | class BinaryTree 25 | { 26 | public: 27 | BinaryTree() : root(NULL), sizes(0) {} 28 | ~BinaryTree() 29 | { 30 | if (root) 31 | delete root; 32 | } 33 | 34 | void insert(DataType data) { root = insert_internal(root, data); } 35 | void remove(DataType data) { root = remove_internal(root, data); } 36 | 37 | // 返回最小/最大节点的指针 38 | const TreeNode *min() const; 39 | const TreeNode *max() const; 40 | void print() const { print_internal(root); std::cout << std::endl; } 41 | size_t size() const { return sizes; } 42 | 43 | // 测试data是否在二叉查找树中 44 | bool find(DataType data) const { return find_internal(root, data); } 45 | 46 | private: 47 | TreeNode *insert_internal(TreeNode *pnode, DataType data); 48 | TreeNode *remove_internal(TreeNode *pnode, DataType data); 49 | bool find_internal(TreeNode *pnode, DataType data) const; 50 | void print_internal(TreeNode *pnode) const; 51 | 52 | TreeNode *root; // 根节点 53 | size_t sizes; // 二叉查找树中节点的个数 54 | }; 55 | 56 | int main(void) 57 | { 58 | BinaryTree tree; 59 | 60 | tree.insert(12); 61 | tree.insert(6); 62 | tree.insert(24); 63 | 64 | cout << "size: " << tree.size() << endl; 65 | if (tree.find(24)) 66 | cout << "find it" << endl; 67 | else 68 | cout << "not find it" << endl; 69 | 70 | const TreeNode *iter = NULL; 71 | iter = tree.min(); 72 | if (iter) 73 | cout << "min: " << iter->data << endl; 74 | iter = tree.max(); 75 | if (iter) 76 | cout << "max: " << iter->data << endl; 77 | 78 | tree.print(); 79 | 80 | tree.remove(12); 81 | cout << "size: " << tree.size() << endl; 82 | tree.print(); 83 | 84 | tree.remove(6); 85 | cout << "size: " << tree.size() << endl; 86 | tree.print(); 87 | 88 | tree.remove(24); 89 | cout << "size: " << tree.size() << endl; 90 | tree.print(); 91 | 92 | return 0; 93 | } 94 | 95 | const TreeNode *BinaryTree::min() const 96 | { 97 | TreeNode *pnode = root; 98 | if (root) 99 | { 100 | while (pnode->left) 101 | pnode = pnode->left; 102 | } 103 | 104 | return pnode; 105 | } 106 | 107 | const TreeNode *BinaryTree::max() const 108 | { 109 | TreeNode *pnode = root; 110 | if (root) 111 | { 112 | while (pnode->right) 113 | pnode = pnode->right; 114 | } 115 | 116 | return pnode; 117 | } 118 | 119 | TreeNode *BinaryTree::insert_internal(TreeNode *pnode, DataType data) 120 | { 121 | if (!pnode) 122 | { 123 | pnode = new TreeNode(data); 124 | sizes++; 125 | } 126 | else if (data < pnode->data) 127 | pnode->left = insert_internal(pnode->left, data); 128 | else 129 | pnode->right = insert_internal(pnode->right, data); 130 | 131 | return pnode; 132 | } 133 | 134 | TreeNode *BinaryTree::remove_internal(TreeNode *pnode, DataType data) 135 | { 136 | if (!pnode) 137 | return NULL; 138 | else if (data < pnode->data) 139 | pnode->left = remove_internal(pnode->left, data); 140 | else if (data > pnode->data) 141 | pnode->right = remove_internal(pnode->right, data); 142 | else if (pnode->left && pnode->right) 143 | { 144 | TreeNode *ptmp = pnode->right; 145 | while (ptmp->left != NULL) 146 | ptmp = ptmp->left; 147 | 148 | pnode->data = ptmp->data; 149 | pnode->right = remove_internal(pnode->right, ptmp->data); 150 | } 151 | else // 删除节点有一个child节点或者没有child节点 152 | { 153 | TreeNode *ptmp = pnode; 154 | if (pnode->left != NULL) 155 | pnode->left; 156 | else if (pnode->right != NULL) 157 | pnode->right; 158 | else // 表示现在删除的是root节点,并且此时二叉树中只有一个root节点 159 | pnode = NULL; 160 | 161 | delete ptmp; //ptmp所指内存已释放,pnode指向ptmp的子树节点,pnode和二叉查找树的连接是在函数返回时,因为函数是递归的 162 | sizes--; 163 | } 164 | 165 | return pnode; 166 | } 167 | 168 | bool BinaryTree::find_internal(TreeNode *pnode, DataType data) const 169 | { 170 | if (!pnode) 171 | return false; 172 | else if (data < pnode->data) 173 | return find_internal(pnode->left, data); 174 | else if (data > pnode->data) 175 | return find_internal(pnode->right, data); 176 | else 177 | return true; 178 | } 179 | 180 | void BinaryTree::print_internal(TreeNode *pnode) const 181 | { 182 | if (pnode) 183 | { 184 | print_internal(pnode->left); 185 | std::cout << pnode->data << " "; 186 | print_internal(pnode->right); 187 | } 188 | } -------------------------------------------------------------------------------- /sort/sort_bubble.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void bubble_sort(int arr[], int length); 8 | 9 | int main(void) 10 | { 11 | const int N = 10; 12 | int left = 0; 13 | int right = 100; 14 | int arr[N]; 15 | 16 | srand(time(NULL)); 17 | for (int i = 0; i < N; i++) 18 | { 19 | int tmp = rand() % (right - left) + left; 20 | arr[i] = tmp; 21 | } 22 | 23 | bubble_sort(arr, N); 24 | 25 | for (int i = 0; i < N; i++) 26 | { 27 | cout << arr[i] << " "; 28 | } 29 | cout << endl; 30 | 31 | return 0; 32 | } 33 | 34 | /** 35 | * @brief: bubble sort 36 | * @param [in] arr:sorted array 37 | * [in] length:the length of arr 38 | * @return void 39 | */ 40 | void bubble_sort(int arr[], int length) 41 | { 42 | for (int i = 0; i < length; i++) 43 | { 44 | for (int j = 0; j < length - i - 1; j++) 45 | { 46 | if (arr[j] > arr[j+1]) 47 | swap(arr[j], arr[j+1]); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sort/sort_heap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | 8 | void heap_sort(int arr[], int length); 9 | 10 | int main(void) 11 | { 12 | const int N = 10 + 1; 13 | int left = 0; 14 | int right = 100; 15 | int arr[N]; 16 | 17 | srand(time(NULL)); 18 | for (int i = 1; i <= N; i++) 19 | { 20 | int tmp = rand() % (right - left) + left; 21 | arr[i] = tmp; 22 | } 23 | 24 | heap_sort(arr, N + 1); 25 | 26 | for (int i = 1; i <= N; i++) 27 | { 28 | cout << arr[i] << " "; 29 | } 30 | cout << endl; 31 | 32 | return 0; 33 | } 34 | 35 | /** 36 | * 堆排序 37 | * 堆排序是用堆来实现的一种排序算法,堆排序分为两个阶段,在堆的构造阶段中,我们将原始数据重新组织安排 38 | * 进一个堆中;然后在下沉排序阶段,我们从堆中按照递减顺序取出所有元素并得到排序算法 39 | */ 40 | void sink(int arr[], int k, int high) 41 | { 42 | while (2 * k <= high) 43 | { 44 | int child = 2 * k; 45 | if (child < high && arr[child] < arr[child + 1]) 46 | child++; 47 | 48 | if (arr[k] < arr[child]) 49 | swap(arr[k], arr[child]); 50 | else 51 | break; 52 | 53 | k = child; 54 | } 55 | } 56 | 57 | void heap_sort(int arr[], int length) 58 | { 59 | int high = length - 1; 60 | 61 | /* 这个需要注意i >= 1,如果是i > 1,则建堆不完全 */ 62 | for (int i = high / 2; i >= 1; i--) 63 | sink(arr, i, high); 64 | 65 | while (high > 1) 66 | { 67 | swap(arr[1], arr[high--]); 68 | sink(arr, 1, high); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /sort/sort_insert.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void insert_sort(int a[], int length); 8 | void insert2_sort(int a[], int length); 9 | 10 | int main(void) 11 | { 12 | const int N = 10; 13 | int left = 0; 14 | int right = 100; 15 | int arr[N]; 16 | 17 | srand(time(NULL)); 18 | for (int i = 0; i < N; i++) 19 | { 20 | int tmp = rand() % (right - left) + left; 21 | arr[i] = tmp; 22 | } 23 | 24 | insert_sort(arr, N); 25 | 26 | for (int i = 0; i < N; i++) 27 | { 28 | cout << arr[i] << " "; 29 | } 30 | cout << endl; 31 | 32 | return 0; 33 | } 34 | 35 | /** 36 | * @brief insert sort 37 | * @param [in] arr: the array be sorted 38 | * [in] length: the array size 39 | * @return void 40 | * @note time complexity O(n^2) 41 | */ 42 | void insert_sort(int arr[], int length) 43 | { 44 | for (int i = 0; i < length; i++) 45 | { 46 | for (int j = i; j > 0 && arr[j-1] > arr[j]; j--) 47 | swap(arr[j], arr[j-1]); 48 | } 49 | } 50 | 51 | void insert2_sort(int arr[], int length) 52 | { 53 | for (int i = 0; i < length; i++) 54 | { 55 | int x = arr[i], j; 56 | for (j = i; j > 0 && arr[j-1] > x; j--) 57 | arr[j] = arr[j-1]; 58 | arr[j] = x; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /sort/sort_merge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void merge_sort(int a[], int length); 8 | 9 | int main(void) 10 | { 11 | const int N = 10; 12 | int left = 0; 13 | int right = 100; 14 | int arr[N]; 15 | 16 | srand(time(NULL)); 17 | for (int i = 0; i < N; i++) 18 | { 19 | int tmp = rand() % (right - left) + left; 20 | arr[i] = tmp; 21 | } 22 | 23 | merge_sort(arr, N); 24 | 25 | for (int i = 0; i < N; i++) 26 | { 27 | cout << arr[i] << " "; 28 | } 29 | cout << endl; 30 | 31 | return 0; 32 | } 33 | 34 | void merge(int a[], int aux[], int left, int mid, int right) 35 | { 36 | int i = left; 37 | int j = mid + 1; 38 | int k = left; 39 | 40 | while (i <= mid && j <= right) 41 | { 42 | if (a[j] < a[i]) 43 | aux[k++] = a[j++]; 44 | else 45 | aux[k++] = a[i++]; 46 | } 47 | while (i <= mid) 48 | aux[k++] = a[i++]; 49 | while (j <= right) 50 | aux[k++] = a[j++]; 51 | 52 | for (i = left; i <= right; i++) 53 | a[i] = aux[i]; 54 | } 55 | 56 | void merge_sort(int a[], int aux[], int left, int right) 57 | { 58 | if (left < right) 59 | { 60 | int mid = left + ((right - left) >> 1); 61 | merge_sort(a, aux, left, mid); 62 | merge_sort(a, aux, mid + 1, right); 63 | merge(a, aux, left, mid, right); 64 | } 65 | } 66 | 67 | /// 自顶向下的归并排序 68 | void merge_sort(int a[], int length) 69 | { 70 | int *aux = new int[length]; 71 | 72 | merge_sort(a, aux, 0, length - 1); 73 | 74 | delete aux; 75 | } 76 | -------------------------------------------------------------------------------- /sort/sort_quick.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | void quick_sort(int arr[], int length); 8 | 9 | int main(void) 10 | { 11 | const int N = 10; 12 | int left = 0; 13 | int right = 100; 14 | int arr[N]; 15 | 16 | srand(time(NULL)); 17 | for (int i = 0; i < N; i++) 18 | { 19 | int tmp = rand() % (right - left) + left; 20 | arr[i] = tmp; 21 | } 22 | 23 | quick_sort(arr, N); 24 | 25 | for (int i = 0; i < N; i++) 26 | { 27 | cout << arr[i] << " "; 28 | } 29 | cout << endl; 30 | 31 | return 0; 32 | } 33 | 34 | /** 35 | * 快速排序 36 | * 快速排序是一种分治的排序算法,它将一个数组分成两个子数组,将两部分独立地排序。 37 | * 快速排序和归并排序是互补的:归并排序将数组分成两个子数组分别排序,并将有序的子数组归并以将整个数组排序; 38 | * 而快速排序的方式是当两个子数组有序时整个数组也就自然有序了。归并排序中,递归发生在处理整个数组之前, 39 | * 一个数组被分为两半;快速排序中,递归调用发生在处理整个数组之后,切分的位置取决于数组的内容。 40 | */ 41 | int partion(int arr[], int left, int right) 42 | { 43 | int x = arr[right]; 44 | int i, j; 45 | 46 | for (i = j = left; i < right; i++) 47 | { 48 | if (arr[i] <= x) 49 | swap(arr[i], arr[j++]); 50 | } 51 | swap(arr[j], arr[right]); 52 | 53 | return j; 54 | } 55 | 56 | void quick_sort(int arr[], int left, int right) 57 | { 58 | if (left < right) 59 | { 60 | int mid = partion(arr, left, right); 61 | quick_sort(arr, left, mid - 1); 62 | quick_sort(arr, mid + 1, right); 63 | } 64 | } 65 | 66 | void quick_sort(int arr[], int length) 67 | { 68 | if (!arr || length <= 1) 69 | return; 70 | 71 | quick_sort(arr, 0, length - 1); 72 | } 73 | 74 | // partion()的第二种写法 75 | /** 76 | * @brief 把数组arr分为两部分,比选择数字小的移到数组的左边,大的移动到数组右边 77 | * @param [in] arr:待划分数组 78 | * [in] left:数组左边界 79 | * [in] right:数组右边界 80 | * @return 所选择数字最后所在位置下标值 81 | */ 82 | int partion2(int arr[], int left, int right) 83 | { 84 | if (left < right) 85 | { 86 | int x = arr[left]; 87 | while (left < right) 88 | { 89 | while (left < right && arr[right] >= x) 90 | right--; 91 | arr[left] = arr[right]; 92 | 93 | while (left < right && arr[left] <= x) 94 | left++; 95 | arr[right] = arr[left]; 96 | } 97 | arr[left] = x; 98 | } 99 | 100 | return left; 101 | } 102 | -------------------------------------------------------------------------------- /sort/sort_radix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | //#include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | // low和high表示元素区间,前开后闭,[low, high) 10 | int low = 0; 11 | int high = 100; 12 | #define N 100 13 | 14 | void radix_sort(int arr[], int length); 15 | 16 | int main(void) 17 | { 18 | int arr[N]; 19 | srand(time(NULL)); 20 | 21 | for (int i = 0; i < N; i++) 22 | { 23 | int x = rand() % (high - low) + low; 24 | arr[i] = x; 25 | } 26 | 27 | radix_sort(arr, N); 28 | 29 | for (int i = 0; i < N; i++) 30 | cout << arr[i] << " "; 31 | cout << endl; 32 | 33 | return 0; 34 | } 35 | 36 | /** 37 | * @brief 基数排序 38 | * @parm [in] arr:待排序的数组 39 | * length:待排序数组大小 40 | * @return void 41 | * @note 基数排序不是基于比较的排序算法 42 | */ 43 | void radix_sort(int arr[], int length) 44 | { 45 | int sectionSize = high - low; 46 | int *aux = new int[length]; 47 | int *cnt = new int[sectionSize]; 48 | 49 | memset(cnt, 0, sizeof(int) * sectionSize); 50 | 51 | for (int i = 0; i < length; i++) // 计算出现频率 52 | cnt[arr[i] + 1]++; 53 | for (int i = 1; i < sectionSize; i++) // 频率转化为索引 54 | cnt[i] += cnt[i - 1]; 55 | for (int i = 0; i < length; i++) // 将元素分类 56 | aux[cnt[arr[i]]++] = arr[i]; 57 | for (int i = 0; i < length; i++) // 回写 58 | arr[i] = aux[i]; 59 | 60 | delete []cnt; 61 | delete []aux; 62 | } 63 | -------------------------------------------------------------------------------- /sort/sort_select.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | void select_sort(int a[], int length); 6 | 7 | #define N 100 8 | int main(void) 9 | { 10 | int left = 0; 11 | int right = 100; 12 | int arr[N]; 13 | 14 | srand(time(NULL)); 15 | 16 | for (int i = 0; i < N; i++) 17 | { 18 | int x = rand() % (right - left) + left; 19 | arr[i] = x; 20 | } 21 | 22 | select_sort(arr, N); 23 | 24 | for (int i = 0; i < N; i++) 25 | cout << arr[i] << " "; 26 | cout << endl; 27 | 28 | return 0; 29 | } 30 | 31 | /** 32 | * @brief select sort 33 | * @param [in] a: the array be sorted 34 | * [in] length: the array size 35 | * @return void 36 | * @note time complexity O(n^2) 37 | */ 38 | void select_sort(int a[], int length) 39 | { 40 | for (int i = 0; i < length; i++) 41 | { 42 | int min = i; 43 | for (int j = i + 1; j < length; j++) 44 | { 45 | if (a[j] < a[min]) 46 | min = j; 47 | } 48 | if (min != i) 49 | swap(a[min], a[i]); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /sort/sort_shell.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | void select_shell(int a[], int length); 6 | 7 | int main(void) 8 | { 9 | int a[5] = {-1, 6, 2, 0, 12}; 10 | 11 | select_shell(a, 5); 12 | for (int i = 0; i < 5; i++) 13 | cout << a[i] << " "; 14 | cout << endl; 15 | 16 | return 0; 17 | } 18 | 19 | /** 20 | * @brief select sort 21 | * @param [in] a: the array be sorted 22 | * [in] length: the array size 23 | * @return void 24 | * @note time complexity O(n^2) 25 | * 希尔排序类似于插入排序,只是插入排序只会交换相邻的元素,而希尔排序 26 | * 会交换不相邻的元素以对数组进行局部排序 27 | */ 28 | void select_shell(int a[], int length) 29 | { 30 | for (int inc = length / 2; inc > 0; inc /= 2) 31 | { 32 | for (int i = inc; i < length; i++) 33 | { 34 | for (int j = i; j >= inc && a[j-inc] > a[j]; j -= inc) 35 | swap(a[j], a[j-inc]); 36 | } 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /string/string_LSD_sort.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | 低位优先的字符串排序 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | void string_lsd(string a[], int length); 12 | 13 | int main(void) 14 | { 15 | string arr[5] = {"name", "main", "null", "turn", "head"}; 16 | 17 | for (int i = 0; i < 5; i++) 18 | cout << arr[i] << " "; 19 | cout << endl; 20 | 21 | string_lsd(arr, 5); 22 | 23 | for (int i = 0; i < 5; i++) 24 | cout << arr[i] << " "; 25 | cout << endl; 26 | 27 | return 0; 28 | } 29 | 30 | const int N = 256; // 字母表的范围 31 | /** 32 | * @brief 低位优先的字符串排序 33 | * @param [in] a:待排序的string数组 34 | * [out] length:string数组中的元素个数 35 | * @return void 36 | * @note 数组中string元素的长度要一样 37 | */ 38 | void string_lsd(string a[], int length) 39 | { 40 | string *aux = new string[length]; 41 | int *count = new int[N + 1]; 42 | 43 | for (int k = length - 1; k >= 0; k--) 44 | { 45 | memset(count, 0, sizeof(int)* (N + 1)); 46 | 47 | for (int i = 0; i < length; i++) //计算出现频率 48 | count[(int)a[i][k] + 1]++; 49 | for (int i = 1; i < N + 1; i++) //将频率转换为索引 50 | count[i] += count[i - 1]; 51 | for (int i = 0; i < length; i++) //将元素分类 52 | aux[count[(int)a[i][k]]++] = a[i]; 53 | for (int i = 0; i < length; i++) //回写 54 | a[i] = aux[i]; 55 | } 56 | 57 | delete []count; 58 | delete []aux; 59 | } 60 | -------------------------------------------------------------------------------- /string/string_huffman.cpp: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | Huffman实际上会生成二进制流,这里把输入字符串翻译为二进制的字符串,比如"AAB"翻译为“001”,'A'为'0',‘B’为'1' 4 | 这样使用输出时更以观察生成的结果 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | struct HuffNode 15 | { 16 | char data; 17 | size_t freq; 18 | HuffNode *left; 19 | HuffNode *right; 20 | 21 | HuffNode() : data('\0'), freq(0), left(NULL), right(NULL) {} 22 | ~HuffNode() 23 | { 24 | if (left) 25 | delete left; 26 | if (right) 27 | delete right; 28 | } 29 | }; 30 | 31 | class HuffTree 32 | { 33 | public: 34 | HuffTree(const char *str) : rawStr(str), root(NULL), freqVec(N) { init(); } 35 | HuffTree(const string &str) : rawStr(str), root(NULL), freqVec(N) { init(); } 36 | ~HuffTree(); 37 | 38 | void printCodingVec(); 39 | void setBinStr(); 40 | void printBinStr(); 41 | void printRawStr() { cout << rawStr << endl; } 42 | 43 | private: 44 | static const size_t N = 256; 45 | string rawStr; 46 | string binStr; 47 | HuffNode *root; // Huffman tree 48 | vector> freqVec; 49 | vector> codingVec; 50 | 51 | void init(); 52 | void makeFreqVec(); 53 | void makeTree(); 54 | void makeCodingVec(HuffNode *root); 55 | }; 56 | 57 | int main(void) 58 | { 59 | HuffTree tree("ABCACAABF"); 60 | 61 | tree.printCodingVec(); 62 | 63 | tree.setBinStr(); 64 | tree.printRawStr(); 65 | tree.printBinStr(); 66 | 67 | return 0; 68 | } 69 | 70 | 71 | HuffTree::~HuffTree() 72 | { 73 | if (root) 74 | delete root; 75 | } 76 | 77 | void HuffTree::printCodingVec() 78 | { 79 | for (size_t i = 0; i < codingVec.size(); i++) 80 | { 81 | cout << codingVec[i].first << ": " << codingVec[i].second << endl; 82 | } 83 | } 84 | 85 | void HuffTree::setBinStr() 86 | { 87 | for (size_t i = 0; i < rawStr.size(); i++) 88 | { 89 | for (size_t j = 0; j < codingVec.size(); j++) 90 | { 91 | if (rawStr[i] == codingVec[j].first) 92 | binStr += codingVec[j].second; 93 | } 94 | } 95 | } 96 | 97 | void HuffTree::printBinStr() 98 | { 99 | cout << binStr << endl; 100 | } 101 | 102 | template 103 | struct greator 104 | { 105 | bool operator()(const T &x, const T &y) 106 | { 107 | return (x->freq > y->freq); // 建立的是小堆 108 | } 109 | }; 110 | 111 | void HuffTree::init() 112 | { 113 | makeFreqVec(); 114 | makeTree(); 115 | makeCodingVec(root); 116 | } 117 | 118 | void HuffTree::makeFreqVec() 119 | { 120 | if (rawStr.empty()) 121 | return; 122 | 123 | for (size_t i = 0; i < rawStr.size(); i++) 124 | { 125 | freqVec[(size_t)rawStr[i]].second++; 126 | } 127 | } 128 | 129 | void HuffTree::makeTree() 130 | { 131 | if (rawStr.empty()) 132 | return; 133 | 134 | vector treeVec; 135 | for (size_t i = 0; i < N; i++) 136 | { 137 | if (freqVec[i].second) 138 | { 139 | HuffNode *pnode = new HuffNode; 140 | 141 | pnode->data = (char)i; 142 | pnode->freq = freqVec[i].second; 143 | treeVec.push_back(pnode); 144 | } 145 | } 146 | 147 | make_heap(treeVec.begin(), treeVec.end(), greator()); 148 | size_t length = treeVec.size(); 149 | 150 | for (size_t i = 0; i < length - 1; i++) 151 | { 152 | pop_heap(treeVec.begin(), treeVec.end(), greator()); 153 | HuffNode *pnode1 = treeVec.back(); 154 | treeVec.pop_back(); 155 | 156 | pop_heap(treeVec.begin(), treeVec.end(), greator()); 157 | HuffNode *pnode2 = treeVec.back(); 158 | treeVec.pop_back(); 159 | 160 | HuffNode *pnode = new HuffNode; 161 | pnode->data = -1; // 表示为内部节点 162 | pnode->freq = pnode1->freq + pnode2->freq; 163 | pnode->left = pnode1; 164 | pnode->right = pnode2; 165 | 166 | treeVec.push_back(pnode); 167 | push_heap(treeVec.begin(), treeVec.end(), greator()); 168 | } 169 | 170 | root = treeVec.front(); 171 | } 172 | 173 | void HuffTree::makeCodingVec(HuffNode *pnode) 174 | { 175 | if (!pnode) 176 | return; 177 | 178 | static vector cvec; 179 | 180 | if ((int)pnode->data > 0) // 内部节点的data域为-1,初始化为0 181 | { 182 | string s(cvec.begin(), cvec.end()); 183 | pair tmp(pnode->data, s); 184 | 185 | codingVec.push_back(tmp); 186 | } 187 | 188 | cvec.push_back('0'); 189 | makeCodingVec(pnode->left); 190 | cvec.pop_back(); 191 | 192 | cvec.push_back('1'); 193 | makeCodingVec(pnode->right); 194 | cvec.pop_back(); 195 | } 196 | -------------------------------------------------------------------------------- /string/string_kmp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int KmpSearch(char *s, char *p); 6 | 7 | int main(void) 8 | { 9 | char pstr[] = "BBC ABCDAB ABCDABCDABDE"; 10 | char pfind[] = "ABCDABD"; 11 | 12 | int index = KmpSearch(pstr, pfind); 13 | if (index == -1) 14 | cout << "not find" << endl; 15 | else 16 | cout << (char *)&pstr[index] << endl; 17 | 18 | return 0; 19 | } 20 | 21 | // 通过代码递推计算求得的next数组 22 | void GetNext(char *p, int next[]) 23 | { 24 | if (!p || !next) 25 | return; 26 | 27 | int length = strlen(p); 28 | int j = 0; 29 | int k = -1; 30 | 31 | next[0] = -1; 32 | while (j < length - 1) // 根据next[j]的值来求next[j+1]的值,所以j != length-1 33 | { 34 | // p[k]表示前缀,p[j]表示后缀 35 | if (k == -1 || p[j] == p[k]) 36 | { 37 | k++; 38 | j++; 39 | next[j] = k; 40 | } 41 | else 42 | { 43 | k = next[k]; 44 | } 45 | } 46 | } 47 | 48 | /// KMP搜索 49 | int KmpSearch(char *s, char *p) 50 | { 51 | int lengthS = strlen(s); 52 | int lengthP = strlen(p); 53 | int i = 0, j = 0; 54 | 55 | int *next = new int[lengthP]; 56 | 57 | GetNext(p, next); 58 | while (i < lengthS && j < lengthP) 59 | { 60 | if (j == -1 || s[i] == p[j]) 61 | { 62 | i++; 63 | j++; 64 | } 65 | else 66 | { 67 | j = next[j]; 68 | } 69 | } 70 | 71 | delete next; 72 | if (j == lengthP) 73 | return i - j; 74 | else 75 | return -1; 76 | } 77 | 78 | 79 | /// 暴力搜索1 80 | int Search1(const char *pstr, const char *pfind) 81 | { 82 | int n = strlen(pstr); 83 | int m = strlen(pfind); 84 | 85 | for (int i = 0; i <= n - m; i++) 86 | { 87 | int j; 88 | for (j = 0; j < m; j++) 89 | { 90 | if (pstr[i + j] != pfind[j]) 91 | break; 92 | } 93 | 94 | if (j == m) 95 | return i; 96 | } 97 | 98 | return n; 99 | } 100 | 101 | /// 暴力搜索2 102 | int Search2(const char *pstr, const char *pfind) 103 | { 104 | int n = strlen(pstr); 105 | int m = strlen(pfind); 106 | int i, j; 107 | 108 | for (i = j = 0; i < n && j < m; i++) 109 | { 110 | if (pstr[i] == pfind[j]) 111 | j++; 112 | else 113 | { 114 | i -= j; 115 | j = 0; 116 | } 117 | } 118 | 119 | if (j == m) 120 | return i - m; 121 | else 122 | return n; 123 | } 124 | -------------------------------------------------------------------------------- /string/单词查找树.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | /// 单词查找树的节点 7 | struct Node 8 | { 9 | static const int R = 26; // 总共有26个字母 10 | int value; // 存放编号,初始化为-1 11 | Node *arr[R]; 12 | 13 | Node() : value(-1) 14 | { 15 | for (int i = 0; i < R; i++) 16 | arr[i] = NULL; 17 | } 18 | ~Node() 19 | { 20 | for (int i = 0; i < R; i++) 21 | { 22 | if (arr[i]) 23 | { 24 | delete arr[i]; 25 | arr[i] = NULL; 26 | } 27 | } 28 | } 29 | }; 30 | 31 | /// 单词查找树数据结构,单词全部是小写 32 | class WordTree 33 | { 34 | public: 35 | WordTree() : root(new Node), word_size(0) {} 36 | ~WordTree() { delete root; } 37 | 38 | // 往单词查找树中插入一个单词key,value为该单词的序号 39 | void insert(const string &key, int value) { insert_internal(root, key, value, 0); } 40 | 41 | // 查找key是否在单词查找树中 42 | bool find(string key) const { return find_internal(root, key, 0); } 43 | 44 | int size() const { return word_size; } 45 | void print() const 46 | { 47 | vector vec; 48 | print_internal(root, vec); 49 | } 50 | 51 | private: 52 | int getID(char c) const { return c - 'a'; } 53 | 54 | // 插入单词key,value为该单词序号,depth为当前插入的深度,当depth为key.size()时表示插入已经完成 55 | Node *insert_internal(Node *pnode, const string &key, int value, int depth); 56 | 57 | bool find_internal(Node *pnode, string &key, int depth) const; 58 | 59 | void print_internal(Node *pnode, vector &vec) const; 60 | 61 | Node *root; // 根节点 62 | int word_size; // 单词查找树中存放单词的个数 63 | }; 64 | 65 | int main(void) 66 | { 67 | WordTree wtree; 68 | 69 | wtree.insert("sea", 2); 70 | wtree.insert("she", 0); 71 | wtree.insert("sells", 1); 72 | 73 | cout << wtree.size() << endl; 74 | if (wtree.find("she")) 75 | cout << "find it" << endl; 76 | else 77 | cout << "not find" << endl; 78 | 79 | wtree.print(); 80 | 81 | return 0; 82 | } 83 | 84 | Node *WordTree::insert_internal(Node *pnode, const string &key, int value, int depth) 85 | { 86 | if (!pnode) 87 | { 88 | pnode = new Node; 89 | } 90 | if (depth == key.size()) 91 | { 92 | pnode->value = value; 93 | word_size++; // 完成插入一个单词了 94 | return pnode; 95 | } 96 | 97 | char c = key[depth]; 98 | pnode->arr[getID(c)] = insert_internal(pnode->arr[getID(c)], key, value, depth + 1); 99 | 100 | return pnode; 101 | } 102 | 103 | bool WordTree::find_internal(Node *pnode, string &key, int depth) const 104 | { 105 | if (!pnode) 106 | return false; 107 | if (depth == key.size()) 108 | return true; 109 | 110 | char c = key[depth]; 111 | return find_internal(pnode->arr[getID(c)], key, depth + 1); 112 | } 113 | 114 | void WordTree::print_internal(Node *pnode, vector &vec) const 115 | { 116 | if (!pnode) 117 | return; 118 | 119 | for (int i = 0; i < Node::R; i++) 120 | { 121 | if (pnode->arr[i]) 122 | { 123 | vec.push_back(i + 'a'); 124 | print_internal(pnode->arr[i], vec); 125 | 126 | if (pnode->arr[i]->value != -1) // 已经到达一个单词的终点,打印 127 | { 128 | cout << pnode->arr[i]->value << ": "; 129 | for (int i = 0; i < vec.size(); i++) 130 | cout << vec[i]; 131 | cout << endl; 132 | } 133 | 134 | vec.pop_back(); 135 | } 136 | } 137 | } --------------------------------------------------------------------------------