项目作者: LemonPi

项目描述 :
Simple algorithms library
高级语言: C++
项目地址: git://github.com/LemonPi/sal.git
创建时间: 2014-12-30T05:42:31Z
项目社区:https://github.com/LemonPi/sal

开源协议:

下载


SAL - simple algorithms and datastructures library

A c++ header only library containing efficient algorithms and data structures implemented simply.

Simplicity here refers to how close the implementation matches the core concepts of each algorithm,
rather than the triviality of each algorithm.

For detailed documentation and some analysis, see my portfolio


Features

decoupled algorithms so most files are standalone

  • contest friendly
  • paste specific functions in without the rest of the library



simple implementation of efficient algorithms

  • learning friendly
  • engineered for readability


Getting started

  1. open cmd/terminal and change directory to somewhere in your include path (ex. /usr/local/include)
  2. type git clone --recursive git@github.com:LemonPi/sal.git
  3. if you missed #2 and cloned it without --recursive, get the submodules with git submodule update --init


Motivation

I enjoyed some features of the boost library (namely variant), but found the library too cumbersome as a whole.
Using it in a set up environment was fine, but it was impossible to understand conceptual slices of it.
It wasn’t the best resource to learn the concepts from, and you couldn’t (in most cases) use functions from it for contests.

The focus for this library is on representing the concepts

Table of contents

For examples, look at algotest.cpp and datatest.cpp

Algorithms

sal/algo/numerics.h —- numeric
  • Θ(lg(exponent)) modular exponentiation
  • Θ(lg(exponent)) integer exponentiation
  • Θ(lg(n)) fibonacci generation
  • Θ(prime) cyclic number generation and detection (1/prime in a given base)
  • Θ(M(n)) checking for perfect square (M(n) is the complexity of the multiplication algorithm used)
  • Θ(lg(ab)) greatest common denominator of integers a and b
  • totient (number coprimes below)
  • Θ(n^3) matrix chain multiplication ordering
  • prime factorize
  • number of total factors
  • sum of total factors
sal/algo/perm.h —- permutation and combination
  • kth permutation of an indexable sequence
  • all permutations (non-distinct)
  • all permutations (distinct)
  • generate all possible combinations using each element in sequence
  • count ways to generate a sum using a set number of elements of given value
sal/algo/prime.h —- prime generation and manipulation
  • sequence of primes
  • nth prime
  • prime closest to a number
  • prime after a number
  • count primes below a number
  • check if prime
sal/algo/search.h —- basic searching, substring matching, and finding longest common features
  • binary search on sorted sequence
  • intersection of a set of sets
  • order statistic select
  • matching word inside sentence
  • longest common substring
  • longest common subsequence
  • longest common subsequence length
  • suffix array (data structure for substring searches)
sal/algo/sort.h —- comparison, distributive, and hybrid sorts
  • partition
  • bubble sort
  • linear insertion sort
  • binary insertion sort
  • merge sort
  • quick sort
  • heap sort
  • counting sort
  • radix sort
  • tim sort
  • patience sort
sal/algo/string.h —- edit distances
  • levenshtein distance
sal/algo/utility.h —- utility and testing functions
  • random integer generation
  • timer
  • perturb a sequence (soft random shuffle)
  • fast pointer hashing

Data structures

sal/data/list.h —- basic linked list
sal/data/heap.h —- binary heap
  • maxheap by default
  • Ө(1) time search
  • Ө(n) time construction and batch insert
  • Ө(lgn) time insert
  • Ө(lgn) time extract top
  • Ө(lgn) time change key (check key if value was indirectly changed)
sal/data/matrix.h —- 2D matrix
  • square identities
  • random matrices
  • efficient multiplication of a sequence of matrices
  • resizable
sal/data/infint.h —- infinity precision integers (Sercan Tutar’s)
sal/data/tree.h —- red black tree and augmentations of it
  • easily extensible base RB tree
  • node iterator
  • order statistic tree augmentation
  • treap
  • order statistic tree
sal/data/interval.h —- interval tree
  • overlapping regions or time intervals
  • collision resolution
  • scheduling
sal/data/graph.h —- directed and undirected graphs
  • adjacency matrix (not really supported)
  • adjacency list
  • vertex iterator
  • adjacency iterator
sal/data/graph/search.h —- graph searches
  • Ө(V + E) breadth first search
  • Ө(V + E) depth first search
  • Ө(V + E) recursive depth first search
  • visitors for custom actions at certain points of DFS
sal/data/graph/utility.h —- important graph algorithms
  • Ө(V + E) topological sort
  • Ө(V + E) check for cycle
  • Ө(V + E) transpose of graph
  • Ө(V + E) strongly connected components
  • O((V + E)lgV) minimum spanning tree
sal/data/graph/shortest.h —- shortest paths for different graphs or trees
  • single source algorithms:
  • O(VE) Bellman-Ford (allows negative edges)
  • O(V + E) shortest dag (directed acyclic graph)
  • O((V + E)lgV) Dijkstra (non-negative edges)
sal/data/graph/linear.h —- linear programming
  • O(mn) Difference constraint feasibility (m <- # constraints, n <- # variables)

Example usage

namespace sal will be used implicitely here
functions that take iterator pairs are overloaded to take containers as well

numeric" class="reference-link">sal/algo/numeric.h —- numeric
  1. // 7^91 % 10
  2. modular_pow(7, 91, 10);
  3. // int 3
  4. // 13789^722341 % 2345
  5. modular_pow(13789, 722341, 2345);
  6. // int 2029
  7. int_pow(5, 3);
  8. // int 125
  9. fibonacci<Infint>(1000);
  10. // Infint 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875
  11. // repeating part of 1/7 in base 10
  12. make_cyclic(10, 7);
  13. // size_t 142857
  14. // length of repeating part of 1/7 in base 10
  15. cycle_length(10, 7);
  16. // size_t 6
  17. // check if number is an integer power of a base
  18. is_pow(4194304,4);
  19. // bool true
  20. // check if number is a perfect square
  21. is_square(21489798124);
  22. // bool false
  23. // greatest common denominator
  24. gcd(56, 91);
  25. // unsigned int 7
  26. // chain matrix multiplication ordering to minimize work
  27. std::vector<Matrix<int>> mats;
  28. size_t row {30}, col {35};
  29. for (int i = 0; i != 100; ++i) {
  30. // generate sequence of random matrices
  31. mats.push_back(random_matrix<int>(row, col, 0, 50));
  32. // next matrix's row must be prev matrix's col
  33. row = col;
  34. col = rand() % 100 + 5; // between 5 - 105
  35. }
  36. mul(mats);
  37. // Matrix<int>
  38. totient(500);
  39. phi(500);
  40. // big_int 200 (200 numbers below 500 that are coprime with it)
  41. size_t num = 421412;
  42. // prime factorize regular numbers (usually smooth) ----------
  43. factorize(421412);
  44. // vector<size_t> 2 2 137 769 (in order)
  45. num_factors(num);
  46. // size_t 12 (1 2 4 137 274 548 769 1538 3076 105353 210706 421412)
  47. sum_factors(num);
  48. // size_t 743820 (1 + 2 + 4 + 137 + ... + 421412)
  49. // factorize primes or semiprimes ----
  50. big_int semiprime = 32452843 * 32452867; // 1053187797650881
  51. // would still not be too slow
  52. factorize(semiprime);
  53. // would be faster
  54. factorize_rough(semiprime);
  55. // would be much faster for repeated uses (primes are kept static)
permutation and combination" class="reference-link">sal/algo/perm.h —- permutation and combination
  1. std::string words {"Hello"};
  2. // modifies the sequence without return
  3. // algorithms work on any indexable sequence, string is the example's sequence type
  4. // k is from 0 to s.size()! - 1
  5. perm(words, 1);
  6. // sequence "oHell"
  7. llperms(words);
  8. // vector<sequence> (120 permutations of "Hello")
  9. allperms_distinct(words);
  10. // set<sequence> (60 distinct permutations of "Hello")
  11. std::vector<int> ints {1,2,3,4,5,6};
  12. std::set<int> int_add {combine(ints,
  13. [](int a, int b){return a + b;})};
  14. // 2 3 4 5 6 7 8 9 10 11 12 handshake by adding
  15. std::set<int> int_add_odd {combine(ints,
  16. [](int a, int b){return a + b;},
  17. [](int a, int b){return (a & 1) && (b & 1);})};
  18. // 2 4 6 8 10 handshake by adding odd elements
  19. std::vector<int> coins {1, 2, 5, 10, 20, 50, 100, 200};
  20. int combos = count_combos(coins, 200);
  21. // size_t 73682 (ways to sum up to 200 using coins)
prime generation and manipulation" class="reference-link">sal/algo/prime.h —- prime generation and manipulation
  1. // keep a sieve object if continuous work with primes is needed
  2. using big_int = size_t;
  3. Sieve<big_int> sieve;
  4. while (true) sieve.next_prime();
  5. // generate infinite stream of primes (each of big_int)
  6. sieve.nth_prime(1000);
  7. // big_int 7919 (1000th prime)
  8. sieve.is_prime(sieve.nth_prime(420000));
  9. // bool true (the 4200000th prime is a prime!)
  10. sieve.count(1000000);
  11. // size_t 78498 primes below a million
  12. sieve.closest_prime(50000);
  13. // big_int 49999
  14. sieve.next_prime(50000);
  15. // big_int 50021,
  16. sieve.primes_upto(1000000);
  17. // vector<big_int> (78498 primes that are under one million)
basic searching, substring matching, and finding longest common features" class="reference-link">sal/algo/search.h —- basic searching, substring matching, and finding longest common features
  1. std::vector<int> seq {1,3,12,14,15,18,20};
  2. // bin_search assumes sequence is in order and elements are comparable
  3. bin_search(seq.begin(), seq.end(), 12);
  4. // iterator to element 12
  5. bin_search(seq.begin(), seq.end(), 17);
  6. // iterator seq.end()
  7. std::vector<int> seq2 {1,3,5,6,7,8,20,32};
  8. std::vector<int> seq3 {2,3,6,9,20,32,45,55};
  9. intersection(std::set<vector<int>>{seq, seq2, seq3});
  10. // unordered_set {3, 20} (elements shared by all 3 sequences)
  11. std::string a {"It was the best of times..."};
  12. std::string b {"That's the best orange juice!"};
  13. lc_substr(a, b);
  14. // string "s the best o"
  15. lc_subseq(a, b);
  16. // string "as the best o ie"
  17. lc_subseq_len(a, b);
  18. // size_t 16
  19. sub_match(a, std::string{"the best"});
  20. // const_iterator to 't' in a
  21. // find ith smallest element (1 is smallest)
  22. std::vector<int> v {632, 32, 31, 50, 88, 77, 942, 5, 23};
  23. select(v.begin(), v.end(), 4);
  24. // iterator to 4th element (50)
comparison, distributive, and hybrid sorts" class="reference-link">sal/algo/sort.h —- comparison, distributive, and hybrid sorts
  1. std::vector<int> u {632, 32, 31, 88, 77, 942, 5, 23};
  2. partition(u.begin(), u.end());
  3. // iterator to pivot 77
  4. // 23 32 31 5 77 942 88 632 (all elements < 77 on left and > 77 on right)
  5. std::vector<int> v {randgen(1048576, 100000)}; // 2^20
  6. bub_sort(v.begin(), v.end());
  7. // need to know maximum for counting sort, else wastes one pass finding maximum
  8. cnt_sort(v.begin(), v.end(), 1048577);
  9. // can also not specify anything, additional call to min_max
  10. cnt_sort(v.begin(), v.end());
  11. // sort only on only bits 20-12 which only requires 2^8 = 256 bits of storage
  12. cnt_sort(v.begin(), v.end(), 256, [](int n){return (n & 0xFF000) >> 12;});
  13. // binary insertion sort
  14. ins_sort(v.begin(), v.end());
  15. heap_sort(v.begin(), v.end());
  16. // linear insertion sort
  17. lin_sort(v.begin(), v.end());
  18. mer_sort(v.begin(), v.end());
  19. // patience sort, really slow in practice
  20. pat_sort(v.begin(), v.end());
  21. qck_sort(v.begin(), v.end());
  22. // need to know maximum for counting sort, else uses the maximum bit of size
  23. rdx_sort(v.begin(), v.end(), 20); // 20 bits needed for 2^20 max
  24. tim_sort(v.begin(), v.end());
edit distances" class="reference-link">sal/algo/string.h —- edit distances
  1. // # edit actions including insertion, deletion, or substitution to turn source into new
  2. levenshtein("Saturday", "Sunday");
  3. // size_t 3
utility and testing functions" class="reference-link">sal/algo/utility.h —- utility and testing functions
  1. // precision timing, starts counting when constructed
  2. Timer timing;
  3. // generate random vector of integers for testing
  4. int max_value = 50000;
  5. int element_number = 4000;
  6. randgen(max_value, element_number);
  7. // vector<int> (4000 elements with values between 0 and 50000)
  8. // restart timer
  9. timing.restart();
  10. std::vector<int> v;
  11. v.reserve(element_number);
  12. for (int i = 0; i < element_number; ++i) v.push_back(i);
  13. // vector 1 2 3 4 5 ... 50000
  14. // randomly displace elements of v probabilistically 5 elements away from sorted position
  15. perturb(v.begin(), v.end(), 5);
  16. // print a sequence so elements are separated by space
  17. print(v);
  18. timing.tonow();
  19. // double in microseconds
basic linked list" class="reference-link">sal/data/list.h —- basic linked list
  1. // Construction ----------------------
  2. Basic_list<int> l {5, 7, 11, 13, 17, 19};
  3. std::cout << l;
  4. // 5 7 11 13 17 19
  5. // Queries ---------------------------
  6. l.kth_last(2);
  7. // pointer to node 19
  8. std::cout << l.kth_last(2)->data << std::endl;
  9. // 19
  10. // Modification ----------------------
  11. // insert at head
  12. l.insert(3);
  13. l.print();
  14. // 3 5 7 11 13 17 19
  15. // append to tail
  16. l.append(23);
  17. // 3 5 7 11 13 17 19 23
  18. // insert after the 2nd last
  19. l.insert_after(19, l.kth_last(2));
  20. // 3 5 7 11 13 17 19 19 23
  21. l.erase(13);
  22. // 3 5 7 11 17 19 19 23
  23. // remove duplicates
  24. l.remove_dup();
  25. // 3 5 7 11 17 19 23
Binary heap" class="reference-link">sal/data/heap.h —- Binary heap
  1. // great for use as a priority queue
  2. // advantage over std::priority_queue or using make_heap and friends
  3. // can find key in Ө(1) time and change its value in Ө(lgn) time
  4. // can also check key for indirect value update (from comparator)
  5. // Construction ----------------------
  6. // by default maxheap using std::greater<T> as Cmp
  7. Heap<int> maxheap {3, 4, 6, 5, 1, 8, 11, 12};
  8. // can also construct via iterator range
  9. std::vector<int> temp {3, 4, 6, 5, 1, 8, 11, 12};
  10. Heap<int> maxheap2 {temp.begin(), temp.end()}
  11. // give a different comparator
  12. Heap<int, std::less<int>> minheap {3, 4, 6, 5, 1, 8, 11, 12};
  13. // a stateful comparator, for example the one used in minimum spanning tree
  14. // looks up vertices' minimum edge in each step of Prim's algorithm
  15. template <typename Property_map>
  16. struct Prim_cmp {
  17. using V = typename Property_map::key_type;
  18. // keep reference to a mapping that might change
  19. const Property_map& property;
  20. Prim_cmp(const Property_map& p) : property(p) {}
  21. // u and v will always be valid vertices, so no need to check for not found
  22. bool operator()(const V& u, const V& v) const {
  23. return property.find(u)->second.min_edge < property.find(v)->second.min_edge;
  24. }
  25. };
  26. // minimum spanning tree's property map
  27. using Cmp = Prim_cmp<MPM<Graph>>;
  28. using V = Graph::vertex_type;
  29. MPM<Graph> property;
  30. Cmp cmp {property};
  31. // ... load necessary info into property
  32. // constructor for stateful comparator
  33. Heap<V, Cmp> queue {cmp};
  34. // Ө(n) batch insert
  35. queue.batch_insert(g.begin(), g.end());
  36. // Queries ---------------------------
  37. // looking at top (min in a minheap, max in a maxheap)
  38. maxheap.top();
  39. // value_type 12
  40. // index used to change and check elements held at key Ө(1) lookup
  41. maxheap.key(12);
  42. // size_t 1
  43. // Iterations ------------------------
  44. // begin and end as per standard
  45. for (auto v : maxheap) std::cout << v << ' ';
  46. // Modification ----------------------
  47. // pop top and return it
  48. maxheap.extract_top();
  49. // value_type 12 (top() did not modify top)
  50. // change key to something that has "greater" value
  51. // for maxheap: increase key, for minheap: decrease key
  52. // does nothing if you attempt to decrease value
  53. maxheap.change_key(maxheap.key(12), 13);
  54. // directly change using value (does a key lookup in the background)
  55. maxheap.change_val(13, 15);
  56. // indirectly change key by affecting the comparator
  57. // for example in the relaxation step of minimum spanning tree
  58. property[edge.dest()].min_edge = edge.weight();
  59. // to affect change in the queue, check the key (will update it if heap violations exist)
  60. queue.check_key(queue.key(edge.dest()));
  61. // inserts into proper position
  62. maxheap.insert(2);
  63. // batch insertion, as shown above
  64. maxheap.batch_insert(temp.begin(), temp.end());
2D matrix" class="reference-link">sal/data/matrix.h —- 2D matrix
  1. // Construction ----------------------
  2. Matrix<int> A {{2, 5, 6},
  3. {3, 4, -3},
  4. {7, 8, 0}};
  5. Matrix<int> B {{-1, 1},
  6. {5, -2},
  7. {4, 2}};
  8. // Queries ---------------------------
  9. // size query
  10. A.row();
  11. // size_t 3
  12. B.col();
  13. // size_t 2
  14. // get element (indices from 0)
  15. A.get(1, 2);
  16. // int -3 (2nd row, 3rd col)
  17. // Arithmetic Operations -------------
  18. Matrix<int> F {{1, 1},
  19. {1, 0}};
  20. // matrix exponentiation
  21. F.pow(5);
  22. // Matrix<int>
  23. // 8 5
  24. // 5 3
  25. // matrix addition
  26. F += Matrix<int> {{2, 5}, {5, 7}};
  27. // 10 10
  28. // 10 10
  29. F + Matrix<int>{{1,1},{1,1},{1,1}};
  30. // runtime error exception from adding different dimensions
  31. // for least work in multiplying matrices, use mul(sequence) from numeric.h
  32. Matrix<int> C = A * B;
  33. // Matrix<int>
  34. // 2 5 6 -1 1 47 4
  35. // 3 4 -3 5 -2 --> 5 -11
  36. // 7 8 0 4 2 33 -9
  37. // Modification ----------------------
  38. // individual elements can be changed by get()
  39. // size modification
  40. Matrix<int> id3 {identity<int>(3)};
  41. // 1 0 0
  42. // 0 1 0
  43. // 0 0 1
  44. // default for new elements is 0
  45. id3.resize(4,5,2);
  46. // 1 0 0 2 2
  47. // 0 1 0 2 2
  48. // 0 0 1 2 2
  49. // 2 2 2 2 2
  50. id3.resize(2,2);
  51. // 1 0
  52. // 0 1
  53. // clockwise rotation
  54. C.rotate();
  55. // 33 5 47
  56. // -9 -11 4
red black tree and augmentations of it" class="reference-link">sal/data/tree.h —- red black tree and augmentations of it
  1. // Basic tree usage ------------------
  2. Basic_tree<int> t {5, 3, 7, 1, 9, 4, 2, 0, 10, 8, 6};
  3. // insert element
  4. t.insert(5);
  5. // erase element
  6. t.erase(1);
  7. // find element
  8. auto node = t.find(5);
  9. // iterator to node holding 5
  10. t.find(11);
  11. // iterator to end == t.end()
  12. // Iterations ------------------------
  13. // iteration over adjacent nodes (left to right)
  14. for (auto adjacent = node.begin(); adjacent != node.end(); ++adjacent)
  15. std::cout << *adjacent << ' ';
  16. // * operator returns key
  17. // iteration over all nodes (in order)
  18. using Node = Basic_node<int>;
  19. std::for_each(t.begin(), t.end(),
  20. [](const Node& node){std::cout << node.key << ' ';});
  21. // Extending Tree for an augmented data structure ---------
  22. // first step is creating a node
  23. /* requires
  24. 1. key element that can be compared using <
  25. 2. static node pointer nil, sentinel
  26. 3. parent, left, and right pointers initialized to nil
  27. 4. Color attribute, BLACK for nil and RED for non-nil
  28. */
  29. template <typename T>
  30. struct Order_node {
  31. static Order_node* nil;
  32. using key_type = T;
  33. T key;
  34. Order_node *parent, *left, *right;
  35. // # of descendent nodes including itself = left->size + right->size + 1
  36. size_t size;
  37. Color color;
  38. Order_node() : size{0}, color{Color::BLACK} {} // sentinel construction
  39. Order_node(T val) : key{val}, parent{nil}, left{nil}, right{nil}, size{1}, color{Color::RED} {}
  40. };
  41. template <typename T>
  42. Order_node<T>* Order_node<T>::nil {new Order_node{}};
  43. // Augmented tree need to publically inherit from Tree<Node>
  44. // it should use the following protected members from Tree<node>
  45. template <typename Node>
  46. class Order_augment : public Tree<Node> {
  47. using NP = Node*; // optional
  48. using T = typename Node::key_type; // optional
  49. using Tree<Node>::root;
  50. using Tree<Node>::rb_insert;
  51. using Tree<Node>::transplant;
  52. using Tree<Node>::rb_insert_fixup;
  53. using Tree<Node>::rb_delete_fixup;
  54. // iterators can also be inherited from Tree
  55. using iterator = typename Tree<Node>::iterator;
  56. using const_iterator = typename Tree<Node>::const_iterator;
  57. // override specific virtual methods to maintain augmented property
  58. // tree_insert, rb_delete, rotate_left, and rotate_right
  59. virtual void tree_insert(NP start, NP node) override {
  60. NP parent {Node::nil};
  61. while (start != Node::nil) {
  62. // modification: simply increment size of each ancestor going down
  63. ++start->size;
  64. parent = start;
  65. if (node->key < start->key) start = start->left;
  66. else start = start->right;
  67. }
  68. node->parent = parent;
  69. if (parent == Node::nil) root = node;
  70. else if (node->key < parent->key) parent->left = node;
  71. else parent->right = node;
  72. }
  73. };
  74. // provide convenient user access
  75. template <typename T>
  76. using Order_tree = Order_augment<Order_node<T>>;
  77. // Utilities -------------------------
  78. // non-member functions that work on nodes only
  79. Order_tree<int> t {5, 3, 7, 1, 9, 4, 2, 0, 10, 8, 6};
  80. using NP = Order_node<int>*;
  81. auto node = t.find(5);
  82. // const iterator
  83. // check if t is a valid RB tree, 0 is invalid, else returns blackheight
  84. // PRINTLINE macro is from utility.h
  85. PRINTLINE(t.valid());
  86. // get() on iterators return the raw node pointer
  87. tree_min(node.get());
  88. // node pointer to smallest node rooted at given node pointer
  89. // goes left as far as possible
  90. tree_max(node.get());
  91. // node pointer to largest node, symmetrical to tree_min
  92. tree_predecessor(node.get());
  93. // node pointer to next smallest node
  94. tree_successor(node.get());
  95. // node pointer to next largest node
  96. // traversals take NP root and an operation that acts on NP
  97. inorder_walk(node.get(), [](const NP node){std::cout << node->key << ' ';});
  98. preorder_walk(node.get(), [](const NP node){std::cout << node->key << ' ';});
  99. postorder_walk(node.get(), [](const NP node){std::cout << node->key << ' ';});
  100. // Order statistics tree usage (with t above)
  101. // Queries ---------------------------
  102. // selecting ith smallest
  103. t.select(4);
  104. t[4];
  105. // iterator to node holding 4th smallest (3)
  106. // select is overloaded on constness, operator[] is always non-const
  107. // check the rank of a node pointer
  108. auto node = t.find(5);
  109. t.rank(node.get());
  110. // size_t 6 (node holding 5 is 6th smallest node)
interval tree" class="reference-link">sal/data/interval.h —- interval tree
  1. // for finding overlapping intervals, useful for scheduling and collision detection
  2. // Construction ----------------------
  3. Interval_set<int> t {{16,21},{8,9},{5,8},{15,23},{25,30},{0, 3},{6, 10},{17,19},
  4. {26,26}, {19,20}};
  5. // Queries ---------------------------
  6. // find any interval overlapping [22, 25]
  7. // overlap by default includes edge, so [25, 26] overlaps [22, 25]
  8. // easily adjustable by changing the strictness of ordering in the no_overlap method
  9. t.find({22, 25});
  10. t.find(22, 25); // overloaded to accept Intervals as well as low, high pairs
  11. // iterator to some overlapping interval, else end()
  12. // find first (earliest) overlapping interval
  13. t.find_first(20, 22);
  14. // iterator to [15, 23] (note that [16, 21] is also overlapping, but starts later)
  15. // find all intervals that match
  16. for (auto interval : t.find_all(20,22)) PRINTLINE(*interval);
  17. // vector<node pointers> [15, 23], [16, 21]
  18. // find exact interval match
  19. t.find_exact(16, 21);
  20. // iterator to [16, 21]
directed and undirected graphs" class="reference-link">sal/data/graph.h —- directed and undirected graphs
  1. // Construction ----------------------
  2. // unweighted is equivalent to having uniform weight 1
  3. // undirected and unweighted graph by default
  4. graph<int> g {{5,1},{5,4},{5,10},{1,4},{4,10}};
  5. // directed and and unweighted graph
  6. digraph<int> g {{5,1},{5,4},{5,10},{1,4},{4,10}};
  7. // undirected and weighted graph
  8. graph<int> g {{5,1,10},{5,4,13},{5,10,17},{1,4,19},{4,10,23}};
  9. // directed and weighted graph
  10. digraph<int> g {{5,1,10},{5,4,13},{5,10,17},{1,4,19},{4,10,23}};
  11. // use a different type for edge weight
  12. digraph<int,double> g {{5,1,0.5},{5,4,0.2},{5,10,0.3},{1,4,10.0},{4,10,0.1}};
  13. // Queries ---------------------------
  14. // number of vertex
  15. g.num_vertex();
  16. // size_t 4
  17. // number of edges
  18. g.num_edge();
  19. // size_t 5
  20. // check if vertex exists
  21. g.is_vertex(5);
  22. // bool true
  23. // check if edge exists
  24. g.is_edge(5, 1);
  25. // bool true
  26. // weight of edge (1 for unweighted, 0 if not found)
  27. g.weight(5, 1);
  28. // int 10
  29. // out degree of a vertex
  30. g.degree(5);
  31. // size_t 3
  32. // Modification ----------------------
  33. // adding vertex (names have to be unique)
  34. g.add_vertex(7);
  35. // adding edge (have to be unique)
  36. // adding edge to non-existent vertices will create them
  37. // weight is 1 by default
  38. g.add_edge(6, 4);
  39. // Iterations ------------------------
  40. // iterate over all vertices ordered by <
  41. for (auto v = g.begin(); v != g.end(); ++v)
  42. std::cout << v;
  43. // 1 4 5 10
  44. // << overloaded for iterators
  45. // adjacency iteration
  46. auto edges = g.adjacent(5);
  47. // alter the weight
  48. for (auto v = edges.first; v != edges.second; ++v)
  49. v.weight() = 1;
  50. // can also be done given a vertex iterator
  51. // get vertex iterator
  52. auto v = g.vertex(5);
  53. // iterator to vertex named 5
  54. // iterate over adjacent vertices u
  55. for (auto u = v.begin(); u != v.end(); ++u)
  56. std::cout << u;
  57. // 1 4 10 (5 has out edges to all of them)
graph searches" class="reference-link">sal/data/graph/search.h —- graph searches
  1. /* algorithms expects Graph to have:
  2. vertex iterators in begin() and end() (and reverse iterators in rbegin(), rend())
  3. * gives vertex name of type V
  4. begin() and end() to give adjacent iterators
  5. adjacent iterator pair in adjacent(V)
  6. * gives vertex name of type V, the destination vertex
  7. dest() gives name of destination vertex (same as * operator)
  8. weight() gives weight of edge to destination vertex
  9. */
  10. // breadth first search --------------
  11. // usually used to find distances to a source node
  12. // works with directed and undirected but have to be unweighted
  13. graph<char> g {{'v','r'},{'r','s'},{'s','w'},{'w','t'},{'t','x'},{'w','x'},{'t','u'},
  14. {'x','u'},{'x','y'},{'u','y'}};
  15. // breadth first search starting from a vertex
  16. auto property = bfs(g, 's');
  17. // property map with distance and parent information
  18. // tracing back parents of each vertex creates a breadth-first tree
  19. for (char vertex = 'u'; ;vertex = property[vertex].parent) {
  20. std::cout << vertex;
  21. if (vertex == 's') break;
  22. std::cout << " <- ";
  23. }
  24. // u <- x <- w <- s
  25. property['u'].distance;
  26. // size_t 3 (number of edges to get to u from s)
  27. // depth first search ----------------
  28. // usually used as part of other algorithms
  29. // can also function to find shortest number of edges from a source node
  30. auto property = dfs(g, 's', 0); // need dummy int variable for overload resolution
  31. // property map with parent and time stamp information
  32. for (char vertex = 'u'; ;vertex = property[vertex].parent) {
  33. std::cout << vertex;
  34. if (vertex == 's') break;
  35. std::cout << " <- ";
  36. }
  37. // u <- t <- w <- s different from bfs, but same length
  38. digraph<char> e {{'u','v'},{'u','x'},{'x','v'},{'v','y'},{'y','x'},
  39. {'w','y'},{'w','z'},{'z','z'}};
  40. // create depth-first forest
  41. auto dfs_property = dfs(e);
  42. // not particularly useful by itself, but very useful for other algorithms
  43. // DFS visitor -----------------------
  44. // actions taken at several key points of searching can be customized
  45. struct Graph_visitor {
  46. // generate vector of vertices to visit
  47. // acts as a stack, visitation happens from back to front
  48. // by default visits every vertex
  49. template <typename Property_map, typename Graph>
  50. std::vector<typename Graph::vertex_type> initialize_vertex(Property_map& property, const Graph& g) {
  51. std::vector<typename Graph::vertex_type> exploring;
  52. for (auto v = g.rbegin(); v != g.rend(); ++v) {
  53. // mark unexplored
  54. property[*v] = {unsigned_infinity, 0, *v};
  55. // expore every vertex
  56. exploring.push_back(*v);
  57. }
  58. return std::move(exploring);
  59. }
  60. // root vertex of a new depth-first tree, when a new unconnected component is discovered
  61. template <typename Graph>
  62. void start_vertex(typename Graph::vertex_type, const Graph&) {}
  63. // when each vertex is first discovered
  64. template <typename Graph>
  65. void discover_vertex(typename Graph::vertex_type, const Graph&) {}
  66. // when a vertex's neighbours are all being explored
  67. template <typename Graph>
  68. void finish_vertex(typename Graph::vertex_type, const Graph&) {}
  69. // when an edge leads to an ancestor vertex of the current exploration path
  70. template <typename Graph>
  71. void back_edge(typename Graph::vertex_type, const Graph&) {}
  72. // when an edge leads to a vertex without a shared ancestor
  73. template <typename Graph>
  74. void forward_or_cross_edge(typename Graph::vertex_type, const Graph&) {}
  75. };
important graph algorithms" class="reference-link">sal/data/graph/utility.h —- important graph algorithms
  1. // topological sort ------------------
  2. // for directed acyclic graph (dag)
  3. // orders all vertices so that parent vertices are always before children
  4. // if vertices are events, then sorting gives one possible sequence of events
  5. // directed edge (u,v) means u has to happen before v
  6. digraph<std::string> dress {{"undershorts", "pants"}, {"undershorts", "shoes"}, {"pants", "belt"},
  7. {"pants", "shoes"}, {"socks", "shoes"}, {"shirt", "belt"}, {"shirt", "tie"}, {"tie", "jacket"},
  8. {"belt", "jacket"}};
  9. dress.add_vertex("watch");
  10. std::list<string> dress_order;
  11. // give a possible ordering of events
  12. topological_sort(dress, std::front_inserter(dress_order));
  13. for (const std::string& item : dress_order) std::cout << item << ' ';
  14. // watch undershorts socks shirt tie pants shoes belt jacket
  15. // perfectly logical sequence of dressing
  16. // cycle testing ---------------------
  17. // some algorithms need directed acyclic graphs (dag)
  18. has_cycle(dress);
  19. // bool true (if false, then the ordering given would be false)
  20. // transpose -------------------------
  21. // create graph with all the edges reversed
  22. transpose(dress);
  23. // graph (of taking off clothes)
  24. // topological sort gives
  25. // watch shoes socks jacket tie belt shirt pants undershorts
  26. // strongly connected components -----
  27. // a SCC is a part of a graph where any vertex can get to any other vertex inside it
  28. // could model trading networks and the like
  29. digraph<std::string> trade {{"China","USA"},{"USA","EU"},{"USA","Canada"},{"USA","Russia"},{"EU","Brazil"},{"EU","France"},
  30. {"Brazil","EU"},{"Brazil","Australia"},{"Canada","China"},{"Canada","Russia"},{"Russia","France"},
  31. {"France","Russia"},{"France","Australia"},{"Australia","Australia"}};
  32. auto mutual_partners = strongly_connected(trade);
  33. // vector of sets of vertex names (strings in this case)
  34. for (const auto& bloc: mutual_partners) {
  35. for (const std::string& country : bloc) std::cout << country << ' ';
  36. cout << '\t';
  37. }
  38. // USA China Canada EU Brazil Russia France Australia
  39. // minimum spanning tree -------------
  40. // for a connected, undirected graph with positive edge weights
  41. // find the cheapest way to connect all the vertices
  42. // ex. connecting nodes on a circuit board
  43. graph<char> circuit {{'a','b',4},{'a','h',8},{'b','h',11},{'b','c',8},{'c','i',2},
  44. {'c','f',4},{'c','d',7},{'d','f',14},{'d','e',9},{'e','f',10},{'f','g',2},
  45. {'i','h',7},{'i','g',6},{'h','g',1}};
  46. // cheapest way to connect all the circuit nodes (suppose edges were wire lengths)
  47. auto mst = min_span_tree(circuit);
  48. // each vertex-property pair from the MST property map
  49. // hold parent and the min_edge cost to parent
  50. // to actually create the tree, simply iterate over vertex and add edge between parent and child
  51. // pm_to_tree works on any property map and undirected graph
  52. graph<char> min_circuit {pm_to_tree(mst)};
shortest path for different graphs and models" class="reference-link">sal/data/graph/shortest.h —- shortest path for different graphs and models
  1. // Single source shortest paths ------
  2. // Bellman-Ford ----------------------
  3. // most general and slowest of path finding algorithms
  4. // O(VE) time since it might have to backtrack
  5. // can find negative weight cycles, in which case it returns an empty property map
  6. digraph<char> g {{'s','t',6},{'s','y',7},{'t','y',8},{'t','x',5},{'t','z',-4},
  7. {'x','t',-2},{'y','x',-3},{'y','z',9},{'z','s',2},{'z','x',7}};
  8. bellman_ford(g, 's');
  9. // property map with parent and distance attributes
  10. // Shortest dag ----------------------
  11. // special case where graph is directed and acyclical
  12. // O(V + E) time by topologically sorting the vertices and relaxing in that order
  13. // can have negative weight since acyclical, so never negative cycles
  14. digraph<char> g {{'r','s',5},{'r','t',3},{'s','t',2},{'s','x',6},{'t','x',7},
  15. {'t','y',4},{'t','z',2},{'x','y',-1},{'x','z',1},{'y','z',-2}};
  16. shortest_dag(g, 's');
  17. // property map with parent and distance attributes
  18. // Dijkstra --------------------------
  19. // directed and non-negative weight
  20. // O((V + E)lgV) time implemented with binary heap priority queue
  21. digraph<char> g {{'s','t',10},{'s','y',5},{'t','y',2},{'t','x',1},{'x','z',4},{'y','t',3},
  22. {'y','x',9},{'y','z',2},{'z','s',7},{'z','x',6}};
  23. dijkstra(g, 's');
  24. // property map with parent and distance attributes
  25. // remember to actually create tree, filter with pm_to_tree
  26. graph<char> shortest_g {pm_to_tree(mst)};
linear programming" class="reference-link">sal/data/graph/linear.h —- linear programming
  1. // optimizing solutions to a system under certain constraints
  2. // mathematically: Ax <= b
  3. // A <- m x n system
  4. // x <- n x 1 solution
  5. // b <- m x 1 constraints
  6. // difference constraints is a specific case of linear programming
  7. // each limit is a difference of 2 variables
  8. // aka each row of A has one 1 and -1, the rest being 0
  9. // resolves into xj - xi <= bk
  10. // create system ---------------
  11. Constraint_sys<int> system {{1,2,0},{1,5,-1},{2,5,1},{3,1,5},{4,1,4},{4,3,-1},
  12. {5,3,-3},{5,4,-3}};
  13. // set of constraints, ex. x1 - x2 <= 0 for the first constraint
  14. // feasibility problem: does any x exist?
  15. // feasible(system, n <- # of variables)
  16. Constraint_sol<int> solution = feasible(system, 5);
  17. // vector<limit type> -5 -3 0 -1 -4
  18. // so x1 is -5, x2 is -3, ..
  19. solution.empty();
  20. // false (true if system of constraints is unfeasible)
  21. // sum of solution and their spread is minimized