├── .analysis_options.yaml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── lib ├── dart_algorithms.dart └── src │ ├── algorithms │ ├── searching.dart │ └── sorting │ │ ├── advanced.dart │ │ └── basic.dart │ └── data_structures │ ├── graph │ └── graph.dart │ ├── hash │ └── hash_table.dart │ ├── linked_list │ ├── doubly_linked_list.dart │ └── linked_list.dart │ ├── queue │ ├── priority_queue.dart │ └── queue.dart │ ├── stack │ ├── stack.dart │ └── stack_example.dart │ └── tree │ └── binary_search_tree.dart ├── pubspec.yaml └── test ├── algorithms ├── searching_test.dart └── sorting_test.dart └── data_structures ├── binary_search_tree_test.dart ├── doubly_linked_list_test.dart ├── graph_test.dart ├── hash_table_test.dart ├── linked_list_test.dart ├── priority_queue_test.dart ├── queue_test.dart └── stack_test.dart /.analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | # see https://github.com/dart-lang/pedantic#enabled-lints. 4 | include: package:pedantic/analysis_options.yaml 5 | 6 | # For lint rules and documentation, see http://dart-lang.github.io/linter/lints. 7 | # Uncomment to specify additional rules. 8 | # linter: 9 | # rules: 10 | # - camel_case_types 11 | 12 | analyzer: 13 | # exclude: 14 | # - path/to/excluded/files/** 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | # Remove the following pattern if you wish to check in your lock file 5 | pubspec.lock 6 | 7 | # Conventional directory for build outputs 8 | build/ 9 | 10 | # Directory created by dartdoc 11 | doc/api/ 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: dart 2 | script: 3 | - pub run test 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jaron Tai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dart-algorithms 2 | ================ 3 | 4 | [![Build status](https://travis-ci.org/jarontai/dart-algorithms.svg)](https://travis-ci.org/jarontai/dart-algorithms) 5 | 6 | `dart-algorithms` - Data structures and algorithms with `Dart`. 7 | 8 | Dart版本的数据结构与算法 9 | 10 | ## Contents 11 | 12 | ### Data Structures 13 | 14 | * [queue](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/data_structures/queue) 15 | * [stack](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/data_structures/stack) 16 | * [linked list](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/data_structures/linked_list) 17 | * [hash](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/data_structures/hash) 18 | * [tree](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/data_structures/tree) 19 | * [graph](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/data_structures/graph) 20 | 21 | ### Algorithms 22 | 23 | * [basic sorting](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/algorithms/sorting/basic.dart) 24 | * [advanced sorting](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/algorithms/sorting/advanced.dart) 25 | * [searching](https://github.com/jarontai/dart-algorithms/tree/master/lib/src/algorithms/searching.dart) 26 | 27 | ## Test 28 | 29 | pub run test 30 | -------------------------------------------------------------------------------- /lib/dart_algorithms.dart: -------------------------------------------------------------------------------- 1 | library dart_algorithms; 2 | 3 | export 'src/data_structures/stack/stack.dart'; 4 | export 'src/data_structures/queue/queue.dart'; 5 | export 'src/data_structures/queue/priority_queue.dart'; 6 | export 'src/data_structures/linked_list/linked_list.dart'; 7 | export 'src/data_structures/linked_list/doubly_linked_list.dart'; 8 | export 'src/data_structures/hash/hash_table.dart'; 9 | export 'src/data_structures/tree/binary_search_tree.dart'; 10 | export 'src/data_structures/graph/graph.dart'; 11 | 12 | export 'src/algorithms/sorting/basic.dart'; 13 | export 'src/algorithms/sorting/advanced.dart'; 14 | export 'src/algorithms/searching.dart'; 15 | -------------------------------------------------------------------------------- /lib/src/algorithms/searching.dart: -------------------------------------------------------------------------------- 1 | int sequentialSearch(List arr, int target) { 2 | for (var i = 0; i < arr.length; i++) { 3 | if (arr[i] == target) { 4 | return i; 5 | } 6 | } 7 | return -1; 8 | } 9 | 10 | int binarySearch(List arr, int target) { 11 | var upper = arr.length - 1; 12 | var lower = 0; 13 | while (lower <= upper) { 14 | var mid = ((upper + lower) / 2).floor(); 15 | if (arr[mid] < target) { 16 | lower = mid + 1; 17 | } else if (arr[mid] > target) { 18 | upper = mid - 1; 19 | } else { 20 | return mid; 21 | } 22 | } 23 | return -1; 24 | } 25 | -------------------------------------------------------------------------------- /lib/src/algorithms/sorting/advanced.dart: -------------------------------------------------------------------------------- 1 | shellSort(List arr, Function swap) { 2 | var gap = (arr.length / 2).floor(); 3 | 4 | while (gap > 0) { 5 | for (var outer = gap; outer < arr.length; outer++) { 6 | for (var inner = outer; inner >= gap; inner -= gap) { 7 | if (arr[inner] < arr[inner - gap]) { 8 | swap(arr, inner, inner - gap); 9 | } else { 10 | break; 11 | } 12 | } 13 | } 14 | 15 | gap = (gap / 2).floor(); 16 | } 17 | 18 | return arr; 19 | } 20 | 21 | mergeSort(List arr, Function swap) { 22 | List merge(List left, List right) { 23 | var result = []; 24 | var i = 0, j = 0; 25 | while (i sort(List arr) { 42 | var length = arr.length; 43 | if (length == 1) { 44 | return arr; 45 | } 46 | var mid = (length / 2).floor(); 47 | List left = arr.sublist(0, mid); 48 | List right = arr.sublist(mid); 49 | return merge(sort(left), sort(right)); 50 | } 51 | 52 | return sort(arr); 53 | } 54 | 55 | quickSort(List arr, Function swap) { 56 | partition(List arr, int left, int right) { 57 | var pivot = arr[((right + left) / 2).floor()]; 58 | var i = left; 59 | var j = right; 60 | 61 | while (i <= j) { 62 | while (arr[i] < pivot) { 63 | i++; 64 | } 65 | while (arr[j] > pivot) { 66 | j--; 67 | } 68 | if (i <= j) { 69 | swap(arr, i, j); 70 | i++; 71 | j--; 72 | } 73 | } 74 | return i; 75 | } 76 | 77 | sort(List arr, int left, int right) { 78 | var index; 79 | if (arr.length > 1) { 80 | index = partition(arr, left, right); 81 | 82 | if (left < index - 1) { 83 | sort(arr, left, index - 1); 84 | } 85 | 86 | if (index < right) { 87 | sort(arr, index, right); 88 | } 89 | } 90 | } 91 | 92 | sort(arr, 0, arr.length - 1); 93 | 94 | return arr; 95 | } 96 | -------------------------------------------------------------------------------- /lib/src/algorithms/sorting/basic.dart: -------------------------------------------------------------------------------- 1 | bubbleSort(List arr, Function swap) { 2 | for (var i = 0; i < arr.length; i++) { 3 | for (var j = 0; j < arr.length - 1 - i; j++) { 4 | if (arr[j] > arr[j + 1]) { 5 | swap(arr, j, j + 1); 6 | } 7 | } 8 | } 9 | return arr; 10 | } 11 | 12 | selectionSort(List arr, Function swap) { 13 | var min; 14 | for (var i = 0; i < arr.length; i++) { 15 | min = i; 16 | for (var j = i; j < arr.length; j++) { 17 | if (arr[j] < arr[min]) { 18 | min = j; 19 | } 20 | } 21 | swap(arr, min, i); 22 | } 23 | return arr; 24 | } 25 | 26 | insertionSort(List arr, Function swap) { 27 | var j, temp; 28 | for (var i = 1; i < arr.length; i++) { 29 | j = i; 30 | temp = arr[i]; 31 | while (j > 0 && arr[j - 1] > temp) { 32 | arr[j] = arr[j - 1]; 33 | j--; 34 | } 35 | arr[j] = temp; 36 | } 37 | return arr; 38 | } 39 | -------------------------------------------------------------------------------- /lib/src/data_structures/graph/graph.dart: -------------------------------------------------------------------------------- 1 | import '../queue/queue.dart'; 2 | 3 | class Graph { 4 | int edges = 0; 5 | Map> adjList = >{}; 6 | Set markSet = new Set(); 7 | 8 | addEdge(T v, T w) { 9 | if (adjList[v] == null) { 10 | adjList[v] = []; 11 | } 12 | adjList[v].add(w); 13 | if (adjList[w] == null) { 14 | adjList[w] = []; 15 | } 16 | adjList[w].add(v); 17 | edges++; 18 | } 19 | 20 | dfs(T v) { 21 | markSet.clear(); 22 | _dfs(v); 23 | } 24 | 25 | _dfs(T v) { 26 | markSet.add(v); 27 | if (adjList.containsKey(v)) { 28 | print("Visited vertex: $v"); 29 | for (T n in adjList[v]) { 30 | if (!markSet.contains(n)) { 31 | _dfs(n); 32 | } 33 | } 34 | } 35 | } 36 | 37 | bfs(T v) { 38 | markSet.clear(); 39 | var queue = new Queue(); 40 | markSet.add(v); 41 | queue.enqueue(v); 42 | while (!queue.isEmpty) { 43 | var p = queue.dequeue(); 44 | print('Visited vertex: $p'); 45 | for (T n in adjList[p]) { 46 | if (!markSet.contains(n)) { 47 | markSet.add(n); 48 | queue.enqueue(n); 49 | } 50 | } 51 | } 52 | } 53 | 54 | String toString() { 55 | var s = ''; 56 | for (T v in adjList.keys) { 57 | s += v.toString() + ' -> '; 58 | for (T n in adjList[v]) { 59 | s += n.toString() + ' '; 60 | } 61 | s += '\n'; 62 | } 63 | return s; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /lib/src/data_structures/hash/hash_table.dart: -------------------------------------------------------------------------------- 1 | import '../linked_list/linked_list.dart'; 2 | 3 | class HashTable { 4 | Map>> _dataStore = 5 | >>{}; 6 | 7 | int _hash(K key) { 8 | var hash = 0; 9 | var keyStr = key.toString(); 10 | for (var i = 0; i < keyStr.toString().length; i++) { 11 | hash += keyStr.codeUnitAt(i); 12 | } 13 | return hash % 37; 14 | } 15 | 16 | // int _betterHash(K key) { 17 | // var hash = 5381; 18 | // var keyStr = key.toString(); 19 | // for (var i = 0; i < keyStr.length; i++) { 20 | // hash = hash * 33 + keyStr.codeUnitAt(i); 21 | // } 22 | // return hash % 1013; 23 | // } 24 | 25 | void put(K key, V value) { 26 | var position = _hash(key); 27 | if (!_dataStore.containsKey(position)) { 28 | _dataStore[position] = new LinkedList>(); 29 | } 30 | _dataStore[position].append(new HashItem(key, value)); 31 | } 32 | 33 | bool remove(K key) { 34 | var position = _hash(key); 35 | if (_dataStore.containsKey(position)) { 36 | var list = _dataStore[position]; 37 | var current = list.head; 38 | while (current != null) { 39 | if (current?.element?.key == key) { 40 | list.remove(current.element); 41 | return true; 42 | } 43 | current = current.next; 44 | } 45 | } 46 | return false; 47 | } 48 | 49 | V get(K key) { 50 | var position = _hash(key); 51 | if (_dataStore.containsKey(position)) { 52 | var list = _dataStore[position]; 53 | var current = list.head; 54 | while (current != null) { 55 | if (current?.element?.key == key) { 56 | return current.element.value; 57 | } 58 | current = current.next; 59 | } 60 | } 61 | return null; 62 | } 63 | } 64 | 65 | class HashItem { 66 | K key; 67 | V value; 68 | 69 | HashItem(this.key, this.value); 70 | 71 | int get hashCode { 72 | int result = 17; 73 | result = 37 * result + key.hashCode; 74 | result = 37 * result + value.hashCode; 75 | return result; 76 | } 77 | 78 | bool operator ==(other) { 79 | if (other is! HashItem) return false; 80 | HashItem valuePair = other; 81 | return (valuePair.key == key && valuePair.value == value); 82 | } 83 | 84 | String toString() { 85 | return '[$key - $value]'; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /lib/src/data_structures/linked_list/doubly_linked_list.dart: -------------------------------------------------------------------------------- 1 | class DoublyLinkedList { 2 | DoublyNode head; 3 | DoublyNode tail; 4 | 5 | DoublyLinkedList(); 6 | 7 | int _size = 0; 8 | 9 | int get size => _size; 10 | 11 | bool get isEmpty => _size == 0; 12 | 13 | append(T element) { 14 | var node = new DoublyNode(element); 15 | var current = head; 16 | if (head == null) { 17 | head = node; 18 | } else { 19 | current = head; 20 | while (current.next != null) { 21 | current = current.next; 22 | } 23 | current.next = node; 24 | } 25 | _size++; 26 | tail = node; 27 | } 28 | 29 | T removeAt(int position) { 30 | if (position > -1 && position < _size) { 31 | var index = 0; 32 | var previous = head; 33 | var current = head; 34 | if (position == 0) { 35 | head = current.next; 36 | if (_size == 1) { 37 | tail = null; 38 | } else { 39 | head.prev = null; 40 | } 41 | } else if (position == _size - 1) { 42 | current = tail; 43 | tail = current.prev; 44 | tail.next = null; 45 | } else { 46 | while (index++ < position) { 47 | previous = current; 48 | current = current.next; 49 | } 50 | previous.next = current.next; 51 | current.next.prev = previous; 52 | } 53 | _size--; 54 | return current.element; 55 | } 56 | return null; 57 | } 58 | 59 | bool insert(int position, T element) { 60 | if (position >= 0 && position < _size) { 61 | var node = new DoublyNode(element); 62 | var index = 0; 63 | var previous = head; 64 | var current = head; 65 | if (position == 0) { 66 | if (head == null) { 67 | head = node; 68 | tail = node; 69 | } else { 70 | node.next = current; 71 | current.prev = node; 72 | head = node; 73 | } 74 | } else if (position == _size) { 75 | current = tail; 76 | current.next = node; 77 | node.prev = current; 78 | tail = node; 79 | } else { 80 | while (index++ < position) { 81 | previous = current; 82 | current = current.next; 83 | } 84 | node.next = current; 85 | current.prev = node; 86 | previous.next = node; 87 | node.prev = previous; 88 | } 89 | _size++; 90 | return true; 91 | } 92 | return false; 93 | } 94 | 95 | int indexOf(T element) { 96 | var index = 0; 97 | var current = head; 98 | while (current != null) { 99 | if (current.element == element) { 100 | return index; 101 | } 102 | current = current.next; 103 | index++; 104 | } 105 | return -1; 106 | } 107 | 108 | T remove(T element) { 109 | var index = indexOf(element); 110 | return removeAt(index); 111 | } 112 | 113 | String toString() { 114 | var current = head; 115 | var string = ''; 116 | while (current != null) { 117 | string += current.element.toString() + (current.next != null ? '\n' : ''); 118 | current = current.next; 119 | } 120 | return string; 121 | } 122 | } 123 | 124 | class DoublyNode { 125 | T element; 126 | DoublyNode next; 127 | DoublyNode prev; 128 | 129 | DoublyNode(this.element); 130 | } 131 | -------------------------------------------------------------------------------- /lib/src/data_structures/linked_list/linked_list.dart: -------------------------------------------------------------------------------- 1 | class LinkedList { 2 | Node head; 3 | 4 | LinkedList(); 5 | 6 | int _size = 0; 7 | 8 | int get size => _size; 9 | 10 | bool get isEmpty => _size == 0; 11 | 12 | append(T element) { 13 | var node = new Node(element); 14 | var current = head; 15 | if (head == null) { 16 | head = node; 17 | } else { 18 | current = head; 19 | while (current.next != null) { 20 | current = current.next; 21 | } 22 | current.next = node; 23 | } 24 | _size++; 25 | } 26 | 27 | T removeAt(int position) { 28 | if (position > -1 && position < _size) { 29 | var index = 0; 30 | var previous = head; 31 | var current = head; 32 | if (position == 0) { 33 | head = current.next; 34 | } else { 35 | while (index++ < position) { 36 | previous = current; 37 | current = current.next; 38 | } 39 | previous.next = current.next; 40 | } 41 | _size--; 42 | return current.element; 43 | } 44 | return null; 45 | } 46 | 47 | bool insert(int position, T element) { 48 | if (position >= 0 && position < _size) { 49 | var node = new Node(element); 50 | var index = 0; 51 | var previous = head; 52 | var current = head; 53 | if (position == 0) { 54 | node.next = current; 55 | head = node; 56 | } else { 57 | while (index++ < position) { 58 | previous = current; 59 | current = current.next; 60 | } 61 | node.next = current; 62 | previous.next = node; 63 | } 64 | _size++; 65 | return true; 66 | } 67 | return false; 68 | } 69 | 70 | int indexOf(T element) { 71 | var index = 0; 72 | var current = head; 73 | while (current != null) { 74 | if (current.element == element) { 75 | return index; 76 | } 77 | current = current.next; 78 | index++; 79 | } 80 | return -1; 81 | } 82 | 83 | T remove(T element) { 84 | var index = indexOf(element); 85 | return removeAt(index); 86 | } 87 | 88 | String toString() { 89 | var current = head; 90 | var string = ''; 91 | while (current != null) { 92 | string += current.element.toString() + (current.next != null ? '\n' : ''); 93 | current = current.next; 94 | } 95 | return string; 96 | } 97 | } 98 | 99 | class Node { 100 | T element; 101 | Node next; 102 | 103 | Node(this.element); 104 | } 105 | -------------------------------------------------------------------------------- /lib/src/data_structures/queue/priority_queue.dart: -------------------------------------------------------------------------------- 1 | class PriorityQueue { 2 | List> _dataStore = >[]; 3 | 4 | int get size => _dataStore.length; 5 | 6 | bool get isEmpty => _dataStore.isEmpty; 7 | 8 | enqueue(T item, int priority) { 9 | QueueItem queueItem = new QueueItem(item, priority); 10 | bool added = false; 11 | for (int i = 0; i < _dataStore.length; i++) { 12 | if (priority < _dataStore[i].priority) { 13 | added = true; 14 | _dataStore.insert(i, queueItem); 15 | break; 16 | } 17 | } 18 | if (!added) { 19 | _dataStore.add(queueItem); 20 | } 21 | } 22 | 23 | T dequeue() { 24 | if (_dataStore.isNotEmpty) { 25 | return _dataStore.removeAt(0).item; 26 | } 27 | return null; 28 | } 29 | 30 | T get front { 31 | if (_dataStore.isNotEmpty) { 32 | return _dataStore.first.item; 33 | } 34 | return null; 35 | } 36 | 37 | T get end { 38 | if (_dataStore.isNotEmpty) { 39 | return _dataStore.last.item; 40 | } 41 | return null; 42 | } 43 | 44 | clear() { 45 | _dataStore.clear(); 46 | } 47 | 48 | String toString() { 49 | return _dataStore.toString(); 50 | } 51 | } 52 | 53 | class QueueItem { 54 | T item; 55 | int priority; 56 | 57 | QueueItem(this.item, this.priority); 58 | 59 | String toString() { 60 | return '$item - $priority'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/src/data_structures/queue/queue.dart: -------------------------------------------------------------------------------- 1 | class Queue { 2 | List _dataStore = []; 3 | 4 | int get size => _dataStore.length; 5 | 6 | bool get isEmpty => _dataStore.isEmpty; 7 | 8 | enqueue(T element) { 9 | _dataStore.add(element); 10 | } 11 | 12 | T dequeue() { 13 | if (_dataStore.isNotEmpty) { 14 | return _dataStore.removeAt(0); 15 | } 16 | return null; 17 | } 18 | 19 | T get front { 20 | if (_dataStore.isNotEmpty) { 21 | return _dataStore.first; 22 | } 23 | return null; 24 | } 25 | 26 | T get end { 27 | if (_dataStore.isNotEmpty) { 28 | return _dataStore.last; 29 | } 30 | return null; 31 | } 32 | 33 | clear() { 34 | _dataStore.clear(); 35 | } 36 | 37 | String toString() { 38 | return _dataStore.toString(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/src/data_structures/stack/stack.dart: -------------------------------------------------------------------------------- 1 | class Stack { 2 | List _dataStore = []; 3 | 4 | int get size => _dataStore.length; 5 | 6 | bool get isEmpty => _dataStore.isEmpty; 7 | 8 | push(T element) { 9 | _dataStore.insert(0, element); 10 | } 11 | 12 | T pop() { 13 | if (_dataStore.isNotEmpty) { 14 | return _dataStore.removeAt(0); 15 | } 16 | return null; 17 | } 18 | 19 | T peek() { 20 | if (_dataStore.isNotEmpty) { 21 | return _dataStore.elementAt(0); 22 | } 23 | return null; 24 | } 25 | 26 | clear() { 27 | _dataStore.clear(); 28 | } 29 | 30 | String toString() { 31 | return _dataStore.toString(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/data_structures/stack/stack_example.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/src/data_structures/stack/stack.dart'; 2 | 3 | // convert decimal number to any base 4 | baseConverter(int decimalNumber, int base) { 5 | var remainderStack = new Stack(); 6 | var binaryString = ''; 7 | var remainderString = '0123456789ABCDEF'; 8 | 9 | var remainder; 10 | while (decimalNumber > 0) { 11 | remainder = (decimalNumber % base).floor(); 12 | remainderStack.push(remainder); 13 | decimalNumber = (decimalNumber / base).floor(); 14 | } 15 | 16 | while (!remainderStack.isEmpty) { 17 | binaryString += remainderString[remainderStack.pop()]; 18 | } 19 | 20 | return binaryString; 21 | } 22 | 23 | main(List args) { 24 | print(baseConverter(10, 2)); 25 | print(baseConverter(10, 8)); 26 | print(baseConverter(43, 16)); 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/data_structures/tree/binary_search_tree.dart: -------------------------------------------------------------------------------- 1 | class BinarySearchTree { 2 | TreeNode root; 3 | 4 | insert(T key) { 5 | var newNode = new TreeNode(key); 6 | 7 | if (root == null) { 8 | root = newNode; 9 | } else { 10 | _insertNode(root, newNode); 11 | } 12 | } 13 | 14 | _insertNode(TreeNode node, TreeNode newNode) { 15 | if (newNode.key < node.key) { 16 | if (node.left == null) { 17 | node.left = newNode; 18 | } else { 19 | _insertNode(node.left, newNode); 20 | } 21 | } else { 22 | if (node.right == null) { 23 | node.right = newNode; 24 | } else { 25 | _insertNode(node.right, newNode); 26 | } 27 | } 28 | } 29 | 30 | inOrderTraverse(void callback(T key)) { 31 | _inOrderTraverse(root, callback); 32 | } 33 | 34 | _inOrderTraverse(TreeNode node, void callback(T key)) { 35 | if (node != null) { 36 | _inOrderTraverse(node.left, callback); 37 | if (callback !=null) { 38 | callback(node.key); 39 | } 40 | _inOrderTraverse(node.right, callback); 41 | } 42 | } 43 | 44 | preOrderTraverse(void callback(T key)) { 45 | _preOrderTraverse(root, callback); 46 | } 47 | 48 | _preOrderTraverse(TreeNode node, void callback(T key)) { 49 | if (node != null) { 50 | if (callback !=null) { 51 | callback(node.key); 52 | } 53 | _inOrderTraverse(node.left, callback); 54 | _inOrderTraverse(node.right, callback); 55 | } 56 | } 57 | 58 | postOrderTraverse(void callback(T key)) { 59 | _postOrderTraverse(root, callback); 60 | } 61 | 62 | _postOrderTraverse(TreeNode node, void callback(T key)) { 63 | if (node != null) { 64 | _inOrderTraverse(node.left, callback); 65 | _inOrderTraverse(node.right, callback); 66 | if (callback !=null) { 67 | callback(node.key); 68 | } 69 | } 70 | } 71 | 72 | T min() { 73 | return _min(root); 74 | } 75 | 76 | T _min(TreeNode node) { 77 | if (node != null) { 78 | while (node != null && node.left != null) { 79 | node = node.left; 80 | } 81 | return node.key; 82 | } 83 | return null; 84 | } 85 | 86 | T max() { 87 | return _max(root); 88 | } 89 | 90 | T _max(TreeNode node) { 91 | if (node != null) { 92 | while (node != null && node.right != null) { 93 | node = node.right; 94 | } 95 | return node.key; 96 | } 97 | return null; 98 | } 99 | 100 | bool search(T key) { 101 | return _search(root, key); 102 | } 103 | 104 | bool _search(TreeNode node, T searchKey) { 105 | if (node == null) { 106 | return false; 107 | } 108 | 109 | var compareResult = searchKey.compareTo(node.key); 110 | if (compareResult < 0) { 111 | return _search(node.left, searchKey); 112 | } else if (compareResult > 0) { 113 | return _search(node.right, searchKey); 114 | } 115 | return true; 116 | } 117 | 118 | remove(T key) { 119 | root = _remove(root, key); 120 | } 121 | 122 | TreeNode _remove(TreeNode node, T searchKey) { 123 | if (node == null) { 124 | return null; 125 | } 126 | 127 | var compareResult = searchKey.compareTo(node.key); 128 | if (compareResult < 0) { 129 | node.left = _remove(node.left, searchKey); 130 | return node; 131 | } else if (compareResult > 0) { 132 | node.right = _remove(node.right, searchKey); 133 | return node; 134 | } else { 135 | // leaf node 136 | if (node.left == null && node.right == null) { 137 | node = null; 138 | return node; 139 | } 140 | 141 | // node with 1 child 142 | if (node.left == null) { 143 | node = node.right; 144 | return node; 145 | } else if (node.right == null) { 146 | node = node.left; 147 | return node; 148 | } 149 | 150 | // 2 children 151 | var minNode = _findMinNode(node.right); 152 | node.key = minNode.key; 153 | node.right = _remove(node.right, minNode.key); 154 | return node; 155 | } 156 | } 157 | 158 | TreeNode _findMinNode(TreeNode node) { 159 | while (node != null && node.left != null) { 160 | node = node.left; 161 | } 162 | return node; 163 | } 164 | } 165 | 166 | class TreeNode { 167 | T key; 168 | TreeNode left; 169 | TreeNode right; 170 | 171 | TreeNode(this.key); 172 | } 173 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_algorithms 2 | description: Data structures and algorithms with Dart. 3 | # version: 0.1.0 4 | homepage: https://github.com/jarontai/dart-algorithms 5 | author: jarontai 6 | environment: 7 | sdk: '>=2.0.0 <3.0.0' 8 | dependencies: 9 | test: ^1.0.0 10 | -------------------------------------------------------------------------------- /test/algorithms/searching_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | test('sequential search', () { 6 | var arr = [9, 5, 4, 6, 1, 3, 2, 7, 8, 10]; 7 | expect(sequentialSearch(arr, 9), equals(0)); 8 | expect(sequentialSearch(arr, 1), equals(4)); 9 | expect(sequentialSearch(arr, 10), equals(9)); 10 | }); 11 | 12 | test('binary search', () { 13 | var arr = [9, 5, 4, 6, 1, 3, 2, 7, 8, 10]; 14 | expect(sequentialSearch(arr, 9), equals(0)); 15 | expect(sequentialSearch(arr, 1), equals(4)); 16 | expect(sequentialSearch(arr, 10), equals(9)); 17 | }); 18 | } 19 | -------------------------------------------------------------------------------- /test/algorithms/sorting_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:dart_algorithms/dart_algorithms.dart'; 4 | import 'package:test/test.dart'; 5 | 6 | class TestBed { 7 | List dataStore; 8 | int length; 9 | int times; 10 | Function sortFn; 11 | bool auto; 12 | 13 | TestBed(this.length, this.sortFn, {this.auto = false, this.times = 1}) { 14 | if (auto) { 15 | sort(); 16 | } 17 | } 18 | 19 | sort() { 20 | DateTime start = new DateTime.now(); 21 | for (var i = 0; i < times; i++) { 22 | prepareData(); 23 | dataStore = sortFn(dataStore, swap); 24 | } 25 | var costTime = new DateTime.now().difference(start).inMilliseconds; 26 | print('${dataStore.length} items costs : $costTime ms'); 27 | } 28 | 29 | clear() { 30 | dataStore?.clear(); 31 | } 32 | 33 | insert(element) { 34 | dataStore?.add(element); 35 | } 36 | 37 | prepareData() { 38 | Random random = new Random(); 39 | dataStore = new List.generate(length, (index) { 40 | return (random.nextDouble() * length + 1).floor(); 41 | }); 42 | } 43 | 44 | swap(List arr, index1, index2) { 45 | var temp = arr[index1]; 46 | arr[index1] = arr[index2]; 47 | arr[index2] = temp; 48 | } 49 | 50 | bool check() { 51 | sort(); 52 | var prev = -1; 53 | for (var i in dataStore) { 54 | if (i >= prev) { 55 | prev = i; 56 | } else { 57 | return false; 58 | } 59 | } 60 | return true; 61 | } 62 | 63 | String toString() { 64 | return dataStore.toString(); 65 | } 66 | } 67 | 68 | main() { 69 | 70 | group('Basic sort -', () { 71 | test('bubble sort', () { 72 | expect(new TestBed(30000, bubbleSort).check(), equals(true)); 73 | }); 74 | 75 | test('selection sort', () { 76 | expect(new TestBed(30000, selectionSort).check(), equals(true)); 77 | }); 78 | 79 | test('insertion sort', () { 80 | expect(new TestBed(30000, insertionSort).check(), equals(true)); 81 | }); 82 | }); 83 | 84 | group('Advanced sort -', () { 85 | test('shell sort', () { 86 | expect(new TestBed(30000, shellSort).check(), equals(true)); 87 | }); 88 | 89 | test('merge sort', () { 90 | expect(new TestBed(30000, mergeSort).check(), equals(true)); 91 | }); 92 | 93 | test('quick sort', () { 94 | expect(new TestBed(30000, quickSort).check(), equals(true)); 95 | }); 96 | }); 97 | } 98 | -------------------------------------------------------------------------------- /test/data_structures/binary_search_tree_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | var tree = new BinarySearchTree(); 6 | var keys = []; 7 | 8 | // 3 5 6 7 8 9 10 11 12 13 14 15 18 20 25 9 | 10 | setUp(() { 11 | tree.insert(11); 12 | tree.insert(7); 13 | tree.insert(15); 14 | tree.insert(5); 15 | tree.insert(3); 16 | tree.insert(9); 17 | tree.insert(8); 18 | tree.insert(10); 19 | tree.insert(13); 20 | tree.insert(12); 21 | tree.insert(14); 22 | tree.insert(20); 23 | tree.insert(18); 24 | tree.insert(25); 25 | tree.insert(6); 26 | }); 27 | 28 | test('binary search tree operations', () { 29 | tree.inOrderTraverse((key) => keys.add(key)); 30 | expect(keys.length, equals(15)); 31 | expect(keys.first, equals(3)); 32 | expect(keys.last, equals(25)); 33 | 34 | keys.clear(); 35 | tree.preOrderTraverse((key) => keys.add(key)); 36 | expect(keys.length, equals(15)); 37 | expect(keys.first, equals(11)); 38 | expect(keys.last, equals(25)); 39 | 40 | keys.clear(); 41 | tree.postOrderTraverse((key) => keys.add(key)); 42 | expect(keys.length, equals(15)); 43 | expect(keys.first, equals(3)); 44 | expect(keys.last, equals(11)); 45 | 46 | expect(tree.min(), equals(3)); 47 | expect(tree.max(), equals(25)); 48 | 49 | expect(tree.search(1), isFalse); 50 | expect(tree.search(6), isTrue); 51 | 52 | tree.remove(6); 53 | tree.remove(5); 54 | tree.remove(15); 55 | 56 | expect(tree.search(6), isFalse); 57 | expect(tree.search(5), isFalse); 58 | expect(tree.search(15), isFalse); 59 | 60 | expect(tree.min(), equals(3)); 61 | expect(tree.max(), equals(25)); 62 | }); 63 | } 64 | -------------------------------------------------------------------------------- /test/data_structures/doubly_linked_list_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | var list = new DoublyLinkedList(); 6 | 7 | setUp(() { 8 | list.append('Java'); 9 | list.append('JavaScript'); 10 | list.append('C#'); 11 | list.append('Ruby'); 12 | }); 13 | 14 | test('linked list operations', () { 15 | expect(list.head?.element, equals('Java')); 16 | expect(list.tail?.element, equals('Ruby')); 17 | expect(list.insert(4, 'PHP'), isFalse); 18 | expect(list.insert(0, 'Dart'), isTrue); 19 | expect(list.insert(3, 'Go'), isTrue); 20 | expect(list.size, equals(6)); 21 | expect(list.remove('JavaScript'), equals('JavaScript')); 22 | expect(list.size, equals(5)); 23 | expect(list.indexOf('Dart'), equals(0)); 24 | expect(list.indexOf('Go'), equals(2)); 25 | expect(list.isEmpty, isFalse); 26 | expect(list.head?.element, equals('Dart')); 27 | expect(list.append('PHP'), isNull); 28 | expect(list.tail?.element, equals('PHP')); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /test/data_structures/graph_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | var graph = new Graph(); 6 | 7 | setUp(() { 8 | graph.addEdge(0, 1); 9 | graph.addEdge(0, 2); 10 | graph.addEdge(1, 3); 11 | graph.addEdge(2, 4); 12 | }); 13 | 14 | test('graph operations', () { 15 | print(graph); 16 | graph.bfs(0); 17 | graph.dfs(0); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /test/data_structures/hash_table_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | var hash = new HashTable(); 6 | 7 | setUp(() { 8 | hash.put('Gandalf', 'gandalf@email.com'); 9 | hash.put('John', 'johnsnow@email.com'); 10 | hash.put('Tyrion', 'tyrion@email.com'); 11 | hash.put('Aaron', 'aaron@email.com'); 12 | hash.put('Donnie', 'donnie@email.com'); 13 | hash.put('Ana', 'ana@email.com'); 14 | hash.put('Jonathan', 'jonathan@email.com'); 15 | hash.put('Jamie', 'jamie@email.com'); 16 | hash.put('Sue', 'sue@email.com'); 17 | }); 18 | 19 | test('hash table operations', () { 20 | expect(hash.get('Tyrion'), equals('tyrion@email.com')); 21 | expect(hash.get('Aaron'), equals('aaron@email.com')); 22 | expect(hash.get('Joe'), isNull); 23 | expect(hash.remove('Donnie'), isTrue); 24 | expect(hash.remove('Joe'), isFalse); 25 | expect(hash.get('Donnie'), isNull); 26 | expect(hash.get('Jonathan'), equals('jonathan@email.com')); 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /test/data_structures/linked_list_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | var list = new LinkedList(); 6 | 7 | setUp(() { 8 | list.append('Java'); 9 | list.append('JavaScript'); 10 | list.append('C#'); 11 | list.append('Ruby'); 12 | }); 13 | 14 | test('linked list operations', () { 15 | expect(list.head?.element, equals('Java')); 16 | expect(list.insert(4, 'PHP'), isFalse); 17 | expect(list.insert(0, 'Dart'), isTrue); 18 | expect(list.insert(3, 'Go'), isTrue); 19 | expect(list.size, equals(6)); 20 | expect(list.remove('JavaScript'), equals('JavaScript')); 21 | expect(list.size, equals(5)); 22 | expect(list.indexOf('Dart'), equals(0)); 23 | expect(list.indexOf('Go'), equals(2)); 24 | expect(list.isEmpty, isFalse); 25 | expect(list.head?.element, equals('Dart')); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /test/data_structures/priority_queue_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | var queue = new PriorityQueue(); 6 | 7 | setUp(() { 8 | queue.enqueue('Android', 0); 9 | queue.enqueue('iOS', 2); 10 | queue.enqueue('Web', 3); 11 | queue.enqueue('Fuchsia', 1); 12 | }); 13 | 14 | test('priority queue operations', () { 15 | expect(queue.front, equals('Android')); 16 | expect(queue.end, equals('Web')); 17 | expect(queue.size, equals(4)); 18 | expect(queue.dequeue(), equals('Android')); 19 | expect(queue.front, equals('Fuchsia')); 20 | expect(queue.end, equals('Web')); 21 | queue.clear(); 22 | expect(queue.size, equals(0)); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /test/data_structures/queue_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | var queue = new Queue(); 6 | 7 | setUp(() { 8 | queue.enqueue('Android'); 9 | queue.enqueue('iOS'); 10 | queue.enqueue('Web'); 11 | }); 12 | 13 | test('queue operations', () { 14 | expect(queue.front, equals('Android')); 15 | expect(queue.end, equals('Web')); 16 | queue.enqueue('Fuchsia'); 17 | expect(queue.size, equals(4)); 18 | expect(queue.dequeue(), equals('Android')); 19 | expect(queue.end, equals('Fuchsia')); 20 | queue.clear(); 21 | expect(queue.size, equals(0)); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /test/data_structures/stack_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:dart_algorithms/dart_algorithms.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | main() { 5 | var stack = new Stack(); 6 | 7 | setUp(() { 8 | stack.push('Java'); 9 | stack.push('JavaScript'); 10 | stack.push('C#'); 11 | stack.push('Dart'); 12 | }); 13 | 14 | test('stack operations', () { 15 | expect(stack.size, equals(4)); 16 | expect(stack.peek(), 'Dart'); 17 | expect(stack.pop(), equals('Dart')); 18 | expect(stack.peek(), 'C#'); 19 | expect(stack.isEmpty, isFalse); 20 | stack.push('Ruby'); 21 | expect(stack.pop(), 'Ruby'); 22 | stack.clear(); 23 | expect(stack.isEmpty, isTrue); 24 | expect(stack.size, equals(0)); 25 | expect(stack.peek(), isNull); 26 | stack.push('Dart'); 27 | expect(stack.peek(), equals('Dart')); 28 | }); 29 | } 30 | --------------------------------------------------------------------------------