├── .clang-format ├── .gitignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── app ├── CMakeLists.txt ├── deflate.c └── inflate.c ├── build └── .keep ├── doc ├── Doxyfile └── intro.h ├── src ├── CMakeLists.txt ├── ac.c ├── ac.h ├── arraylist.c ├── arraylist.h ├── avltree.c ├── avltree.h ├── bignum.c ├── bignum.h ├── bitmap.c ├── bitmap.h ├── bm.c ├── bm.h ├── bstree.c ├── bstree.h ├── compare.c ├── compare.h ├── def.h ├── dijkstra.c ├── dijkstra.h ├── distance.c ├── distance.h ├── dup.c ├── dup.h ├── graph.c ├── graph.h ├── hash.c ├── hash.h ├── hash_table.c ├── hash_table.h ├── heap.c ├── heap.h ├── huffman.c ├── huffman.h ├── kmp.c ├── kmp.h ├── list.c ├── list.h ├── matrix.c ├── matrix.h ├── prime.c ├── prime.h ├── queue.c ├── queue.h ├── rbtree.c ├── rbtree.h ├── skip_list.c ├── skip_list.h ├── sparse_graph.c ├── sparse_graph.h ├── sunday.c ├── sunday.h ├── text.c ├── text.h ├── trie.c ├── trie.h ├── vector.c └── vector.h └── test ├── CMakeLists.txt ├── alloc-testing.c ├── alloc-testing.h ├── test_ac.c ├── test_arraylist.c ├── test_avltree.c ├── test_bignum.c ├── test_bitmap.c ├── test_bm.c ├── test_bstree.c ├── test_dijkstra.c ├── test_distance.c ├── test_graph.c ├── test_hash_table.c ├── test_heap.c ├── test_helper.c ├── test_helper.h ├── test_huffman.c ├── test_kmp.c ├── test_list.c ├── test_matrix.c ├── test_prime.c ├── test_queue.c ├── test_rbtree.c ├── test_skip_list.c ├── test_sunday.c ├── test_text.c ├── test_trie.c ├── test_vector.c └── testmain.c /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | IndentWidth: 4 4 | BreakBeforeBraces: Linux 5 | PointerAlignment: Right 6 | BinPackArguments: false 7 | BinPackParameters: false 8 | AlignEscapedNewlines: Left 9 | AllowShortFunctionsOnASingleLine: Empty 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | !build/.keep 3 | clang-format.original 4 | 5 | /doc/html/ 6 | /doc/latex/ 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | services: 3 | - docker 4 | dist: bionic 5 | compiler: 6 | - clang 7 | - gcc 8 | script: cd build && cmake .. && make && make test CTEST_OUTPUT_ON_FAILURE=1 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "clang build and debug active file", 9 | "type": "cppdbg", 10 | "request": "launch", 11 | "program": "${workspaceRoot}/build/unit_tests", 12 | "args": [], 13 | "stopAtEntry": false, 14 | "cwd": "${workspaceRoot}", 15 | "environment": [], 16 | "externalConsole": false, 17 | "MIMode": "lldb", 18 | "preLaunchTask": "build" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "__node_handle": "c", 4 | "iterator": "c" 5 | } 6 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "type": "shell", 9 | "command": "make", 10 | "args": [ 11 | "unit_tests" 12 | ], 13 | "options": { 14 | "cwd": "${workspaceRoot}/build" 15 | } 16 | }, 17 | { 18 | "label": "build clean", 19 | "type": "shell", 20 | "command": "make", 21 | "args": [ 22 | "clean" 23 | ], 24 | "options": { 25 | "cwd": "${workspaceRoot}/build" 26 | } 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | project(rethink) 3 | 4 | # set(COMPILE_OPTIONS -std=c99 -O2 -Wall -g -DALLOC_TESTING) 5 | # set(COMPILE_OPTIONS -std=c99 -Wall -g) 6 | set(COMPILE_OPTIONS -std=c99 -Wall -g -DTESTING -DALLOC_TESTING) 7 | set(INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/src 8 | ${CMAKE_CURRENT_SOURCE_DIR}/test) 9 | 10 | # message("======${CMAKE_CURRENT_SOURCE_DIR}") 11 | 12 | add_subdirectory(src) 13 | add_subdirectory(test) 14 | add_subdirectory(app) 15 | 16 | # CTest 17 | enable_testing() 18 | 19 | add_executable(unit_tests test/testmain.c) 20 | target_link_libraries(unit_tests testcases algorithm m) 21 | target_compile_options(unit_tests PRIVATE ${COMPILE_OPTIONS}) 22 | 23 | add_test(test_all unit_tests) 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 hutusi.com 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RETHINK C 2 | 3 | [![Build Status](https://travis-ci.org/hutusi/rethink-c.svg?branch=master)](https://travis-ci.org/hutusi/rethink-c) 4 | 5 | Relearn and rethink C Programming Language, including some of data structures and algorithms. 6 | 7 | The code is licensed under the MIT license, copyright by [hutusi.com](http://hutusi.com/). 8 | 9 | Some of the code inspired (copied) by Simon Howard's [c-algorithms](https://github.com/fragglet/c-algorithms), like ArrayList, etc. This project also reused his alloc-testing framework for memory testing. 10 | 11 | RETHINK-C aims to build a reuseable codebase for C Programming Language. 12 | 13 | ## How to build & test 14 | 15 | ### Requirements: 16 | 17 | * Editor/IDE: VS Code is recommended. 18 | * GCC on Mac, Linux or Windows. (Recommend msys2 + MingW on Windows.) 19 | * CMake. 20 | * Clang-Format. 21 | 22 | ### build & test: 23 | 24 | * build 25 | 26 | ``` 27 | cd build 28 | cmake .. 29 | make 30 | ``` 31 | 32 | * test: 33 | 34 | ``` 35 | make test 36 | ``` 37 | 38 | ## Goals / Achievements 39 | 40 | ### Basic Data Structures 41 | 42 | - [x] ArrayList, Stack [arraylist.h](src/arraylist.h) [arraylist.c](src/arraylist.c) 43 | - [x] LinkedList [list.h](src/list.h) [list.c](src/list.c) 44 | - [x] Queue [queue.h](src/queue.h) [queue.c](src/queue.c) 45 | - [x] BitMap [bitmap.h](src/bitmap.h) [bitmap.c](src/bitmap.c) 46 | - [x] Muti-dimensional Matrix [matrix.h](src/matrix.h) [matrix.c](src/matrix.c) 47 | - [x] Hash Table [hash_table.h](src/hash_table.h) [hash_table.c](src/hash_table.c) [hash.h](src/hash.h) [hash.c](src/hash.c) 48 | 49 | ### Trees 50 | - [x] Binary Search Tree [bstree.h](src/bstree.h) [bstree.c](src/bstree.c) 51 | - [x] AVL Tree [avltree.h](src/avltree.h) [avltree.c](src/avltree.c) 52 | - [x] Red Black Tree [rbtree.h](src/rbtree.h) [rbtree.c](src/rbtree.c) 53 | - [x] Binary Heap [heap.h](src/heap.h) [heap.c](src/heap.c) 54 | - [ ] Fibonacci Heap, Binomial Heap 55 | - [x] Skip List [skip_list.h](src/skip_list.h) [skip_list.c](src/skip_list.c) 56 | - [ ] B+ Tree 57 | 58 | ### Graphs 59 | - [x] Adjacency Matrix [graph.h](src/graph.h) [graph.c](src/graph.c) 60 | - [x] Adjacency List [sparse_graph.h](src/sparse_graph.h) [sparse_graph.c](src/sparse_graph.c) 61 | - [ ] Union-Find 62 | - [x] BFS & DFS [graph.h##bfs(), ##dfs()](src/graph.h) 63 | - [x] Topological sorting (Kahn) [sparse_graph_topo_sort()](src/sparse_graph.h) 64 | - [ ] Floyd 65 | - [x] Dijkstra [dijkstra.h](src/dijkstra.h) [dijkstra.c](src/dijkstra.c) 66 | - [ ] Minimum spanning trees: Prim, Kruskal 67 | - [ ] A-star 68 | 69 | ### String & Text 70 | - [x] Text (similar to string in C++). [text.h](src/text.h) [text.c](src/text.c) 71 | - [x] BigNum integer [bignum.h](src/bignum.h) [bignum.c](src/bignum.c) 72 | - [ ] BigNum decimal 73 | - [x] KMP (Knuth-Morris-Pratt) algorithm [kmp.h](src/kmp.h) [kmp.c](src/kmp.c) 74 | - [x] BM (Boyer-Moore) algorithm [bm.h](src/bm.h) [bm.c](src/bm.c) 75 | - [x] Sunday algorithm [sunday.h](src/sunday.h) [sunday.c](src/sunday.c) 76 | - [x] Trie Tree [trie.h](src/trie.h) [trie.c](src/trie.c) 77 | - [x] Aho–Corasick algorithm [ac.h](src/ac.h) [ac.c](src/ac.c) 78 | - [ ] DAT (Double-Array Trie) 79 | - [x] Huffman coding [huffman.h](src/huffman.h) [huffman.c](src/huffman.c) 80 | 81 | ### Sorting 82 | - [x] Quick Sort [arraylist.c##arraylist_sort()](src/arraylist.c) 83 | - [x] Merge Sort [list.c##list_sort()](src/list.c) 84 | - [x] Heap Sort [heap.h](src/heap.h) [heap.c](src/heap.c) 85 | 86 | ### Math 87 | - [ ] Matrix multiplication 88 | - [x] Eratosthenes sieve (prime numbers) [prime.h](src/prime.h) [prime.c](src/prime.c) 89 | 90 | ### Distance Measures 91 | - [x] Euclidean distance [distance.h##euclidiean_distance()](src/distance.h) 92 | - [ ] Manhattan distance 93 | - [ ] Hamming distance 94 | 95 | ### MISC 96 | - [ ] Bloom filter 97 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(deflate deflate.c) 2 | target_link_libraries(deflate algorithm testcases) 3 | target_compile_options(deflate PRIVATE ${COMPILE_OPTIONS}) 4 | target_include_directories(deflate PRIVATE ${INCLUDE_DIRECTORIES}) 5 | 6 | add_executable(inflate inflate.c) 7 | target_link_libraries(inflate algorithm testcases) 8 | target_compile_options(inflate PRIVATE ${COMPILE_OPTIONS}) 9 | target_include_directories(inflate PRIVATE ${INCLUDE_DIRECTORIES}) 10 | -------------------------------------------------------------------------------- /app/deflate.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file deflate.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Use Huffman Tree to deflate text file. 5 | * @date 2019-08-30 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "huffman.h" 12 | #include "hash_table.h" 13 | #include "hash.h" 14 | #include "compare.h" 15 | #include "dup.h" 16 | #include "heap.h" 17 | #include "text.h" 18 | #include "def.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | int main(int argc, char *argv[]) { 25 | if (argc < 2) { 26 | fprintf(stderr, "Usage: %s []", argv[0]); 27 | return -1; 28 | } 29 | 30 | char outfile[100]; 31 | outfile[0] = '\0'; 32 | if (argc > 2) { 33 | strcpy(outfile, argv[2]); 34 | } else { 35 | strcpy(outfile, "out.deflate"); 36 | } 37 | fprintf(stdout, "%s %s ==> %s \n", argv[0], argv[1], outfile); 38 | 39 | FILE *fin = fopen(argv[1], "r"); 40 | if (fin == NULL) { 41 | fprintf(stderr, "Error: Cannot open file [%s]", argv[1]); 42 | return -1; 43 | } 44 | 45 | fseek(fin, 0, SEEK_END); 46 | unsigned long size = ftell(fin); 47 | fseek(fin, 0, SEEK_SET); 48 | 49 | char *buffer = (char *)malloc(size); 50 | fread(buffer, 1, size, fin); 51 | fclose(fin); 52 | 53 | Heap *heap = huffman_heap_from_string(buffer, size); 54 | HuffmanTree *tree = huffman_tree_from(heap); 55 | BitMap *textbits = huffman_encode_string(tree, buffer, size); 56 | BitMap *treebits = huffman_tree_deflate(tree); 57 | free(buffer); 58 | huffman_tree_free(tree); 59 | 60 | FILE *fout = fopen(outfile, "w"); 61 | fwrite(&(treebits->num_bits), sizeof(unsigned int), 1, fout); 62 | fwrite(treebits->words, sizeof(word_t), treebits->num_words, fout); 63 | fwrite(&(textbits->num_bits), sizeof(unsigned int), 1, fout); 64 | fwrite(textbits->words, sizeof(word_t), textbits->num_words, fout); 65 | fclose(fout); 66 | 67 | bitmap_free(treebits); 68 | bitmap_free(textbits); 69 | 70 | fprintf(stdout, "done! deflate to file [%s]. \n", outfile); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /app/inflate.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file inflate.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Use Huffman Tree to inflate binary file to Text file. 5 | * @date 2019-08-30 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | #include "huffman.h" 11 | #include "hash_table.h" 12 | #include "hash.h" 13 | #include "compare.h" 14 | #include "dup.h" 15 | #include "heap.h" 16 | #include "text.h" 17 | #include "def.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | int main(int argc, char *argv[]) { 24 | if (argc < 2) { 25 | fprintf(stderr, "Usage: %s []", argv[0]); 26 | return -1; 27 | } 28 | 29 | char outfile[100]; 30 | outfile[0] = '\0'; 31 | if (argc > 2) { 32 | strcpy(outfile, argv[2]); 33 | } else { 34 | strcpy(outfile, "out.txt"); 35 | } 36 | fprintf(stdout, "%s %s ==> %s \n", argv[0], argv[1], outfile); 37 | 38 | FILE *fin = fopen(argv[1], "r"); 39 | if (fin == NULL) { 40 | fprintf(stderr, "Error: Cannot open file [%s]", argv[1]); 41 | return -1; 42 | } 43 | 44 | /** [tree_size][tree_bits][encode_size][encode_bits]*/ 45 | unsigned int num_bits; 46 | fread(&num_bits, sizeof(unsigned int), 1, fin); 47 | BitMap *treebits = bitmap_new(num_bits); 48 | fread(treebits->words, sizeof(word_t), treebits->num_words, fin); 49 | 50 | fread(&num_bits, sizeof(unsigned int), 1, fin); 51 | BitMap *textbits = bitmap_new(num_bits); 52 | fread(textbits->words, sizeof(word_t), textbits->num_words, fin); 53 | 54 | fclose(fin); 55 | 56 | HuffmanTree *tree = huffman_tree_inflate(treebits); 57 | Text *text = huffman_decode(tree, textbits); 58 | bitmap_free(treebits); 59 | bitmap_free(textbits); 60 | huffman_tree_free(tree); 61 | 62 | FILE *fout = fopen(outfile, "w"); 63 | fwrite(text_char_string(text), sizeof(char), text_length(text), fout); 64 | fclose(fout); 65 | text_free(text); 66 | 67 | fprintf(stdout, "done! inflate to file [%s]. \n", outfile); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /build/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hutusi/rethink-c/6d182b39584d5aca9ef7cc7b4f57a465fc0ab08e/build/.keep -------------------------------------------------------------------------------- /doc/intro.h: -------------------------------------------------------------------------------- 1 | /* This file is a dummy header which is used to generate the 2 | * introduction in Doxygen. */ 3 | 4 | /** 5 | * @mainpage RETHINK C --- C Algorithms Library 6 | * 7 | * @section Introduction 8 | * 9 | * Relearn and rethink C Programming Language, including some of data structures and algorithms. 10 | * 11 | * Some of the code inspired (copied) by Simon Howard's [c-algorithms](https://github.com/fragglet/c-algorithms), like ArrayList, etc. This project also reused his alloc-testing framework for memory testing. 12 | * 13 | * RETHINK-C aims to build a reuseable codebase for C Programming Language. 14 | * 15 | * @section Data_structures Data structures 16 | * 17 | * @subsection Basic Data Structures 18 | * 19 | * @li @link arraylist.h ArrayList @endlink: Automatically resizing array. 20 | * @li @link list.h LinkedList @endlink: LinkedList. 21 | * @li @link queue.h Queue @endlink: Queue. 22 | * @li @link bitmap.h BitMap @endlink: BitMap. 23 | * @li @link matrix.h Muti-dimensional Matrix @endlink: Muti-dimensional Matrix. 24 | * @li @link hash_table.h Hash Table @endlink: Hash Table. 25 | * 26 | * @subsection Trees 27 | * 28 | * @li @link bstree.h Binary Search Tree @endlink: Binary Search Tree. 29 | * @li @link avltree.h AVL Tree @endlink: AVL Tree. 30 | * @li @link rbtree.h Red Black Tree @endlink: Red Black Tree. 31 | * @li @link heap.h Binary Heap @endlink: Binary Heap. 32 | * 33 | * @subsection Graphs 34 | * 35 | * @li @link graph.h Adjacency Matrix @endlink: Adjacency Matrix. 36 | * @li @link dijkstra.h Dijkstra @endlink: Dijkstra. 37 | * 38 | * @subsection Graphs 39 | * 40 | * @li @link bignum.h BigNum integer @endlink: BigNum integer. 41 | * 42 | */ -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(algorithm compare.c dup.c text.c 2 | arraylist.c queue.c list.c bitmap.c matrix.c 3 | bstree.c avltree.c rbtree.c heap.c skip_list.c 4 | bignum.c graph.c sparse_graph.c dijkstra.c prime.c hash.c hash_table.c 5 | kmp.c bm.c sunday.c trie.c ac.c huffman.c 6 | vector.c distance.c) 7 | target_compile_options(algorithm PRIVATE ${COMPILE_OPTIONS}) 8 | target_include_directories(algorithm PRIVATE ${INCLUDE_DIRECTORIES}) 9 | -------------------------------------------------------------------------------- /src/ac.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file ac.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief AC (Aho-Corasick) algorithm. (AC ACTrie Tree). 7 | * 8 | * @date 2019-08-13 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_AC_H 15 | #define RETHINK_C_AC_H 16 | 17 | #include "hash_table.h" 18 | #include 19 | 20 | /** 21 | * @brief Definition of a @ref ACTrieNode. 22 | * 23 | */ 24 | typedef struct _ACTrieNode { 25 | /** Value of the node. */ 26 | char data; 27 | bool ending; 28 | unsigned int height; 29 | HashTable *children; 30 | struct _ACTrieNode *failure; 31 | } ACTrieNode; 32 | 33 | /** 34 | * @brief Definition of a @ref ACTrie. 35 | * 36 | */ 37 | typedef struct _ACTrie { 38 | ACTrieNode *root; 39 | } ACTrie; 40 | 41 | typedef struct _String { 42 | /** The pattern string. */ 43 | char *data; 44 | /** The length of pattern string. */ 45 | unsigned int length; 46 | } String; 47 | 48 | /** 49 | * @brief Allcate a new ACTrie. 50 | * 51 | * @return ACTrie* The new ACTrie if success, otherwise NULL. 52 | */ 53 | ACTrie *ac_trie_new(); 54 | 55 | /** 56 | * @brief Delete a ACTrie and free back memory. 57 | * 58 | * @param ac_trie The ACTrie to delete. 59 | */ 60 | void ac_trie_free(ACTrie *ac_trie); 61 | 62 | /** 63 | * @brief Insert a string into a Trie. 64 | * 65 | * @param trie The ACTrie. 66 | * @param str The string. 67 | * @param len The length of the string. 68 | * @return int 0 if success. 69 | */ 70 | int ac_trie_insert(ACTrie *trie, const char *str, unsigned int len); 71 | 72 | /** 73 | * @brief Delete a string into a Trie. 74 | * 75 | * Just mark the ending as 'false'. 76 | * 77 | * @param trie The ACTrie. 78 | * @param str The string. 79 | * @param len The length of the string. 80 | * @return int 0 if success. 81 | */ 82 | int ac_trie_delete(ACTrie *trie, const char *str, unsigned int len); 83 | 84 | /** 85 | * @brief Calculate all failure pointers of a ACTrie. 86 | * 87 | * @param trie The ACTrie. 88 | */ 89 | void ac_trie_set_failure(ACTrie *trie); 90 | 91 | /** 92 | * @brief Find all matched pattern strings in a text. 93 | * 94 | * @param trie The ACTrie to store pattern strings. 95 | * @param text The text. 96 | * @param len The length of text. 97 | * @return HashTable* The hashtable: key is pattern string (Text), value is 98 | * ArrayList of the matched indexes. 99 | */ 100 | HashTable *ac_trie_match(ACTrie *trie, const char *text, unsigned int len); 101 | 102 | #endif /* #ifndef RETHINK_C_AC_H */ 103 | -------------------------------------------------------------------------------- /src/arraylist.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file arraylist.c 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Automatically resizing array(stack) 7 | * 8 | * @copyright Copyright (c) 2019, hutusi.com 9 | * 10 | */ 11 | 12 | #include "arraylist.h" 13 | #include "def.h" 14 | #include 15 | #include 16 | 17 | ArrayList *arraylist_new(ArrayListFreeValueFunc free_value_func, 18 | unsigned int length) 19 | { 20 | ArrayList *new_arraylist; 21 | if (length <= 0) { 22 | length = 16; 23 | } 24 | new_arraylist = (ArrayList *)malloc(sizeof(ArrayList)); 25 | if (new_arraylist == NULL) { 26 | return NULL; 27 | } 28 | 29 | new_arraylist->_allocated = length; 30 | new_arraylist->length = 0; 31 | new_arraylist->_free_value_func = free_value_func; 32 | 33 | new_arraylist->data = malloc(length * sizeof(ArrayListValue)); 34 | if (new_arraylist->data == NULL) { 35 | free(new_arraylist); 36 | return NULL; 37 | } 38 | 39 | return new_arraylist; 40 | } 41 | 42 | void arraylist_free(ArrayList *arraylist) 43 | { 44 | if (arraylist->_free_value_func != NULL) { 45 | for (unsigned int i = 0; i < arraylist->length; ++i) { 46 | arraylist->_free_value_func(arraylist->data[i]); 47 | } 48 | } 49 | free(arraylist->data); 50 | free(arraylist); 51 | } 52 | 53 | static int arraylist_enlarge(ArrayList *arraylist) 54 | { 55 | ArrayListValue *data; 56 | unsigned int newsize; 57 | 58 | newsize = arraylist->_allocated * 2; 59 | data = realloc(arraylist->data, sizeof(ArrayListValue) * newsize); 60 | 61 | if (data == NULL) { 62 | return -1; 63 | } else { 64 | arraylist->data = data; 65 | arraylist->_allocated = newsize; 66 | return 0; 67 | } 68 | } 69 | 70 | int arraylist_insert(ArrayList *arraylist, 71 | unsigned int index, 72 | ArrayListValue data) 73 | { 74 | if (index < 0 || index > arraylist->length) { 75 | return -1; 76 | } 77 | 78 | if (arraylist->_allocated < arraylist->length + 1) { 79 | if (arraylist_enlarge(arraylist) != 0) { 80 | return -1; 81 | } 82 | } 83 | 84 | memmove(&arraylist->data[index + 1], 85 | &arraylist->data[index], 86 | (arraylist->length - index) * sizeof(ArrayListValue)); 87 | 88 | arraylist->data[index] = data; 89 | arraylist->length += 1; 90 | 91 | return 0; 92 | } 93 | 94 | int arraylist_append(ArrayList *arraylist, ArrayListValue data) 95 | { 96 | return arraylist_insert(arraylist, arraylist->length, data); 97 | } 98 | 99 | int arraylist_prepend(ArrayList *arraylist, ArrayListValue data) 100 | { 101 | return arraylist_insert(arraylist, 0, data); 102 | } 103 | 104 | int arraylist_push(ArrayList *arraylist, ArrayListValue data) 105 | { 106 | return arraylist_insert(arraylist, arraylist->length, data); 107 | } 108 | 109 | ArrayListValue arraylist_pop(ArrayList *arraylist) 110 | { 111 | --(arraylist->length); 112 | return arraylist->data[arraylist->length]; 113 | } 114 | 115 | int arraylist_remove_range(ArrayList *arraylist, 116 | unsigned int index, 117 | unsigned int length) 118 | { 119 | if (index >= arraylist->length) { 120 | return -1; 121 | } 122 | 123 | if (length > arraylist->length - index) { 124 | return -1; 125 | } 126 | 127 | memmove(&arraylist->data[index], 128 | &arraylist->data[index + length], 129 | (arraylist->length - (index + length)) * sizeof(ArrayListValue)); 130 | arraylist->length -= length; 131 | return 0; 132 | } 133 | 134 | int arraylist_remove(ArrayList *arraylist, unsigned int index) 135 | { 136 | return arraylist_remove_range(arraylist, index, 1); 137 | } 138 | 139 | void arraylist_clear(ArrayList *arraylist) 140 | { 141 | arraylist->length = 0; 142 | } 143 | 144 | int arraylist_index_of(const ArrayList *arraylist, 145 | ArrayListValueCompareFunc callback, 146 | ArrayListValue data) 147 | { 148 | int index; 149 | 150 | if (callback == NULL) { 151 | return -1; 152 | } 153 | 154 | for (index = 0; index < arraylist->length; ++index) { 155 | if (callback(arraylist->data[index], data) == 0) { 156 | return index; 157 | } 158 | } 159 | 160 | return -1; 161 | } 162 | 163 | #define swap_with_tmp(a, b, tmp) \ 164 | if (a != b) { \ 165 | tmp = a; \ 166 | a = b; \ 167 | b = tmp; \ 168 | } 169 | 170 | /** 171 | * @brief Sort internal function. 172 | * 173 | * Use quick sort. 174 | * 175 | * @param list_data 176 | * @param list_length 177 | * @param compare_func 178 | * @return int 179 | */ 180 | static int arraylist_sort_internal(ArrayListValue *list_data, 181 | unsigned int list_length, 182 | ArrayListValueCompareFunc compare_func) 183 | { 184 | ArrayListValue pivot, tmp; 185 | unsigned int i, left_length, right_length; 186 | 187 | if (list_length <= 1) { 188 | return 0; 189 | } 190 | 191 | pivot = list_data[list_length - 1]; 192 | left_length = 0; 193 | 194 | for (i = 0; i < list_length - 1; ++i) { 195 | if (compare_func(list_data[i], pivot) < 0) { 196 | swap_with_tmp(list_data[left_length], list_data[i], tmp); 197 | ++left_length; 198 | } else { 199 | // do nothing 200 | } 201 | } 202 | swap_with_tmp(list_data[left_length], list_data[list_length - 1], tmp); 203 | right_length = list_length - left_length - 1; // 1 for pivot 204 | 205 | if (left_length > 1) { 206 | arraylist_sort_internal(list_data, left_length, compare_func); 207 | } 208 | 209 | if (right_length > 1) { 210 | arraylist_sort_internal( 211 | &list_data[left_length + 1], right_length, compare_func); 212 | } 213 | 214 | return 0; 215 | } 216 | 217 | int arraylist_sort(ArrayList *arraylist, ArrayListValueCompareFunc compare_func) 218 | { 219 | return arraylist_sort_internal( 220 | arraylist->data, arraylist->length, compare_func); 221 | } 222 | -------------------------------------------------------------------------------- /src/arraylist.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file arraylist.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Automatically resizing array(stack). 7 | * 8 | * ArrayLists are arrays of pointers which automatically increase in 9 | * size. 10 | * 11 | * To create an ArrayList, use @ref arraylist_new. 12 | * To destroy an ArrayList, use @ref arraylist_free. 13 | * 14 | * To add a value to an ArrayList, use @ref arraylist_prepend, 15 | * @ref arraylist_append, or @ref arraylist_insert. 16 | * 17 | * To remove a value from an ArrayList, use @ref arraylist_remove 18 | * or @ref arraylist_remove_range. 19 | * 20 | * ArrayList can be treated as stack, use @ref arraylist_push, 21 | * @ref arraylist_pop to push or pop element value. 22 | * 23 | * @date 2019-07-20 24 | * 25 | * @copyright Copyright (c) 2019, hutusi.com 26 | * 27 | */ 28 | 29 | #ifndef RETHINK_C_ARRAYLIST_H 30 | #define RETHINK_C_ARRAYLIST_H 31 | 32 | /** 33 | * @brief The type of a value to be stored in an @ref ArrayList. 34 | * (void *) can be changed to int, long, or other types if needed. 35 | */ 36 | typedef void *ArrayListValue; 37 | 38 | /** 39 | * @brief Array List free value callback function. 40 | * 41 | */ 42 | typedef void (*ArrayListFreeValueFunc)(ArrayListValue value); 43 | 44 | /** 45 | * @brief Definition of an @ref ArrayList. 46 | */ 47 | typedef struct _ArrayList { 48 | /** Entries in the array */ 49 | ArrayListValue *data; 50 | /** Length of the array */ 51 | unsigned int length; 52 | /** Allocated length of the array. 53 | * (Private data and should not be accessed) */ 54 | unsigned int _allocated; 55 | /** Free value call back function. */ 56 | ArrayListFreeValueFunc _free_value_func; 57 | } ArrayList, Stack; 58 | 59 | /** 60 | * @brief Allocated a new ArrayList for use. 61 | * 62 | * @param free_value_func Free value callback function. 63 | * @param length The initiate length of ArrayList. 64 | * @return ArrayList* 65 | */ 66 | ArrayList *arraylist_new(ArrayListFreeValueFunc free_value_func, 67 | unsigned int length); 68 | 69 | /** 70 | * @brief Destroy an ArrayList and free back the memory. 71 | * 72 | * @param arraylist The arraylist to free. 73 | */ 74 | void arraylist_free(ArrayList *arraylist); 75 | 76 | /** 77 | * @brief Append a value to the end of an ArrayList. 78 | * 79 | * @param arraylist The ArrayList. 80 | * @param data The value to append. 81 | * @return int 0 if success. 82 | */ 83 | int arraylist_append(ArrayList *arraylist, ArrayListValue data); 84 | 85 | /** 86 | * @brief Prepend a value to the beginning of an ArrayList. 87 | * 88 | * @param arraylist The ArrayList. 89 | * @param data The value to prepend. 90 | * @return int 0 if success. 91 | */ 92 | int arraylist_prepend(ArrayList *arraylist, ArrayListValue data); 93 | 94 | /** 95 | * @brief Insert a value into an ArrayList. 96 | * 97 | * @param arraylist The ArrayList. 98 | * @param index The index to be insert. 99 | * @param data The value to insert. 100 | * @return int 0 if success. 101 | */ 102 | int arraylist_insert(ArrayList *arraylist, 103 | unsigned int index, 104 | ArrayListValue data); 105 | 106 | /** 107 | * @brief Push a value to the end of an ArrayList. 108 | * 109 | * @param arraylist The ArrayList. 110 | * @param data The value to push. 111 | * @return int 0 if success. 112 | */ 113 | int arraylist_push(ArrayList *arraylist, ArrayListValue data); 114 | 115 | /** 116 | * @brief Pop a value from the end of an ArrayList. 117 | * 118 | * @param arraylist The ArrayList. 119 | * @return ArrayListValue Value if success, otherwise return NULL. 120 | */ 121 | ArrayListValue arraylist_pop(ArrayList *arraylist); 122 | 123 | /** 124 | * @brief Remove the entry at the specified location in an ArrayList. 125 | * 126 | * @param arraylist The ArrayList. 127 | * @param index The index of entry to remove. 128 | * @return int 0 if success. 129 | */ 130 | int arraylist_remove(ArrayList *arraylist, unsigned int index); 131 | 132 | /** 133 | * @brief Remove a range of entries at the specified location in an ArrayList. 134 | * 135 | * @param arraylist The ArrayList. 136 | * @param index The index of the start of the range to remove. 137 | * @param length The length of the range to remove. 138 | * @return int 0 if success. 139 | */ 140 | int arraylist_remove_range(ArrayList *arraylist, 141 | unsigned int index, 142 | unsigned int length); 143 | 144 | /** 145 | * @brief Clear all entries of an ArrayList. 146 | * 147 | * @param arraylist The ArrayList. 148 | */ 149 | void arraylist_clear(ArrayList *arraylist); 150 | 151 | /** 152 | * @brief Compare two values in an ArrayList. 153 | * 154 | * @param left The first value. 155 | * @param right The second value. 156 | * @return A negative number if left should be sorted before right, 157 | * a positive number if right should be sorted before left, 158 | * zero if the two values are equal. 159 | */ 160 | typedef int (*ArrayListValueCompareFunc)(ArrayListValue left, 161 | ArrayListValue right); 162 | 163 | /** 164 | * @brief Find the index of a particular value in an ArrayList. 165 | * 166 | * @param arraylist The ArrayList. 167 | * @param callback The compare function callback. 168 | * @param data The value to search for. 169 | * @return int The index of the value if found, or -1 if not found. 170 | */ 171 | int arraylist_index_of(const ArrayList *arraylist, 172 | ArrayListValueCompareFunc callback, 173 | ArrayListValue data); 174 | 175 | /** 176 | * @brief Sort the values in an ArrayList. 177 | * 178 | * @param arraylist The ArrayList. 179 | * @param compare_func Function callback used to compare values in sorting. 180 | * @return int 0 if success. 181 | */ 182 | int arraylist_sort(ArrayList *arraylist, 183 | ArrayListValueCompareFunc compare_func); 184 | 185 | #endif /* #ifndef RETHINK_C_ARRAYLIST_H */ 186 | -------------------------------------------------------------------------------- /src/bignum.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bignum.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Big number operation: Addition, Subtraction, Multiplication, 7 | * and Division. Use char string to store big number. 8 | * 9 | * Before arithmetic calculations, use @ref bignum_int_sanitize to 10 | * sanitize the char string. 11 | * 12 | * To do addition, use @ref bignum_int_addition. 13 | * 14 | * To do subtraction, use @ref bignum_int_subtraction. 15 | * 16 | * To do multiplication, use @ref bignum_int_multiplication. 17 | * 18 | * To do division, use @ref bignum_int_division. 19 | * 20 | * @date 2019-07-20 21 | * 22 | * @copyright Copyright (c) 2019, hutusi.com 23 | * 24 | */ 25 | 26 | #ifndef RETHINK_C_BIGNUM_H 27 | #define RETHINK_C_BIGNUM_H 28 | 29 | /** 30 | * @brief The sign type to differentiate positive or negative number. 31 | * NaN means Not a Number. 32 | */ 33 | typedef enum _Sign { Positive = 1, Negative = -1, NaN = 0 } Sign; 34 | 35 | /** 36 | * @brief Compare an number with zero. 37 | * 38 | * @param num the Number. 39 | * @return int 1 if greater than 0, -1 if less than 0, 0 if equals 0. 40 | */ 41 | int bignum_int_compare_zero(const char *num); 42 | 43 | /** 44 | * @brief Compare two number. 45 | * 46 | * @param left The first number. 47 | * @param right The second number. 48 | * @return int 1 if left greater than right, -1 if right greater than left, 49 | * 0 if left equals right. 50 | */ 51 | int bignum_int_compare(const char *left, const char *right); 52 | 53 | /** 54 | * @brief Sanitize the number(char string). 55 | * 56 | * For the big number is represented as char string, it should be sanitized 57 | * before do calculations. e.g., "0001 " "0001" "-123456" will delete 0s or 58 | * blanks, and the sign '+' or '-' will be deleted too, return the sign. 59 | * 60 | * @param num The number be both input and output para. If the input number 61 | * is a invalid number string (like "ABC001"), it will be output 62 | * as "0". 63 | * @return Sign The number's sign. 64 | */ 65 | Sign bignum_int_sanitize(char *num); 66 | 67 | /** 68 | * @brief Do addition. 69 | * 70 | * @param addend The addend number. 71 | * @param aug The augend number. 72 | * @param sum The sum. 73 | * @return Sign The sum sign. (Always Positive.) 74 | */ 75 | Sign bignum_int_addition(const char *addend, const char *aug, char *sum); 76 | 77 | /** 78 | * @brief Do subtraction. 79 | * 80 | * @param minuend The minuend number. 81 | * @param subtractor The subtractor number. 82 | * @param difference The difference number. 83 | * @return Sign The difference sign. 84 | */ 85 | Sign bignum_int_subtraction(const char *minuend, 86 | const char *subtractor, 87 | char *difference); 88 | 89 | /** 90 | * @brief Do multiplication. 91 | * 92 | * @param multiplicand The multiplicand number. 93 | * @param multiplier The multiplier number. 94 | * @param product The product number. 95 | * @return Sign The product sign. (Always Positive.) 96 | */ 97 | Sign bignum_int_multiplication(const char *multiplicand, 98 | const char *multiplier, 99 | char *product); 100 | 101 | /** 102 | * @brief Do division. 103 | * 104 | * @param dividend The dividend number. 105 | * @param divisor The divisor number. 106 | * @param quotient The quotient number. 107 | * @param remainder The remainder number. 108 | * @return Sign The product sign. (Always Positive.) 109 | */ 110 | Sign bignum_int_division(const char *dividend, 111 | const char *divisor, 112 | char *quotient, 113 | char *remainder); 114 | 115 | #endif /* RETHINK_C_BIGNUM_H */ 116 | -------------------------------------------------------------------------------- /src/bm.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bm.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to bm.h 5 | * @date 2019-08-10 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "bm.h" 12 | #include "def.h" 13 | #include 14 | #include 15 | #include 16 | 17 | /** 18 | * @brief Calculate bad charactors. 19 | * 20 | * @param pattern 21 | * @param len 22 | * @param bad_chars 23 | * @return STATIC bm_calculate_bad_chars 24 | */ 25 | STATIC void bm_calculate_bad_chars(const char *pattern, int len, int *bad_chars) 26 | { 27 | for (int i = 0; i < 256; ++i) { 28 | bad_chars[i] = -1; 29 | } 30 | 31 | for (int i = len - 1; i >= 0; --i) { 32 | int ch = pattern[i]; 33 | if (bad_chars[ch] < 0) { 34 | bad_chars[ch] = i; 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * @brief Calculate good suffixes 41 | * 42 | * @param pattern 43 | * @param len 44 | * @param good_suffixes 45 | * @return STATIC bm_calculate_good_suffixes 46 | */ 47 | STATIC void 48 | bm_calculate_good_suffixes(const char *pattern, int len, int *good_suffixes) 49 | { 50 | for (int i = 0; i <= len; ++i) { 51 | good_suffixes[i] = -1; 52 | } 53 | 54 | for (int i = 0; i < len - 1; ++i) { 55 | int j = i; 56 | int k = 0; 57 | while (j >= 0 && pattern[j] == pattern[len - 1 + j - i]) { 58 | ++k; 59 | good_suffixes[k] = j; 60 | --j; 61 | } 62 | } 63 | } 64 | 65 | STATIC int bm_move_by_good_suffixes(int *good_suffixes, int len, int good_len) 66 | { 67 | if (good_len == 0) { 68 | return 1; 69 | } else { 70 | return len - good_suffixes[good_len] - good_len; 71 | } 72 | } 73 | 74 | #define MAX(a, b) ((a) < (b) ? (b) : (a)) 75 | 76 | /** 77 | * @brief BM algorithm function 78 | * 79 | * There are two rules in BM algorithm. 80 | * 81 | * rule 1: bad charactor. 82 | * 83 | * compare begin with last charactor: 84 | * ! 85 | * abceaebabcde 86 | * abcd 87 | * 88 | * 'e' is a bad charactor, 'e' is not in 'abcd', move length 4('abcd'): 89 | * ! 90 | * abceaebabcde 91 | * abcd 92 | * 93 | * now 'a' is a bad charactor, 'a' in 'abcd', move to make 'a' align with 'a': 94 | * 95 | * ! 96 | * abceaebabcde 97 | * abcd 98 | * 99 | * 100 | * rule 2: good suffix. 101 | * 102 | * compare begin with last charactor: 103 | * ! 104 | * abceaabccabef 105 | * aabccab 106 | * 107 | * step to left: 'ab' is good suffix, 'a', 'c' not match: 108 | * *!! 109 | * abceaabccabef 110 | * aabccab 111 | * 112 | * move length 4 to make 'ab' align with 'ab': 113 | * 114 | * !! 115 | * abceaabccabef 116 | * aabccab 117 | * 118 | * 119 | * @param text 120 | * @param pattern 121 | * @return int 122 | */ 123 | int bm_text_match(const char *text, 124 | unsigned int text_len, 125 | const char *pattern, 126 | unsigned int pat_len) 127 | { 128 | int bad_chars[256]; 129 | bm_calculate_bad_chars(pattern, pat_len, bad_chars); 130 | 131 | int *good_suffixes = (int *)malloc((pat_len + 1) * sizeof(int)); 132 | bool *prefixes = (bool *)malloc(pat_len * sizeof(bool)); 133 | bm_calculate_good_suffixes(pattern, pat_len, good_suffixes); 134 | 135 | int index = -1; 136 | int cursor = 0; 137 | while (cursor <= text_len - pat_len) { 138 | int i = 0; 139 | for (; i < pat_len; ++i) { 140 | if (text[cursor + pat_len - 1 - i] == pattern[pat_len - 1 - i]) { 141 | 142 | } else { 143 | int bad = pat_len - i - 1 - 144 | bad_chars[(int)text[cursor + pat_len - 1 - i]]; 145 | int good = bm_move_by_good_suffixes(good_suffixes, pat_len, i); 146 | cursor += MAX(bad, good); 147 | break; 148 | } 149 | } 150 | 151 | if (i == pat_len) { // found it! 152 | index = cursor; 153 | break; 154 | } 155 | } 156 | 157 | free(good_suffixes); 158 | free(prefixes); 159 | return index; 160 | } 161 | 162 | int bm_string_match(const char *text, const char *pattern) 163 | { 164 | return bm_text_match(text, strlen(text), pattern, strlen(pattern)); 165 | } 166 | -------------------------------------------------------------------------------- /src/bm.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bm.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief BM (Boyer-Moore) algorithm. 7 | * 8 | * @date 2019-08-10 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_BM_H 15 | #define RETHINK_C_BM_H 16 | 17 | /** 18 | * @brief BM algorithm to find the match substring. 19 | * 20 | * @param text The text string. 21 | * @param text_len The length of text. 22 | * @param pattern The pattern string. 23 | * @param pat_len The length of pattern string. 24 | * @return int The first match index, -1 if no match. 25 | */ 26 | int bm_text_match(const char *text, 27 | unsigned int text_len, 28 | const char *pattern, 29 | unsigned int pat_len); 30 | 31 | /** 32 | * @brief BM algorithm to find the match substring. 33 | * 34 | * @param text The text string. 35 | * @param pattern The pattern string. 36 | * @return int The first match index, -1 if no match. 37 | */ 38 | int bm_string_match(const char *text, const char *pattern); 39 | 40 | #endif /* #ifndef RETHINK_C_BM_H */ 41 | -------------------------------------------------------------------------------- /src/bstree.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file bstree.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Binary search tree. 7 | * 8 | * @date 2019-07-20 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_BS_TREE_H 15 | #define RETHINK_C_BS_TREE_H 16 | 17 | /** 18 | * @brief The type of a value to be stored in a @ref BSTreeNode. 19 | * (void *) can be changed to int, long, or other types if needed. 20 | */ 21 | typedef void *BSTreeValue; 22 | 23 | /** 24 | * @brief Definition of a @ref BSTreeNode. 25 | * 26 | */ 27 | typedef struct _BSTreeNode { 28 | /** Value of the node. */ 29 | BSTreeValue data; 30 | /** Parent node pointer. */ 31 | struct _BSTreeNode *parent; 32 | /** Left child node pointer. */ 33 | struct _BSTreeNode *left; 34 | /** Right child node pointer. */ 35 | struct _BSTreeNode *right; 36 | } BSTreeNode; 37 | 38 | typedef int (*BSTreeCompareFunc)(BSTreeValue data1, BSTreeValue data2); 39 | 40 | /** 41 | * @brief Definition of a @ref BSTree. 42 | * 43 | */ 44 | typedef struct _BSTree { 45 | /** Root node of the @ref BSTree pointer. */ 46 | struct _BSTreeNode *root; 47 | /** Compare two node value when do searching in BSTree. */ 48 | BSTreeCompareFunc compare_func; 49 | /** The number of nodes of the @ref BSTree. */ 50 | unsigned int num_nodes; 51 | } BSTree; 52 | 53 | /** 54 | * @brief Allcate a new BSTree. 55 | * 56 | * @param compare_func Compare two node value when do searching in BSTree. 57 | * @return BSTree* The new BSTree if success, otherwise return NULL. 58 | */ 59 | BSTree *bs_tree_new(BSTreeCompareFunc compare_func); 60 | 61 | /** 62 | * @brief Delete a BSTree and free back memory. 63 | * 64 | * @param tree The BSTree to delete. 65 | */ 66 | void bs_tree_free(BSTree *tree); 67 | 68 | /** 69 | * @brief Get the leftmost child node of a BSTreeNode. 70 | * 71 | * @param node The BSTreeNode. 72 | * @return BSTreeNode* The leftmost BSTreeNode. If the BSTreeNode has 73 | * no left child, return itself. 74 | */ 75 | BSTreeNode *bs_tree_leftmost_node(BSTreeNode *node); 76 | 77 | /** 78 | * @brief Get the rightmost child node of a BSTreeNode. 79 | * 80 | * @param node The BSTreeNode. 81 | * @return BSTreeNode* The rightmost BSTreeNode. If the BSTreeNode has 82 | * no right child, return itself. 83 | */ 84 | BSTreeNode *bs_tree_rightmost_node(BSTreeNode *node); 85 | 86 | /** 87 | * @brief Insert a BSTreeValue to a BSTree. 88 | * 89 | * @param tree The BSTree. 90 | * @param data The value to insert. 91 | * @return BSTreeNode* The new inserted BSTreeNode if success, 92 | * otherwise return NULL. 93 | */ 94 | BSTreeNode *bs_tree_insert(BSTree *tree, BSTreeValue data); 95 | 96 | /** 97 | * @brief Remove a BSTreeNode from a BSTree. 98 | * 99 | * @param tree The BSTree. 100 | * @param node The BSTreeNode. 101 | * @return BSTreeNode* The removed BSTreeNode if success, 102 | * otherwise return NULL. 103 | */ 104 | BSTreeNode *bs_tree_remove_node(BSTree *tree, BSTreeNode *node); 105 | 106 | /** 107 | * @brief Find a BSTreeNode value in a BSTree. 108 | * 109 | * @param tree The BSTree. 110 | * @param data The BSTreeNode value to lookup. 111 | * @return BSTreeNode* The matched BSTreeNode if success, 112 | * otherwise return NULL. 113 | */ 114 | BSTreeNode *bs_tree_lookup_data(BSTree *tree, BSTreeValue data); 115 | 116 | typedef void (*BSTreeTraverseFunc)(BSTreeNode *node, void *args); 117 | 118 | /** 119 | * @brief Traverse BSTree by preorder. 120 | * 121 | * @param tree The BSTree. 122 | * @param callback The callback function do to each BSTreeNode in traverse. 123 | * @param cb_args The callback function's args. 124 | */ 125 | void bs_tree_preorder_traverse(BSTree *tree, 126 | BSTreeTraverseFunc callback, 127 | void *cb_args); 128 | 129 | /** 130 | * @brief Traverse BSTree by inorder. 131 | * 132 | * @param tree The BSTree. 133 | * @param callback The callback function do to each BSTreeNode in traverse. 134 | * @param cb_args The callback function's args. 135 | */ 136 | void bs_tree_inorder_traverse(BSTree *tree, 137 | BSTreeTraverseFunc callback, 138 | void *cb_args); 139 | 140 | /** 141 | * @brief Traverse BSTree by postorder. 142 | * 143 | * @param tree The BSTree. 144 | * @param callback The callback function do to each BSTreeNode in traverse. 145 | * @param cb_args The callback function's args. 146 | */ 147 | void bs_tree_postorder_traverse(BSTree *tree, 148 | BSTreeTraverseFunc callback, 149 | void *cb_args); 150 | 151 | #endif /* #ifndef RETHINK_C_BS_TREE_H */ 152 | -------------------------------------------------------------------------------- /src/compare.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file compare.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to compare.h 5 | * @date 2019-08-11 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "compare.h" 12 | #include "def.h" 13 | 14 | int int_equal(void *address1, void *address2) 15 | { 16 | return *((int *)address1) == *((int *)address2); 17 | } 18 | 19 | int int_compare(void *address1, void *address2) 20 | { 21 | int value1 = *((int *)address1); 22 | int value2 = *((int *)address2); 23 | 24 | if (value1 < value2) { 25 | return -1; 26 | } else if (value1 > value2) { 27 | return 1; 28 | } else { 29 | return 0; 30 | } 31 | } 32 | 33 | int char_equal(void *address1, void *address2) 34 | { 35 | return *((char *)address1) == *((char *)address2); 36 | } 37 | 38 | int char_compare(void *address1, void *address2) 39 | { 40 | char value1 = *((char *)address1); 41 | char value2 = *((char *)address2); 42 | 43 | if (value1 < value2) { 44 | return -1; 45 | } else if (value1 > value2) { 46 | return 1; 47 | } else { 48 | return 0; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/compare.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file compare.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Compare & Equal functions (between two pointers). 7 | * 8 | * @date 2019-08-11 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_COMPARE_H 15 | #define RETHINK_C_COMPARE_H 16 | 17 | /** 18 | * @brief Equal function of two integers. 19 | * 20 | * @param address1 The first integer pointer address. 21 | * @param address2 The second integer pointer address. 22 | * @return int 1 if equal, otherwise 0. 23 | */ 24 | int int_equal(void *address1, void *address2); 25 | 26 | /** 27 | * @brief Compare function of two integers. 28 | * 29 | * @param address1 The first integer pointer address. 30 | * @param address2 The second integer pointer address. 31 | * @return int 0 if equal, -1 if first less than second, 1 if first greater 32 | * than second. 33 | */ 34 | int int_compare(void *address1, void *address2); 35 | 36 | /** 37 | * @brief Equal function of two chars. 38 | * 39 | * @param address1 The first char pointer address. 40 | * @param address2 The second char pointer address. 41 | * @return int 1 if equal, otherwise 0. 42 | */ 43 | int char_equal(void *address1, void *address2); 44 | 45 | /** 46 | * @brief Compare function of two chars. 47 | * 48 | * @param address1 The first char pointer address. 49 | * @param address2 The second char pointer address. 50 | * @return int 0 if equal, -1 if first less than second, 1 if first greater 51 | * than second. 52 | */ 53 | int char_compare(void *address1, void *address2); 54 | 55 | #endif /* #ifndef RETHINK_C_COMPARE_H */ 56 | -------------------------------------------------------------------------------- /src/def.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file def.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Defines. 7 | * 8 | * @date 2019-08-11 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_DEF_H 15 | #define RETHINK_C_DEF_H 16 | 17 | #ifdef TESTING 18 | #define STATIC 19 | #else 20 | #define STATIC static 21 | #endif 22 | 23 | #ifdef ALLOC_TESTING 24 | #include "alloc-testing.h" 25 | #endif 26 | 27 | #endif /* #ifndef RETHINK_C_DEF_H */ 28 | -------------------------------------------------------------------------------- /src/dijkstra.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dijkstra.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to dijkstra.h 5 | * @date 2019-07-21 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "dijkstra.h" 12 | #include "def.h" 13 | #include 14 | 15 | static void dijkstra_init_distances(int *distances, int num_vertexes) 16 | { 17 | for (int i = 0; i < num_vertexes; ++i) { 18 | distances[i] = -1; 19 | } 20 | } 21 | 22 | static void dijkstra_refresh_candidates(const AdjacencyMatrix *graph, 23 | int vertex, 24 | int *distances, 25 | int *candidates) 26 | { 27 | for (int i = 0; i < graph->num_vertexes; ++i) { 28 | int edge = adjacency_matrix_get(graph, vertex, i); 29 | /** if distances[i] > 0, the vertex has been selected */ 30 | if (edge >= 0 && distances[i] < 0) { 31 | int new_weight = distances[vertex] + edge; 32 | if (candidates[i] < 0 || candidates[i] > new_weight) { 33 | candidates[i] = new_weight; 34 | } 35 | } 36 | } 37 | candidates[vertex] = -1; 38 | } 39 | 40 | static int dijkstra_select_vertex(int *candidates, int num_vertexes) 41 | { 42 | int weight = -1; 43 | int vertex = -1; 44 | for (int i = 0; i < num_vertexes; ++i) { 45 | if (candidates[i] >= 0 && (weight == -1 || weight > candidates[i])) { 46 | weight = candidates[i]; 47 | vertex = i; 48 | } 49 | } 50 | return vertex; 51 | } 52 | 53 | void dijkstra(const AdjacencyMatrix *graph, int vertex, int *distances) 54 | { 55 | dijkstra_init_distances(distances, graph->num_vertexes); 56 | int *candidates = (int *)malloc(sizeof(int *) * graph->num_vertexes); 57 | dijkstra_init_distances(candidates, graph->num_vertexes); 58 | 59 | int select = vertex; 60 | candidates[vertex] = 0; 61 | while (select >= 0) { 62 | distances[select] = candidates[select]; 63 | dijkstra_refresh_candidates(graph, select, distances, candidates); 64 | select = dijkstra_select_vertex(candidates, graph->num_vertexes); 65 | } 66 | 67 | free(candidates); 68 | } 69 | -------------------------------------------------------------------------------- /src/dijkstra.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dijkstra.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Dijkstra algorithm. 7 | * 8 | * @date 2019-07-21 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_DIJKSTRA_H 15 | #define RETHINK_C_DIJKSTRA_H 16 | 17 | #include "graph.h" 18 | 19 | /** 20 | * @brief Dijkstra algorithm. 21 | * 22 | * @param graph AdjacencyMatrix graph. 23 | * @param vertex The start vertex. 24 | * @param distances The distances array. (output) 25 | */ 26 | void dijkstra(const AdjacencyMatrix *graph, int vertex, int *distances); 27 | 28 | #endif /* #ifndef RETHINK_C_DIJKSTRA_H */ 29 | -------------------------------------------------------------------------------- /src/distance.c: -------------------------------------------------------------------------------- 1 | #include "distance.h" 2 | #include 3 | 4 | /** 5 | * v1 6 | * \ 7 | * \ <------ Euclidiean distance 8 | * \ 9 | * v2 10 | * 11 | */ 12 | double euclidiean_distance(const Vector *v1, const Vector *v2) 13 | { 14 | double amount = 0; 15 | for (int i = 0; i < v1->num_dimensions; ++i) { 16 | double distance = fabs(v2->coordinates[i] - v1->coordinates[i]); 17 | amount += distance * distance; 18 | } 19 | 20 | return sqrt(amount); 21 | } 22 | 23 | /** 24 | * v1 25 | * | 26 | * - <------ Manhattan distance (city block) 27 | * | 28 | * -----v2 29 | */ 30 | double manhattan_distance(const Vector *v1, const Vector *v2) 31 | { 32 | double distance = 0; 33 | for (int i = 0; i < v1->num_dimensions; ++i) { 34 | distance += fabs(v2->coordinates[i] - v1->coordinates[i]); 35 | } 36 | 37 | return distance; 38 | } 39 | -------------------------------------------------------------------------------- /src/distance.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file distance.h 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief 5 | * @date 2019-08-29 6 | * 7 | * https://en.wikipedia.org/wiki/Category:Similarity_and_distance_measures 8 | * 9 | * @copyright Copyright (c) 2019, hutusi.com 10 | * 11 | */ 12 | 13 | #ifndef RETHINK_C_DISTANCE_H 14 | #define RETHINK_C_DISTANCE_H 15 | 16 | #include "vector.h" 17 | 18 | /** 19 | * @brief Calculate the Euclidiean distance between two vectors. 20 | * 21 | * @param v1 Vector 1. 22 | * @param v2 Vector 2. 23 | * @return double The Euclidiean distance. 24 | */ 25 | double euclidiean_distance(const Vector *v1, const Vector *v2); 26 | 27 | /** 28 | * @brief Calculate the Manhattan distance (city block) between two vectors. 29 | * 30 | * @param v1 Vector 1. 31 | * @param v2 Vector 2. 32 | * @return double The Manhattan distance. 33 | */ 34 | double manhattan_distance(const Vector *v1, const Vector *v2); 35 | 36 | #endif /* #ifndef RETHINK_C_DISTANCE_H */ 37 | -------------------------------------------------------------------------------- /src/dup.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dup.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to dup.h 5 | * @date 2019-08-16 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "dup.h" 12 | #include 13 | #include "def.h" 14 | 15 | int *intdup(int value) 16 | { 17 | int *dup = (int *)malloc(sizeof(int)); 18 | *dup = value; 19 | return dup; 20 | } 21 | 22 | char *char_dup(char value) 23 | { 24 | char *dup = (char *)malloc(sizeof(char)); 25 | *dup = value; 26 | return dup; 27 | } 28 | -------------------------------------------------------------------------------- /src/dup.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dup.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Utility functions: duplicate primitive value. 7 | * 8 | * intdup, like strdup. 9 | * 10 | * @date 2019-08-16 11 | * 12 | * @copyright Copyright (c) 2019, hutusi.com 13 | * 14 | */ 15 | 16 | #ifndef RETHINK_C_DUP_H 17 | #define RETHINK_C_DUP_H 18 | 19 | /** 20 | * @brief Duplicate a int and return it's pointer. 21 | * 22 | * @param value The original value. 23 | * @return int* The pointer. 24 | */ 25 | int *intdup(int value); 26 | 27 | /** 28 | * @brief Duplicate a char and return it's pointer. 29 | * 30 | * @param value The original value. 31 | * @return int* The pointer. 32 | */ 33 | char *char_dup(char value); 34 | 35 | #endif /* #ifndef RETHINK_C_DUP_H */ 36 | -------------------------------------------------------------------------------- /src/graph.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file graph.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to graph.h 5 | * @date 2019-07-21 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "graph.h" 12 | #include "def.h" 13 | #include "dup.h" 14 | #include "queue.h" 15 | 16 | #include 17 | #include 18 | 19 | AdjacencyMatrix *adjacency_matrix_new(GraphType type, int num_vertexes) 20 | { 21 | AdjacencyMatrix *graph = (AdjacencyMatrix *)malloc(sizeof(AdjacencyMatrix)); 22 | graph->type = type; 23 | graph->num_vertexes = num_vertexes; 24 | graph->edges = (int **)malloc(sizeof(int *) * num_vertexes); 25 | for (int i = 0; i < num_vertexes; ++i) { 26 | graph->edges[i] = (int *)malloc(sizeof(int) * num_vertexes); 27 | } 28 | 29 | adjacency_matrix_reset(graph, -1); 30 | return graph; 31 | } 32 | 33 | void adjacency_matrix_free(AdjacencyMatrix *graph) 34 | { 35 | for (int i = 0; i < graph->num_vertexes; ++i) { 36 | free(graph->edges[i]); 37 | } 38 | free(graph->edges); 39 | free(graph); 40 | } 41 | 42 | void adjacency_matrix_reset(AdjacencyMatrix *graph, int weight) 43 | { 44 | for (int i = 0; i < graph->num_vertexes; ++i) { 45 | for (int j = 0; j < graph->num_vertexes; ++j) { 46 | graph->edges[i][j] = weight; 47 | } 48 | } 49 | } 50 | 51 | void adjacency_matrix_set(AdjacencyMatrix *graph, 52 | int vertex1, 53 | int vertex2, 54 | int edge) 55 | { 56 | graph->edges[vertex1][vertex2] = edge; 57 | } 58 | 59 | int adjacency_matrix_get(const AdjacencyMatrix *graph, int vertex1, int vertex2) 60 | { 61 | return graph->edges[vertex1][vertex2]; 62 | } 63 | 64 | static inline void adjacency_matrix_link_internal(AdjacencyMatrix *graph, int vertex1, int vertex2) 65 | { 66 | graph->edges[vertex1][vertex2] = 1; 67 | } 68 | 69 | int adjacency_matrix_link(AdjacencyMatrix *graph, int vertex1, int vertex2) 70 | { 71 | adjacency_matrix_link_internal(graph, vertex1, vertex2); 72 | if (graph->type == UndirectedUnweighted || graph->type == UndirectedWeighted) { 73 | adjacency_matrix_link_internal(graph, vertex2, vertex1); 74 | } 75 | return 0; 76 | } 77 | 78 | static inline int 79 | adjacency_matrix_connected(const AdjacencyMatrix *graph, int from, int to) 80 | { 81 | return graph->edges[from][to] >= 0; 82 | } 83 | 84 | int adjacency_matrix_bfs(const AdjacencyMatrix *graph, int start, int end) 85 | { 86 | int found = -1; 87 | int *visited = (int *)malloc(sizeof(int) * graph->num_vertexes); 88 | memset(visited, 0, sizeof(int) * graph->num_vertexes); 89 | 90 | Queue *candidates = queue_new(); 91 | queue_push_tail(candidates, intdup(start)); 92 | 93 | while (queue_is_empty(candidates)) { 94 | int *current = (int *)queue_pop_head(candidates); 95 | visited[*current] = 1; 96 | 97 | if (*current == end) { 98 | free(current); 99 | found = 0; 100 | break; 101 | } 102 | 103 | for (int i = 0; i < graph->num_vertexes; ++i) { 104 | if (adjacency_matrix_connected(graph, *current, i) && !visited[i]) { 105 | queue_push_tail(candidates, intdup(i)); 106 | } 107 | } 108 | free(current); 109 | } 110 | 111 | queue_free(candidates); 112 | free(visited); 113 | return found; 114 | } 115 | 116 | static int adjacency_matrix_dfs_internal(const AdjacencyMatrix *graph, 117 | int start, 118 | int end, 119 | int *visited) 120 | { 121 | if (start == end) { 122 | return 0; 123 | } 124 | 125 | for (int i = 0; i < graph->num_vertexes; ++i) { 126 | if (adjacency_matrix_connected(graph, start, i) && !visited[i]) { 127 | adjacency_matrix_dfs_internal(graph, i, end, visited); 128 | } 129 | } 130 | 131 | return -1; 132 | } 133 | 134 | int adjacency_matrix_dfs(const AdjacencyMatrix *graph, int start, int end) 135 | { 136 | int *visited = (int *)malloc(sizeof(int) * graph->num_vertexes); 137 | memset(visited, 0, sizeof(int) * graph->num_vertexes); 138 | int found = adjacency_matrix_dfs_internal(graph, start, end, visited); 139 | free(visited); 140 | return found; 141 | } 142 | -------------------------------------------------------------------------------- /src/graph.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file graph.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Adjacency Matrix. 7 | * 8 | * @date 2019-07-21 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_GRAPH_H 15 | #define RETHINK_C_GRAPH_H 16 | 17 | typedef enum _GraphType { 18 | UndirectedUnweighted = 0, 19 | UndirectedWeighted = 1, 20 | DirectedUnweighted = 2, 21 | DirectedWeighted = 3 22 | } GraphType; 23 | 24 | /** 25 | * @brief Definition of a @ref AdjacencyMatrix. 26 | * WeightedGraph is alias. 27 | */ 28 | typedef struct _AdjacencyMatrix { 29 | GraphType type; 30 | int num_vertexes; 31 | /** edges pointer point to _data */ 32 | int **edges; 33 | } AdjacencyMatrix, Graph; 34 | 35 | /** 36 | * @brief Allcate a new AdjacencyMatrix. 37 | * 38 | * @param num_vertexes The initiate number of vertexes. 39 | * @return AdjacencyMatrix* The new AdjacencyMatrix if success, otherwise 40 | * NULL. 41 | */ 42 | AdjacencyMatrix *adjacency_matrix_new(GraphType type, int num_vertexes); 43 | 44 | /** 45 | * @brief Delete an AdjacencyMatrix and free back memory. 46 | * 47 | * @param graph The AdjacencyMatrix to delete. 48 | */ 49 | void adjacency_matrix_free(AdjacencyMatrix *graph); 50 | 51 | /** 52 | * @brief Reset all edges of an AdjacencyMatrix to a weight. 53 | * 54 | * @param graph The AdjacencyMatrix Graph. 55 | * @param weight The weight. 56 | */ 57 | void adjacency_matrix_reset(AdjacencyMatrix *graph, int weight); 58 | 59 | /** 60 | * @brief Set an edge from a vertex to another vertex of an AdjacencyMatrix 61 | * to a weight. 62 | * 63 | * @param graph The AdjacencyMatrix Graph. 64 | * @param vertex1 From vertex. 65 | * @param vertex2 To vertex. 66 | * @param edge The weight. 67 | */ 68 | void adjacency_matrix_set(AdjacencyMatrix *graph, 69 | int vertex1, 70 | int vertex2, 71 | int edge); 72 | 73 | /** 74 | * @brief Get weight of an edge from a vertex to another vertex of an 75 | * AdjacencyMatrix. 76 | * 77 | * @param graph The AdjacencyMatrix Graph. 78 | * @param vertex1 From vertex. 79 | * @param vertex2 To vertex. 80 | * @return int The weight. 81 | */ 82 | int adjacency_matrix_get(const AdjacencyMatrix *graph, 83 | int vertex1, 84 | int vertex2); 85 | 86 | /** 87 | * @brief Linke two vertex in a graph. 88 | * 89 | * @param graph Vertex 1. 90 | * @param vertex1 Vertex 2. 91 | * @param vertex2 The AdjacencyMatrix Graph. 92 | * @return int 93 | */ 94 | int adjacency_matrix_link(AdjacencyMatrix *graph, int vertex1, int vertex2); 95 | 96 | /** 97 | * @brief Breadth first searching in a graph. 98 | * 99 | * @param graph The AdjacencyMatrix Graph. 100 | * @param start The start vertex. 101 | * @param end The end vertex. 102 | * @return int 0 if reach the end vertex, -1 if not. 103 | */ 104 | int adjacency_matrix_bfs(const AdjacencyMatrix *graph, int start, int end); 105 | 106 | /** 107 | * @brief Depth first searching in a graph. 108 | * 109 | * @param graph The AdjacencyMatrix Graph. 110 | * @param start The start vertex. 111 | * @param end The end vertex. 112 | * @return int 0 if reach the end vertex, -1 if not. 113 | */ 114 | int adjacency_matrix_dfs(const AdjacencyMatrix *graph, int start, int end); 115 | 116 | #endif /* #ifndef RETHINK_C_GRAPH_H */ 117 | -------------------------------------------------------------------------------- /src/hash.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hash.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to hash.h 5 | * @date 2019-07-26 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "hash.h" 12 | #include "def.h" 13 | #include "text.h" 14 | 15 | unsigned int hash_char(void *pointer) 16 | { 17 | return *(unsigned char *)pointer; 18 | } 19 | 20 | unsigned int hash_int(void *pointer) 21 | { 22 | return *(unsigned int *)pointer; 23 | } 24 | 25 | unsigned int hash_object(void *object) 26 | { 27 | return (unsigned int)object; 28 | } 29 | 30 | /** 31 | * @brief BKDR hash algorithm. 32 | * 33 | * Introduced by Brian Kernighan and Dennis Ritchie in *The C Programming 34 | * Language* 35 | * 36 | * @param string Input string. 37 | * @return unsigned int Return hash. 38 | */ 39 | unsigned int hash_string(void *string) 40 | { 41 | unsigned int hash = 0; 42 | char *p = (char *)string; 43 | while (*p != '\0') { 44 | /** factor 131 also could be 31、131、1313、13131、131313 ... */ 45 | hash = hash * 131 + (*p); 46 | ++p; 47 | } 48 | return hash; 49 | } 50 | 51 | /** 52 | * @brief Same as string hash. 53 | * 54 | * @param text Input text. 55 | * @return unsigned int Return hash. 56 | */ 57 | unsigned int hash_text(void *text) 58 | { 59 | unsigned int hash = 0; 60 | for (unsigned int i =0; i < text_length(text); ++i) { 61 | /** factor 131 also could be 31、131、1313、13131、131313 ... */ 62 | hash = hash * 131 + text_char_at(text, i); 63 | } 64 | return hash; 65 | } 66 | -------------------------------------------------------------------------------- /src/hash.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hash.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Hash functions. 7 | * 8 | * @date 2019-07-26 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_HASH_H 15 | #define RETHINK_C_HASH_H 16 | 17 | /** 18 | * @brief Calculate a char's hash. 19 | * 20 | * @param pointer The char address. 21 | * @return unsigned int The hash. 22 | */ 23 | unsigned int hash_char(void *pointer); 24 | 25 | /** 26 | * @brief Calculate a integer's hash. 27 | * 28 | * @param pointer The integer address. 29 | * @return unsigned int The hash. 30 | */ 31 | unsigned int hash_int(void *pointer); 32 | 33 | /** 34 | * @brief Calculate a pointer of object's hash. 35 | * 36 | * @param object The pointer of object. 37 | * @return unsigned int The hash. 38 | */ 39 | unsigned int hash_object(void *object); 40 | 41 | /** 42 | * @brief Calculate a string's hash. 43 | * 44 | * @param string The string. 45 | * @return unsigned int The hash. 46 | */ 47 | unsigned int hash_string(void *string); 48 | 49 | /** 50 | * @brief Calculate a text's hash. 51 | * 52 | * @param text The text. 53 | * @return unsigned int The hash. 54 | */ 55 | unsigned int hash_text(void *text); 56 | 57 | #endif /* #ifndef RETHINK_C_HASH_H */ 58 | -------------------------------------------------------------------------------- /src/hash_table.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hash_table.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Hash table. 7 | * 8 | * @date 2019-07-25 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_HASH_TABLE_H 15 | #define RETHINK_C_HASH_TABLE_H 16 | 17 | /** 18 | * @brief The type of a key to be stored in a @ref HashTable. 19 | * (void *) can be changed to int, char *, or other types if needed. 20 | */ 21 | typedef void *HashTableKey; 22 | 23 | /** 24 | * @brief The type of a key to be stored in a @ref HashTable. 25 | * (void *) can be changed to int, char *, or other types if needed. 26 | */ 27 | typedef void *HashTableValue; 28 | 29 | /** 30 | * A null @ref HashTableValue. 31 | */ 32 | #define HASH_TABLE_VALUE_NULL ((void *)0) 33 | 34 | /** 35 | * @brief Definition of a @ref HashTableEntity. 36 | * 37 | */ 38 | typedef struct _HashTableEntity { 39 | HashTableKey key; 40 | HashTableValue value; 41 | struct _HashTableEntity *next; 42 | } HashTableEntity; 43 | 44 | typedef unsigned int (*HashTableHashFunc)(HashTableKey key); 45 | typedef int (*HashTableEqualFunc)(HashTableKey key1, HashTableKey key2); 46 | 47 | typedef void (*HashTableFreeKeyFunc)(HashTableKey key); 48 | typedef void (*HashTableFreeValueFunc)(HashTableValue value); 49 | 50 | /** 51 | * @brief Definition of a @ref HashTable. 52 | * 53 | */ 54 | typedef struct _HashTable HashTable; 55 | 56 | /** 57 | * @brief Allcate a new HashTable. 58 | * 59 | * @param hash_func The hash function. 60 | * @param equal_func The equal function that compare keys. 61 | * @param free_key_func The free function that free keys. 62 | * @param free_value_func The free function that free values. 63 | * @return HashTable* The new HashTable if success, otherwise NULL. 64 | */ 65 | HashTable *hash_table_new(HashTableHashFunc hash_func, 66 | HashTableEqualFunc equal_func, 67 | HashTableFreeKeyFunc free_key_func, 68 | HashTableFreeKeyFunc free_value_func); 69 | 70 | /** 71 | * @brief Delete a HashTable and free back memory. 72 | * 73 | * @param hash_table The HashTable to delete. 74 | */ 75 | void hash_table_free(HashTable *hash_table); 76 | 77 | /** 78 | * @brief Insert a key/value pair to a HashTable. 79 | * 80 | * @param hash_table The HashTable. 81 | * @param key The key. 82 | * @param value The value. 83 | * @return int 0 if success. 84 | */ 85 | int hash_table_insert(HashTable *hash_table, 86 | HashTableKey key, 87 | HashTableValue value); 88 | 89 | /** 90 | * @brief Get the value by a key from a HashTable. 91 | * 92 | * @param hash_table The HashTable. 93 | * @param key The key. 94 | * @return HashTableValue The value. 95 | */ 96 | HashTableValue hash_table_get(HashTable *hash_table, HashTableKey key); 97 | 98 | /** 99 | * @brief Set a value by a key to a HashTable, insert a key/value pair if key 100 | * not exists in HashTable. 101 | * 102 | * @param hash_table The HashTable. 103 | * @param key The key. 104 | * @param value The value. 105 | * @return int 0 if success. 106 | */ 107 | int hash_table_set(HashTable *hash_table, 108 | HashTableKey key, 109 | HashTableValue value); 110 | 111 | /** 112 | * @brief Delete an entity by a key from a HashTable. 113 | * 114 | * @param hash_table The HashTable. 115 | * @param key The key. 116 | * @return int 0 if success. 117 | */ 118 | int hash_table_delete(HashTable *hash_table, HashTableKey key); 119 | 120 | /** 121 | * @brief Get the size of a HashTable. 122 | * 123 | * @param hash_table The HashTable. 124 | * @return unsigned int The size of HashTable. 125 | */ 126 | unsigned int hash_table_size(const HashTable *hash_table); 127 | 128 | /** 129 | * @brief Get the first entity of a HashTable. 130 | * 131 | * @param hash_table The HashTable. 132 | * @return HashTableEntity* The first entity. 133 | */ 134 | HashTableEntity *hash_table_first_entity(const HashTable *hash_table); 135 | 136 | /** 137 | * @brief Get the last entity of a HashTable. 138 | * 139 | * @param hash_table The HashTable. 140 | * @return HashTableEntity* The last entity. 141 | */ 142 | HashTableEntity *hash_table_last_entity(const HashTable *hash_table); 143 | 144 | /** 145 | * @brief Get the next entity of a HashTable by given entity. 146 | * 147 | * @param hash_table The HashTable. 148 | * @param entity The given entity. 149 | * @return HashTableEntity* The next entity. 150 | */ 151 | HashTableEntity *hash_table_next_entity(const HashTable *hash_table, 152 | HashTableEntity *entity); 153 | 154 | /** 155 | * @brief Get the previous entity of a HashTable by given entity. 156 | * 157 | * @param hash_table The HashTable. 158 | * @param entity The given entity. 159 | * @return HashTableEntity* The previous entity. 160 | */ 161 | HashTableEntity *hash_table_prev_entity(const HashTable *hash_table, 162 | HashTableEntity *entity); 163 | 164 | #endif /* #ifndef RETHINK_C_HASH_TABLE_H */ 165 | -------------------------------------------------------------------------------- /src/heap.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file heap.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to heap.h 5 | * @date 2019-07-31 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "heap.h" 12 | #include "def.h" 13 | #include 14 | #include 15 | #include 16 | 17 | Heap *heap_new(HeapType type, 18 | HeapCompareFunc compare_func, 19 | HeapFreeValueFunc free_value_func) 20 | { 21 | Heap *heap = (Heap *)malloc(sizeof(Heap)); 22 | heap->type = type; 23 | heap->compare_func = compare_func; 24 | heap->free_value_func = free_value_func; 25 | heap->num_data = 0; 26 | 27 | heap->_allocated = 16; 28 | heap->data = (HeapValue *)malloc(sizeof(HeapValue) * heap->_allocated); 29 | 30 | return heap; 31 | } 32 | 33 | void heap_free(Heap *heap) 34 | { 35 | // free all data 36 | for (unsigned int i = 0; i < heap->num_data; ++i) { 37 | if (heap->free_value_func && heap->data[i]) { 38 | heap->free_value_func(heap->data[i]); 39 | } 40 | } 41 | free(heap->data); 42 | free(heap); 43 | } 44 | 45 | static int heap_enlarge(Heap *heap) 46 | { 47 | HeapValue *data; 48 | unsigned int newsize; 49 | 50 | newsize = heap->_allocated * 2; 51 | data = realloc(heap->data, sizeof(HeapValue) * newsize); 52 | 53 | if (data == NULL) { 54 | return -1; 55 | } else { 56 | heap->data = data; 57 | heap->_allocated = newsize; 58 | return 0; 59 | } 60 | } 61 | 62 | static inline int heap_is_correct_order(Heap *heap, int front, int back) 63 | { 64 | if (heap->type == MIN_HEAP) { 65 | return heap->compare_func(heap->data[front], heap->data[back]) <= 0; 66 | } else { 67 | return heap->compare_func(heap->data[front], heap->data[back]) >= 0; 68 | } 69 | } 70 | 71 | static inline void heap_swap(Heap *heap, int index1, int index2) 72 | { 73 | HeapValue tmp = heap->data[index1]; 74 | heap->data[index1] = heap->data[index2]; 75 | heap->data[index2] = tmp; 76 | } 77 | 78 | /** 79 | * @brief heapify bottom-up 80 | * 81 | * @param heap 82 | * 83 | * heapify swap will go through 11 -> 5 -> 2 -> 0, until done. 84 | * 85 | * 0[#] 86 | * / \ 87 | * 1 2[#] 88 | * / \ / \ 89 | * 3 4 5[#] 6 90 | * / \ / \ / 91 | * 7 8 9 10 11[*] 92 | * 93 | */ 94 | static inline void heap_insert_heapify(Heap *heap) 95 | { 96 | int index = heap->num_data - 1; 97 | while (index >= 0 && !heap_is_correct_order(heap, (index - 1) / 2, index)) { 98 | heap_swap(heap, (index - 1) / 2, index); 99 | if (index == 0) 100 | break; 101 | index = (index - 1) / 2; 102 | } 103 | } 104 | 105 | int heap_insert(Heap *heap, HeapValue value) 106 | { 107 | if (heap->num_data >= heap->_allocated) { 108 | heap_enlarge(heap); 109 | } 110 | 111 | heap->data[heap->num_data] = value; 112 | ++(heap->num_data); 113 | 114 | heap_insert_heapify(heap); 115 | return 0; 116 | } 117 | 118 | static inline int heap_pop_select_index(Heap *heap, int index) 119 | { 120 | if (index >= heap->num_data) { 121 | return -1; 122 | } else if (index + 1 >= heap->num_data) { 123 | return index; 124 | } else { 125 | int cmp = heap->compare_func(heap->data[index], heap->data[index + 1]); 126 | if (heap->type == MIN_HEAP) { 127 | return cmp < 0 ? index : (index + 1); 128 | } else { 129 | return cmp > 0 ? index : (index + 1); 130 | } 131 | } 132 | } 133 | 134 | /** 135 | * @brief heapify top-down 136 | * 137 | * @param heap 138 | * 139 | * heapfiy swap will go through: 140 | * 0 -> MAX[1, 2] 141 | * if 1 -> MAX[3,4] 142 | * if 3 -> MAX[7,8], until done. 143 | * 144 | * 0[*] 145 | * / \ 146 | * 1[#] 2[#] 147 | * / \ / \ 148 | * 3[#] 4[#] 5 6 149 | * / \ 150 | * 7[#] 8[#] 151 | */ 152 | static inline void heap_pop_heapify(Heap *heap) 153 | { 154 | int index = 0; 155 | while (1) { 156 | int select = heap_pop_select_index(heap, index * 2 + 1); 157 | if (select < 0) { 158 | break; 159 | } 160 | 161 | if (!heap_is_correct_order(heap, index, select)) { 162 | heap_swap(heap, index, select); 163 | index = select; 164 | } else { 165 | break; 166 | } 167 | } 168 | } 169 | 170 | HeapValue heap_pop(Heap *heap) 171 | { 172 | if (heap->num_data <= 0) { 173 | return HEAP_VALUE_NULL; 174 | } 175 | 176 | HeapValue top = heap->data[0]; 177 | heap->data[0] = heap->data[heap->num_data - 1]; 178 | --(heap->num_data); 179 | 180 | heap_pop_heapify(heap); 181 | return top; 182 | } 183 | -------------------------------------------------------------------------------- /src/heap.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file heap.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Binary Heap. 7 | * 8 | * @date 2019-07-31 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_HEAP_H 15 | #define RETHINK_C_HEAP_H 16 | 17 | /** 18 | * @brief The type of a key to be stored in a @ref Heap. 19 | * (void *) can be changed to int, char *, or other types if needed. 20 | */ 21 | typedef void *HeapValue; 22 | 23 | /** 24 | * A null @ref HeapValue. 25 | */ 26 | #define HEAP_VALUE_NULL ((void *)0) 27 | 28 | typedef int (*HeapCompareFunc)(HeapValue data1, HeapValue data2); 29 | typedef void (*HeapFreeValueFunc)(HeapValue value); 30 | 31 | typedef enum { 32 | /** Minimum heap. */ 33 | MIN_HEAP = 0, 34 | /** Maximum heap. */ 35 | MAX_HEAP = 1 36 | } HeapType; 37 | 38 | /** 39 | * @brief Definition of a @ref Heap. 40 | * 41 | */ 42 | typedef struct _Heap { 43 | /** Values Array of the @ref Heap. */ 44 | HeapValue *data; 45 | /** Compare two entity value when do searching in Heap. */ 46 | HeapCompareFunc compare_func; 47 | HeapFreeValueFunc free_value_func; 48 | 49 | HeapType type; 50 | /** The number of entitys of the @ref Heap. */ 51 | unsigned int num_data; 52 | unsigned int _allocated; 53 | } Heap; 54 | 55 | /** 56 | * @brief Allcate a new Heap. 57 | * 58 | * @param type MIN_HEAP or MAX_HEAP. 59 | * @param compare_func Compare two entity value when do searching in Heap. 60 | * @param free_value_func Free value callback function. 61 | * @return Heap* The new Heap if success, otherwise return NULL. 62 | */ 63 | Heap *heap_new(HeapType type, 64 | HeapCompareFunc compare_func, 65 | HeapFreeValueFunc free_value_func); 66 | 67 | /** 68 | * @brief Delete a Heap and free back memory. 69 | * 70 | * @param heap The Heap to delete. 71 | */ 72 | void heap_free(Heap *heap); 73 | 74 | /** 75 | * @brief Insert a HeapValue to a Heap. 76 | * 77 | * @param heap The Heap. 78 | * @param data The value to insert. 79 | * @return HeapEntity* The new inserted HeapEntity if success, 80 | * otherwise return NULL. 81 | */ 82 | int heap_insert(Heap *heap, HeapValue data); 83 | 84 | /** 85 | * @brief Pop the top HeapValue from a Heap. 86 | * 87 | * @param heap The Heap. 88 | * @return HeapValue The first HeapValue if success, 89 | * otherwise HEAP_VALUE_NULL. 90 | */ 91 | HeapValue heap_pop(Heap *heap); 92 | 93 | #endif /* #ifndef RETHINK_C_HEAP_H */ 94 | -------------------------------------------------------------------------------- /src/huffman.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file huffman.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Huffman Tree. 7 | * 8 | * Use huffman_tree_from to generate a new Huffman Tree from a Minimum HEAP. 9 | * 10 | * Use huffman_encode or huffman_decode to encode or decode Text. 11 | * 12 | * Use huffman_tree_deflate or huffman_tree_inflate to store or restor itself. 13 | * 14 | * @date 2019-08-21 15 | * 16 | * @copyright Copyright (c) 2019, hutusi.com 17 | * 18 | */ 19 | 20 | #ifndef RETHINK_C_HUFFMAN_H 21 | #define RETHINK_C_HUFFMAN_H 22 | 23 | #include "bitmap.h" 24 | #include "heap.h" 25 | #include "text.h" 26 | 27 | /** 28 | * @brief Definition of a @ref HuffmanNode. 29 | * 30 | */ 31 | typedef struct _HuffmanNode { 32 | char value; 33 | unsigned int weight; 34 | struct _HuffmanNode *left; 35 | struct _HuffmanNode *right; 36 | } HuffmanNode; 37 | 38 | /** 39 | * @brief Definition of a @ref HuffmanTree. 40 | * 41 | */ 42 | typedef struct _HuffmanTree { 43 | HuffmanNode *root; 44 | } HuffmanTree; 45 | 46 | /** 47 | * @brief Malloc a new Huffman Heap. 48 | * 49 | * Huffman Heap is a Minimum Heap. 50 | * 51 | * @return Heap* The Huffman Heap. 52 | */ 53 | Heap *huffman_heap_new(); 54 | 55 | /** 56 | * @brief Generate a new Huffman Heap from a Text. 57 | * 58 | * @param text The Text. 59 | * @return Heap* The Huffman Heap. 60 | */ 61 | Heap *huffman_heap_from(const Text *text); 62 | 63 | /** 64 | * @brief Generate a new Huffman Heap from a string. 65 | * 66 | * @param string The string. 67 | * @param size The size of the string. 68 | * @return Heap* The Huffman Heap. 69 | */ 70 | Heap *huffman_heap_from_string(const char *string, unsigned int size); 71 | 72 | /** 73 | * @brief Delete a Huffman Heap and free back memory. 74 | * 75 | * Mind: It's unnecessary to free heap manually, free_heap will be called in 76 | * huffman_tree_from(heap) function. 77 | * 78 | * @param heap The Huffman Heap. 79 | */ 80 | void huffman_heap_free(Heap *heap); 81 | 82 | /** 83 | * @brief Insert a value and it's weight to a Huffman Heap. 84 | * 85 | * @param tree The heap. 86 | * @param value The value. 87 | * @param weight The weight. 88 | * @return int 0 if success. 89 | */ 90 | int huffman_heap_insert(Heap *heap, char value, unsigned int weight); 91 | 92 | /** 93 | * @brief Allocate a new Huffman Tree. 94 | * 95 | * @return HuffmanTree* The new Huffman Tree. 96 | */ 97 | HuffmanTree *huffman_tree_new(); 98 | 99 | /** 100 | * @brief Generate a new Huffman Tree by a Huffman Heap. 101 | * 102 | * Mind: this function will free the input heap. 103 | * 104 | * @param heap The Huffman Heap. 105 | * @return HuffmanTree* The Huffman Tree. 106 | */ 107 | HuffmanTree *huffman_tree_from(Heap *heap); 108 | 109 | /** 110 | * @brief Delete a Huffman Tree and free back memory. 111 | * 112 | * @param tree The Huffman Tree. 113 | */ 114 | void huffman_tree_free(HuffmanTree *tree); 115 | 116 | /** 117 | * @brief Encode a Text to a sequence of BitMap by a Huffman Tree coding. 118 | * 119 | * @param tree The Huffman Tree coding. 120 | * @param text The Text. 121 | * @return BitMap* The BitMap. 122 | */ 123 | BitMap *huffman_encode(const HuffmanTree *tree, const Text *text); 124 | 125 | /** 126 | * @brief Encode a string to a sequence of BitMap by a Huffman Tree coding. 127 | * 128 | * @param tree The Huffman Tree coding. 129 | * @param string The string. 130 | * @param size The size of the string. 131 | * @return BitMap* The BitMap. 132 | */ 133 | BitMap *huffman_encode_string(const HuffmanTree *tree, 134 | const char *string, 135 | unsigned int size); 136 | 137 | /** 138 | * @brief Decode a sequence of BitMap to a Text by a Huffman Tree coding. 139 | * 140 | * @param tree The Huffman Tree coding. 141 | * @param bitmap The BitMap. 142 | * @return Text* The Text. 143 | */ 144 | Text *huffman_decode(const HuffmanTree *tree, const BitMap *bitmap); 145 | 146 | /** 147 | * @brief Deflate a Huffman Tree to a BitMap for storing with few storage. 148 | * 149 | * @param tree The Huffman Tree. 150 | * @return BitMap* The BitMap. 151 | */ 152 | BitMap *huffman_tree_deflate(const HuffmanTree *tree); 153 | 154 | /** 155 | * @brief Inflate a BitMap to a Huffman Tree. (Restore.) 156 | * 157 | * @param bitmap The BitMap. 158 | * @return HuffmanTree* The Huffman Tree. 159 | */ 160 | HuffmanTree *huffman_tree_inflate(const BitMap *bitmap); 161 | 162 | /** 163 | * @brief Judge two Huffman Tree's equality. 164 | * 165 | * @param tree1 One Huffman Tree. 166 | * @param tree2 The other Huffman Tree. 167 | * @return int 1 if equal, 0 if not. 168 | */ 169 | int huffman_tree_equal(const HuffmanTree *tree1, const HuffmanTree *tree2); 170 | 171 | #endif /* #ifndef RETHINK_C_HUFFMAN_H */ 172 | -------------------------------------------------------------------------------- /src/kmp.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file kmp.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to kmp.h 5 | * @date 2019-08-07 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "kmp.h" 12 | #include "def.h" 13 | #include 14 | #include 15 | 16 | /** 17 | * @brief Calculate next array 18 | * 19 | * calucate the max matched suffix substring' length. 20 | * 21 | * string: abcdabd 22 | * 23 | * a 0 24 | * ab 0 25 | * abc 0 26 | * abcd 0 27 | * abcda 1 28 | * abcdab 2 29 | * abcdabd 0 30 | * 31 | * string: ababa 32 | * 33 | * a 0 34 | * ab 0 35 | * aba 1 36 | * abab 2 37 | * ababa 3 38 | * 39 | * @param string 40 | * @param len 41 | * @return STATIC* kmp_calculate_next 42 | */ 43 | STATIC int *kmp_calculate_next(const char *string, int len) 44 | { 45 | int *next = (int *)calloc(len, sizeof(int)); 46 | next[0] = 0; 47 | int k = 0; 48 | for (int i = 1; i < len; ++i) { 49 | while (k > 0 && string[k] != string[i]) { 50 | k = next[k]; 51 | } 52 | 53 | if (string[k] == string[i]) { 54 | ++k; 55 | } 56 | 57 | next[i] = k; 58 | } 59 | 60 | return next; 61 | } 62 | 63 | /** 64 | * @brief KMP algorithm 65 | * 66 | * text: bbcabcdababcdabcdabde 67 | * pattern: abcdabd 68 | * 69 | * ! 70 | * bbcabcdababcdabcdabde 71 | * abcdabd 72 | * 73 | * step 1 -> 74 | * ! 75 | * bbcabcdababcdabcdabde 76 | * abcdabd 77 | * 78 | * step 1 -> 79 | * ! 80 | * bbcabcdababcdabcdabde 81 | * abcdabd 82 | * 83 | * step 1 -> 84 | * ! 85 | * bbcabcdababcdabcdabde 86 | * abcdabd 87 | * 88 | * step 1 -> ... until find failure charactor 'a'-'d' 89 | * ! * 90 | * bbcabcdababcdabcdabde 91 | * abcdabd 92 | * 93 | * step next[5] = 4, then step 1... until find failure charactor 'a'-'c' 94 | * ! * 95 | * bbcabcdababcdabcdabde 96 | * abcdabd 97 | * 98 | * step next[3] = 2 ... 99 | * ! 100 | * bbcabcdababcdabcdabde 101 | * abcdabd 102 | * 103 | * ...... 104 | * 105 | * @param text 106 | * @param pattern 107 | * @return int 108 | */ 109 | int kmp_text_match(const char *text, 110 | unsigned int text_len, 111 | const char *pattern, 112 | unsigned int pat_len) 113 | { 114 | int *next = kmp_calculate_next(pattern, pat_len); 115 | int index = -1; 116 | int j = 0; 117 | 118 | for (int i = 0; i < text_len; ++i) { 119 | if (text[i] == pattern[j]) { 120 | ++j; 121 | } else { 122 | if (j > 0) { 123 | /** C allowed n[-1] */ 124 | j = next[j - 1]; 125 | --i; 126 | } 127 | } 128 | 129 | if (j >= pat_len) { 130 | index = i + 1 - pat_len; 131 | break; 132 | } 133 | } 134 | 135 | free(next); 136 | return index; 137 | } 138 | 139 | int kmp_string_match(const char *text, const char *pattern) 140 | { 141 | return kmp_text_match(text, strlen(text), pattern, strlen(pattern)); 142 | } 143 | -------------------------------------------------------------------------------- /src/kmp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file kmp.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief KMP (Knuth-Morris-Pratt) algorithm. 7 | * 8 | * @date 2019-08-07 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_KMP_H 15 | #define RETHINK_C_KMP_H 16 | 17 | /** 18 | * @brief KMP algorithm to find the match substring. 19 | * 20 | * @param text The text string. 21 | * @param text_len The length of text. 22 | * @param pattern The pattern string. 23 | * @param pat_len The length of pattern string. 24 | * @return int The first match index, -1 if no match. 25 | */ 26 | int kmp_text_match(const char *text, 27 | unsigned int text_len, 28 | const char *pattern, 29 | unsigned int pat_len); 30 | 31 | /** 32 | * @brief KMP algorithm to find the match substring. 33 | * 34 | * @param text The text string. 35 | * @param pattern The pattern string. 36 | * @return int The first match index, -1 if no match. 37 | */ 38 | int kmp_string_match(const char *text, const char *pattern); 39 | 40 | #endif /* #ifndef RETHINK_C_KMP_H */ 41 | -------------------------------------------------------------------------------- /src/list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file list.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Double Linked List. 7 | * 8 | * @date 2019-07-20 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_LIST_H 15 | #define RETHINK_C_LIST_H 16 | 17 | /** 18 | * @brief The type of a value to be stored in a @ref List. 19 | * (void *) can be changed to int, long, or other types if needed. 20 | */ 21 | typedef void *ListValue; 22 | 23 | /** 24 | * A null @ref ListValue. 25 | */ 26 | #define LIST_NULL ((void *)0) 27 | 28 | /** 29 | * @brief Definition of a @ref ListNode. 30 | * 31 | */ 32 | typedef struct _ListNode { 33 | ListValue data; 34 | struct _ListNode *prev; 35 | struct _ListNode *next; 36 | } ListNode; 37 | 38 | /** 39 | * @brief Definition of a @ref List. 40 | * 41 | */ 42 | typedef struct _List { 43 | struct _ListNode *head; 44 | struct _ListNode *tail; 45 | unsigned int length; 46 | } List; 47 | 48 | /** 49 | * @brief Allcate a new List. 50 | * 51 | * @return List* The new List if success, otherwise return NULL. 52 | */ 53 | List *list_new(); 54 | 55 | /** 56 | * @brief Delete a List and free back memory. 57 | * 58 | * @param list The list to delete. 59 | */ 60 | void list_free(List *list); 61 | 62 | /** 63 | * @brief Prepend a value to the beginning of a List. 64 | * 65 | * @param list The list. 66 | * @param data The value to prepend. 67 | * @return int 0 if success. 68 | */ 69 | int list_prepend(List *list, ListValue data); 70 | 71 | /** 72 | * @brief Append a value to the end of a List. 73 | * 74 | * @param list The list. 75 | * @param data The value to append. 76 | * @return int 0 if success. 77 | */ 78 | int list_append(List *list, ListValue data); 79 | 80 | /** 81 | * @brief Get the nth node of a List. 82 | * 83 | * @param list The list. 84 | * @param n The nth index. 85 | * @return ListNode* The nth node if success, otherwise return NULL. 86 | */ 87 | ListNode *list_nth_node(List *list, unsigned int n); 88 | 89 | /** 90 | * @brief Get the nth node value of a List. 91 | * 92 | * @param list The list. 93 | * @param n The nth index. 94 | * @return ListNode* The nth node value if success, otherwise return LIST_NULL. 95 | */ 96 | ListValue list_nth_data(List *list, unsigned int n); 97 | 98 | /** 99 | * @brief Convert an List to an array. 100 | * 101 | * The List still exists! 102 | * 103 | * @param list The List. 104 | * @return ListValue* The ListValue array if success, otherwise return NULL. 105 | */ 106 | ListValue *list_to_array(List *list); 107 | 108 | typedef int (*ListCompareFunc)(ListValue value1, ListValue value2); 109 | typedef int (*ListEqualFunc)(ListValue value1, ListValue value2); 110 | 111 | /** 112 | * @brief Find a ListNode in a List. 113 | * 114 | * @param list The List. 115 | * @param node The ListNode to lookup. 116 | * @return ListNode* The ListNode if success, otherwise return NULL. 117 | */ 118 | ListNode *list_find_node(List *list, ListNode *node); 119 | 120 | /** 121 | * @brief Find the ListNode of a value in a List. 122 | * 123 | * @param list The List. 124 | * @param data The ListNode's value to lookup. 125 | * @return ListNode* The ListNode if success, otherwise return NULL. 126 | */ 127 | ListNode *list_find_data(List *list, ListEqualFunc callback, ListValue data); 128 | 129 | /** 130 | * @brief Remove a ListNode from a List. 131 | * 132 | * The ListNode still exists, not be freed. 133 | * 134 | * @param list The List. 135 | * @param node The ListNode. 136 | * @return ListNode* The ListNode if success, otherwise return NULL. 137 | */ 138 | ListNode *list_remove_node(List *list, ListNode *node); 139 | 140 | /** 141 | * @brief Remove a ListNode of a value from a List. 142 | * 143 | * The ListNode is be deleted and freed back memory. 144 | * 145 | * @param list The List. 146 | * @param callback The equal callback function. 147 | * @param data The ListNode value. 148 | * @return int 0 if success. 149 | */ 150 | int list_remove_data(List *list, ListEqualFunc callback, ListValue data); 151 | 152 | /** 153 | * @brief Sort a List. 154 | * 155 | * @param list The List. 156 | * @param compare_func The compare function to callback. 157 | * @return int 0 if success. 158 | */ 159 | int list_sort(List *list, ListCompareFunc compare_func); 160 | 161 | #endif /* #ifndef RETHINK_C_LIST_H */ 162 | -------------------------------------------------------------------------------- /src/matrix.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file matrix.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to matrix.h 5 | * @date 2019-07-20 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "matrix.h" 12 | #include "def.h" 13 | #include 14 | #include 15 | #include 16 | 17 | Matrix *matrix_new(unsigned int num_dimensions, ...) 18 | { 19 | Matrix *matrix = (Matrix *)malloc(sizeof(Matrix)); 20 | matrix->dimensions = 21 | (unsigned int *)malloc(sizeof(unsigned int) * num_dimensions); 22 | 23 | matrix->num_dimensions = num_dimensions; 24 | 25 | /** todo: ensure matrix->num_data should not greater than MAX_UINT! */ 26 | matrix->num_data = 1; 27 | 28 | va_list vl; 29 | va_start(vl, num_dimensions); 30 | for (int i = 0; i < num_dimensions; ++i) { 31 | matrix->dimensions[i] = va_arg(vl, unsigned int); 32 | matrix->num_data *= matrix->dimensions[i]; 33 | } 34 | va_end(vl); 35 | 36 | matrix->offsets = 37 | (unsigned int *)malloc(sizeof(unsigned int) * num_dimensions); 38 | unsigned int offsets = 1; // the last dimension offset * 1 39 | for (int i = num_dimensions - 1; i >= 0; --i) { 40 | matrix->offsets[i] = offsets; 41 | offsets *= matrix->dimensions[i]; 42 | } 43 | 44 | matrix->data = 45 | (MatrixValue *)malloc(sizeof(MatrixValue) * matrix->num_data); 46 | if (matrix->data == NULL) { 47 | free(matrix->dimensions); 48 | free(matrix->offsets); 49 | free(matrix); 50 | return NULL; 51 | } 52 | 53 | return matrix; 54 | } 55 | 56 | void matrix_free(Matrix *matrix) 57 | { 58 | free(matrix->dimensions); 59 | free(matrix->offsets); 60 | free(matrix->data); 61 | free(matrix); 62 | } 63 | 64 | void matrix_reset(Matrix *matrix) 65 | { 66 | memset(matrix->data, 0, matrix->num_data * sizeof(MatrixValue)); 67 | } 68 | 69 | void matrix_set(Matrix *matrix, 70 | MatrixValue value, 71 | unsigned int num_dimensions, 72 | ...) 73 | { 74 | unsigned int offset = 0; 75 | 76 | va_list vl; 77 | va_start(vl, num_dimensions); 78 | for (int i = 0; i < num_dimensions; ++i) { 79 | unsigned demension_index = va_arg(vl, unsigned int); 80 | offset += demension_index * matrix->offsets[i]; 81 | } 82 | va_end(vl); 83 | 84 | matrix->data[offset] = value; 85 | } 86 | 87 | MatrixValue matrix_get(const Matrix *matrix, unsigned int num_dimensions, ...) 88 | { 89 | unsigned int offset = 0; 90 | 91 | va_list vl; 92 | va_start(vl, num_dimensions); 93 | for (int i = 0; i < num_dimensions; ++i) { 94 | unsigned demension_index = va_arg(vl, unsigned int); 95 | offset += demension_index * matrix->offsets[i]; 96 | } 97 | va_end(vl); 98 | 99 | return matrix->data[offset]; 100 | } 101 | -------------------------------------------------------------------------------- /src/matrix.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file matrix.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Multi-dimensional Matrix. 7 | * 8 | * @date 2019-07-20 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_MATRIX_H 15 | #define RETHINK_C_MATRIX_H 16 | 17 | /** 18 | * @brief The type of a value to be stored in a @ref Matrix. 19 | * (void *) can be changed to int, long, or other types if needed. 20 | */ 21 | typedef void *MatrixValue; 22 | 23 | /** 24 | * @brief Definition of a @ref Matrix. 25 | * 26 | */ 27 | typedef struct _Matrix { 28 | /** Data values in the Matrix. */ 29 | MatrixValue *data; 30 | /** The total number of data, should equals the multiple product 31 | * of all dimensions' length. */ 32 | unsigned int num_data; 33 | 34 | /** The length array of all dimensions. */ 35 | unsigned int *dimensions; 36 | /** The offsets array of all dimensions. 37 | * For example, a 3-dimensional matrix m[3][5][4]: 38 | * All 3 dimensions' offsets will be 5*4, 4, 1, 39 | * m[2][3][1] will be stored in data[2*5*4 + 3*4 + 1*1]. 40 | */ 41 | unsigned int *offsets; 42 | /** Numbers of dimensions. */ 43 | unsigned int num_dimensions; 44 | } Matrix; 45 | 46 | /** 47 | * @brief Allcate a new Matrix. 48 | * 49 | * @param num_dimensions The number of dimensions. 50 | * @param ... The length of each dimensions. 51 | * @return Matrix* The new Matrix if success, otherwise NULL. 52 | */ 53 | Matrix *matrix_new(unsigned int num_dimensions, ...); 54 | 55 | /** 56 | * @brief Delete a Matrix and free back memory. 57 | * 58 | * @param matrix The Matrix to delete. 59 | */ 60 | void matrix_free(Matrix *matrix); 61 | 62 | /** 63 | * @brief Set all entities' value of a Matrix to 0. 64 | * 65 | * @param matrix The Matrix. 66 | */ 67 | void matrix_reset(Matrix *matrix); 68 | 69 | /** 70 | * @brief Set a value to an entity of a Matrix. 71 | * 72 | * @param matrix The Matrix. 73 | * @param value The value. 74 | * @param num_dimensions The dimensions of the Matrix. 75 | * @param ... The index of each dimensions. 76 | */ 77 | void matrix_set(Matrix *matrix, 78 | MatrixValue value, 79 | unsigned int num_dimensions, 80 | ...); 81 | 82 | /** 83 | * @brief Get a value to an entity of a Matrix. 84 | * 85 | * @param matrix The Matrix. 86 | * @param num_dimensions The dimensions of the Matrix. 87 | * @param ... The index of each dimensions. 88 | * @return MatrixValue The value if success. 89 | */ 90 | MatrixValue matrix_get(const Matrix *matrix, unsigned int num_dimensions, ...); 91 | 92 | #endif /* #ifndef RETHINK_C_MATRIX_H */ 93 | -------------------------------------------------------------------------------- /src/prime.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file prime.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to prime.h 5 | * @date 2019-07-21 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "prime.h" 12 | #include "def.h" 13 | #include 14 | 15 | static inline unsigned int bit_map_index_to_number(unsigned int n) 16 | { 17 | /** from 3: [0] => 3, [1] => 5 */ 18 | return n * 2 + 3; 19 | } 20 | 21 | /** para number must be odd number */ 22 | static inline unsigned int bit_map_number_to_index(unsigned int number) 23 | { 24 | /** from 3: [0] => 3, [1] => 5 */ 25 | return (number - 3) / 2; 26 | } 27 | 28 | BitMap *prime_number_sieve(unsigned int max_number) 29 | { 30 | /** prime number should be odd number (except 2), 31 | * so we only need sieve half of the number. 32 | * 1 is no need to sieve either. 33 | */ 34 | unsigned int sieve_size = (max_number - 1) / 2; 35 | BitMap *sieve = bitmap_new(sieve_size); 36 | bitmap_set_all(sieve); 37 | 38 | /** only need loop to sqrt(max_number) */ 39 | double max_sqrt = sqrt((double)max_number); 40 | int max_loop = (unsigned int)ceil(max_sqrt) / 2 + 1; 41 | for (unsigned int i = 0; i < max_loop; ++i) { 42 | /** no need to sieve composite's multiples */ 43 | if (!bitmap_get(sieve, i)) 44 | continue; 45 | unsigned int base_prime = bit_map_index_to_number(i); 46 | 47 | /** each time start from base_prime * base_prime, sieve 3 * 3 first, 48 | * etc. */ 49 | unsigned int composite = base_prime * base_prime; 50 | while (composite <= max_number) { 51 | /** sieve prime */ 52 | unsigned int index = bit_map_number_to_index(composite); 53 | bitmap_clear(sieve, index); 54 | composite += (base_prime + base_prime); /** skip even number */ 55 | } 56 | } 57 | 58 | return sieve; 59 | } 60 | int prime_number_sieve_check(const BitMap *sieve, unsigned int number) 61 | { 62 | if (number < 2) { 63 | return 0; 64 | } else if (number == 2) { 65 | return 1; 66 | } else if (number % 2 == 0) { 67 | return 0; 68 | } else { 69 | return bitmap_get(sieve, bit_map_number_to_index(number)); 70 | } 71 | } 72 | 73 | unsigned int prime_number_sieve_count(const BitMap *sieve) 74 | { 75 | return bitmap_count(sieve) + 1; /** plus prime 2 */ 76 | } 77 | 78 | void prime_number_sieve_free(BitMap *sieve) 79 | { 80 | bitmap_free(sieve); 81 | } 82 | -------------------------------------------------------------------------------- /src/prime.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file prime.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Prime number calculation. 7 | * 8 | * @date 2019-07-21 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_PRIME_H 15 | #define RETHINK_C_PRIME_H 16 | 17 | #include "bitmap.h" 18 | 19 | /** 20 | * @brief Sieve the prime numbers less than or equal to specific max number. 21 | * 22 | * @param max_number The max number. 23 | * @return BitMap* The sieve bitmap. 24 | */ 25 | BitMap *prime_number_sieve(unsigned int max_number); 26 | 27 | /** 28 | * @brief Check if a number is prime number. 29 | * 30 | * Need call prime_number_sieve to get the sieve bitmap first. 31 | * 32 | * @param sieve The prime sieve bitmap. 33 | * @param number The number. 34 | * @return int 1 if prime, otherwise 0. 35 | */ 36 | int prime_number_sieve_check(const BitMap *sieve, unsigned int number); 37 | 38 | /** 39 | * @brief Count the amount of all prime numbers in a prime sieve. 40 | * 41 | * @param sieve The sieve. 42 | * @return unsigned int The amount. 43 | */ 44 | unsigned int prime_number_sieve_count(const BitMap *sieve); 45 | 46 | /** 47 | * @brief Delete a prime sieve and free back memory. 48 | * 49 | * @param sieve The prime sieve. 50 | */ 51 | void prime_number_sieve_free(BitMap *sieve); 52 | 53 | #endif /* #ifndef RETHINK_C_PRIME_H */ 54 | -------------------------------------------------------------------------------- /src/queue.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file queue.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to queue.h 5 | * @date 2019-07-20 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "queue.h" 12 | #include "def.h" 13 | #include 14 | #include 15 | 16 | Queue *queue_new() 17 | { 18 | Queue *queue = (Queue *)malloc(sizeof(Queue)); 19 | if (queue == NULL) { 20 | return NULL; 21 | } 22 | 23 | queue->head = queue->tail = NULL; 24 | queue->length = 0; 25 | return queue; 26 | } 27 | 28 | void queue_free(Queue *queue) 29 | { 30 | QueueNode *node = queue->head; 31 | 32 | while (node != NULL) { 33 | QueueNode *next = node->next; 34 | free(node); 35 | node = next; 36 | } 37 | 38 | free(queue); 39 | } 40 | 41 | static QueueNode *queuenode_new(QueueValue data) 42 | { 43 | QueueNode *node = (QueueNode *)malloc(sizeof(QueueNode)); 44 | if (node == NULL) { 45 | return NULL; 46 | } 47 | 48 | node->data = data; 49 | node->prev = node->next = NULL; 50 | return node; 51 | } 52 | 53 | int queue_push_head(Queue *queue, QueueValue data) 54 | { 55 | QueueNode *node = queuenode_new(data); 56 | if (node == NULL) { 57 | return -1; 58 | } 59 | 60 | if (queue->length == 0) { 61 | queue->tail = node; 62 | } else { 63 | queue->head->prev = node; 64 | } 65 | 66 | node->next = queue->head; 67 | queue->head = node; 68 | ++(queue->length); 69 | return 0; 70 | } 71 | 72 | QueueValue queue_pop_head(Queue *queue) 73 | { 74 | if (queue->length == 0) { 75 | return QUEUE_NULL; 76 | } 77 | 78 | QueueNode *node = queue->head; 79 | queue->head = node->next; 80 | 81 | if (queue->head == NULL) { 82 | queue->tail = NULL; 83 | } else { 84 | queue->head->prev = NULL; 85 | } 86 | 87 | --(queue->length); 88 | QueueValue value = node->data; 89 | free(node); 90 | return value; 91 | } 92 | 93 | QueueValue queue_peek_head(const Queue *queue) 94 | { 95 | if (queue->length == 0) { 96 | return QUEUE_NULL; 97 | } else { 98 | return queue->head->data; 99 | } 100 | } 101 | 102 | int queue_push_tail(Queue *queue, QueueValue data) 103 | { 104 | QueueNode *node = queuenode_new(data); 105 | if (node == NULL) { 106 | return -1; 107 | } 108 | 109 | if (queue->length == 0) { 110 | queue->head = node; 111 | } else { 112 | queue->tail->next = node; 113 | } 114 | 115 | node->prev = queue->tail; 116 | queue->tail = node; 117 | ++(queue->length); 118 | return 0; 119 | } 120 | 121 | QueueValue queue_pop_tail(Queue *queue) 122 | { 123 | if (queue->length == 0) { 124 | return QUEUE_NULL; 125 | } 126 | 127 | QueueNode *node = queue->tail; 128 | queue->tail = node->prev; 129 | 130 | if (queue->tail == NULL) { 131 | queue->head = NULL; 132 | } else { 133 | queue->tail->next = NULL; 134 | } 135 | 136 | --(queue->length); 137 | QueueValue value = node->data; 138 | free(node); 139 | return value; 140 | } 141 | 142 | QueueValue queue_peek_tail(const Queue *queue) 143 | { 144 | if (queue->length == 0) { 145 | return QUEUE_NULL; 146 | } else { 147 | return queue->tail->data; 148 | } 149 | } 150 | 151 | int queue_is_empty(const Queue *queue) 152 | { 153 | return queue->length == 0; 154 | } 155 | -------------------------------------------------------------------------------- /src/queue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file queue.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Double-ended queue (Deque). 7 | * 8 | * @date 2019-07-20 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_QUEUE_H 15 | #define RETHINK_C_QUEUE_H 16 | 17 | /** 18 | * @brief The type of a value to be stored in a @ref Queue. 19 | * (void *) can be changed to int, long, or other types if needed. 20 | */ 21 | typedef void *QueueValue; 22 | #define QUEUE_NULL ((void *)0) 23 | 24 | /** 25 | * @brief Definition of a @ref QueueNode. 26 | * 27 | */ 28 | typedef struct _QueueNode { 29 | QueueValue data; 30 | struct _QueueNode *prev; 31 | struct _QueueNode *next; 32 | } QueueNode; 33 | 34 | /** 35 | * @brief Definition of a @ref Queue. 36 | * 37 | */ 38 | typedef struct _Queue { 39 | struct _QueueNode *head; 40 | struct _QueueNode *tail; 41 | unsigned int length; 42 | } Queue; 43 | 44 | /** 45 | * @brief Allcate a new Queue. 46 | * 47 | * @return Queue* The new Queue if success, otherwise return NULL. 48 | */ 49 | Queue *queue_new(); 50 | 51 | /** 52 | * @brief Delete a Queue and free back memory. 53 | * 54 | * @param queue The Queue to delete. 55 | */ 56 | void queue_free(Queue *queue); 57 | 58 | /** 59 | * @brief Push a value to the head of a Queue. 60 | * 61 | * @param queue The Queue. 62 | * @param data The value to push. 63 | * @return int 0 if success. 64 | */ 65 | int queue_push_head(Queue *queue, QueueValue data); 66 | 67 | /** 68 | * @brief Pop the head value of a Queue. 69 | * 70 | * The head QueueNode of Queue has been popped and freed back memory. 71 | * 72 | * @param queue The Queue. 73 | * @return QueueValue The popped value. 74 | */ 75 | QueueValue queue_pop_head(Queue *queue); 76 | 77 | /** 78 | * @brief Peek the head value of a Queue. 79 | * 80 | * The head QueueNode of Queue still exists in the Queue! 81 | * 82 | * @param queue The Queue. 83 | * @return QueueValue The peeked value. 84 | */ 85 | QueueValue queue_peek_head(const Queue *queue); 86 | 87 | /** 88 | * @brief Push a value to the tail of a Queue. 89 | * 90 | * @param queue The Queue. 91 | * @param data The value to push. 92 | * @return int 0 if success. 93 | */ 94 | int queue_push_tail(Queue *queue, QueueValue data); 95 | 96 | /** 97 | * @brief Pop the head value of a Queue. 98 | * 99 | * The head QueueNode of Queue has been popped and freed back memory. 100 | * 101 | * @param queue The Queue. 102 | * @return QueueValue The popped value. 103 | */ 104 | QueueValue queue_pop_tail(Queue *queue); 105 | 106 | /** 107 | * @brief Peek the head value of a Queue. 108 | * 109 | * The head QueueNode of Queue still exists in the Queue! 110 | * 111 | * @param queue The Queue. 112 | * @return QueueValue The peeked value. 113 | */ 114 | QueueValue queue_peek_tail(const Queue *queue); 115 | 116 | /** 117 | * @brief Check if a Queue is empty. 118 | * 119 | * @param queue The Queue. 120 | * @return int 0 if not empty, 1 if empty. 121 | */ 122 | int queue_is_empty(const Queue *queue); 123 | 124 | #endif /* #ifndef RETHINK_C_QUEUE_H */ 125 | -------------------------------------------------------------------------------- /src/rbtree.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file rbtree.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Red black tree. 7 | * 8 | * @date 2019-07-28 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_RB_TREE_H 15 | #define RETHINK_C_RB_TREE_H 16 | 17 | /** 18 | * @brief The type of a key to be stored in a @ref RBTree. 19 | * (void *) can be changed to int, char *, or other types if needed. 20 | */ 21 | typedef void *RBTreeKey; 22 | 23 | /** 24 | * @brief The type of a key to be stored in a @ref RBTree. 25 | * (void *) can be changed to int, char *, or other types if needed. 26 | */ 27 | typedef void *RBTreeValue; 28 | 29 | /** 30 | * @brief Definition of RBTree Colors. 31 | * 32 | */ 33 | typedef enum _RBTreeColor { RED = 0, BLACK = 1 } RBTreeColor; 34 | 35 | /** 36 | * @brief Definition of a @ref RBTreeEntity. 37 | * 38 | */ 39 | typedef struct _RBTreeEntity { 40 | RBTreeValue value; 41 | struct _RBTreeEntity *next; 42 | } RBTreeEntity; 43 | 44 | /** 45 | * @brief Definition of a @ref RBTreeNode. 46 | * 47 | */ 48 | typedef struct _RBTreeNode { 49 | /** Key of the node. */ 50 | RBTreeKey key; 51 | /** Values of the node. */ 52 | RBTreeEntity *data; 53 | /** Parent node pointer. */ 54 | struct _RBTreeNode *parent; 55 | /** Left child node pointer. */ 56 | struct _RBTreeNode *left; 57 | /** Right child node pointer. */ 58 | struct _RBTreeNode *right; 59 | 60 | RBTreeColor color; 61 | } RBTreeNode; 62 | 63 | typedef int (*RBTreeCompareFunc)(RBTreeKey data1, RBTreeKey data2); 64 | typedef void (*RBTreeFreeKeyFunc)(RBTreeKey key); 65 | typedef void (*RBTreeFreeValueFunc)(RBTreeValue value); 66 | 67 | /** 68 | * @brief Definition of a @ref RBTree. 69 | * 70 | */ 71 | typedef struct _RBTree { 72 | /** Root node of the @ref RBTree pointer. */ 73 | struct _RBTreeNode *root; 74 | /** Compare two node key when do searching in RBTree. */ 75 | RBTreeCompareFunc compare_func; 76 | RBTreeFreeKeyFunc free_key_func; 77 | RBTreeFreeValueFunc free_value_func; 78 | /** The number of nodes of the @ref RBTree. */ 79 | unsigned int num_nodes; 80 | } RBTree; 81 | 82 | /** 83 | * @brief Allcate a new RBTree. 84 | * 85 | * @param compare_func Compare two node value when do searching in RBTree. 86 | * @param free_key_func Free key callback function. 87 | * @param free_value_func Free value callback function. 88 | * @return RBTree* The new RBTree if success, otherwise return NULL. 89 | */ 90 | RBTree *rb_tree_new(RBTreeCompareFunc compare_func, 91 | RBTreeFreeKeyFunc free_key_func, 92 | RBTreeFreeValueFunc free_value_func); 93 | 94 | /** 95 | * @brief Delete a RBTree and free back memory. 96 | * 97 | * @param tree The RBTree to delete. 98 | */ 99 | void rb_tree_free(RBTree *tree); 100 | 101 | /** 102 | * @brief Free a node in a RBTree. 103 | * 104 | * @param tree The RBTree. 105 | * @param node The node. 106 | */ 107 | void rb_tree_free_node(RBTree *tree, RBTreeNode *node); 108 | 109 | /** 110 | * @brief Get the leftmost child node of a RBTreeNode. 111 | * 112 | * @param node The RBTreeNode. 113 | * @return RBTreeNode* The leftmost RBTreeNode. If the RBTreeNode has 114 | * no left child, return itself. 115 | */ 116 | RBTreeNode *rb_tree_leftmost_node(RBTreeNode *node); 117 | 118 | /** 119 | * @brief Get the rightmost child node of a RBTreeNode. 120 | * 121 | * @param node The RBTreeNode. 122 | * @return RBTreeNode* The rightmost RBTreeNode. If the RBTreeNode has 123 | * no right child, return itself. 124 | */ 125 | RBTreeNode *rb_tree_rightmost_node(RBTreeNode *node); 126 | 127 | /** 128 | * @brief Insert a Key/Value to a RBTree. 129 | * 130 | * @param tree The RBTree. 131 | * @param key The key to insert. 132 | * @param value The value to insert. 133 | * @return RBTreeNode* The new inserted RBTreeNode if success, 134 | * otherwise return NULL. 135 | */ 136 | RBTreeNode *rb_tree_insert(RBTree *tree, RBTreeKey key, RBTreeValue value); 137 | 138 | /** 139 | * @brief Remove a RBTreeNode from a RBTree. 140 | * 141 | * @param tree The RBTree. 142 | * @param node The RBTreeNode. 143 | * @return RBTreeNode* The removed RBTreeNode if success, 144 | * otherwise return NULL. 145 | */ 146 | RBTreeNode *rb_tree_remove_node(RBTree *tree, RBTreeNode *node); 147 | 148 | /** 149 | * @brief Find a RBTreeNode value in a RBTree. 150 | * 151 | * @param tree The RBTree. 152 | * @param key The RBTreeNode key to lookup. 153 | * @return RBTreeNode* The matched RBTreeNode if success, otherwise NULL. 154 | */ 155 | RBTreeNode *rb_tree_find_node(RBTree *tree, RBTreeKey key); 156 | 157 | /** 158 | * @brief Traverse RBTree callback function. 159 | * 160 | */ 161 | typedef void (*RBTreeTraverseFunc)(RBTreeNode *node, void *args); 162 | 163 | /** 164 | * @brief Traverse RBTree by preorder. 165 | * 166 | * @param tree The RBTree. 167 | * @param callback The callback function do to each RBTreeNode in traverse. 168 | * @param cb_args The callback function's args. 169 | */ 170 | void rb_tree_preorder_traverse(RBTree *tree, 171 | RBTreeTraverseFunc callback, 172 | void *cb_args); 173 | 174 | /** 175 | * @brief Traverse RBTree by inorder. 176 | * 177 | * @param tree The RBTree. 178 | * @param callback The callback function do to each RBTreeNode in traverse. 179 | * @param cb_args The callback function's args. 180 | */ 181 | void rb_tree_inorder_traverse(RBTree *tree, 182 | RBTreeTraverseFunc callback, 183 | void *cb_args); 184 | 185 | /** 186 | * @brief Traverse RBTree by postorder. 187 | * 188 | * @param tree The RBTree. 189 | * @param callback The callback function do to each RBTreeNode in traverse. 190 | * @param cb_args The callback function's args. 191 | */ 192 | void rb_tree_postorder_traverse(RBTree *tree, 193 | RBTreeTraverseFunc callback, 194 | void *cb_args); 195 | 196 | /** 197 | * @brief A subtree's height in a RBTree. 198 | * 199 | * @param node The subtree's root node. 200 | * @return unsigned int The height. 201 | */ 202 | unsigned int rb_tree_subtree_height(RBTreeNode *node); 203 | 204 | /** 205 | * @brief Print a subtree. 206 | * 207 | * @param node The subtree's root node. 208 | * @param depth The subtree's depth. 209 | */ 210 | void rb_tree_subtree_print(RBTreeNode *node, int depth); 211 | 212 | #endif /* #ifndef RETHINK_C_RB_TREE_H */ 213 | -------------------------------------------------------------------------------- /src/skip_list.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file skip_list.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to skip_list.h 5 | * @date 2020-03-29 6 | * 7 | * @copyright Copyright (c) 2020, hutusi.com 8 | * 9 | */ 10 | 11 | /** 12 | * The implementaion of skip list reference to: 13 | * https://www.geeksforgeeks.org/skip-list/ 14 | * 15 | */ 16 | 17 | #include "skip_list.h" 18 | #include "def.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define SKIP_LIST_NIL NULL 25 | 26 | static SkipListNode * 27 | skip_list_node_new(int level, SkipListKey key, SkipListValue value) 28 | { 29 | SkipListNode *node = (SkipListNode *)malloc(sizeof(SkipListNode)); 30 | 31 | node->key = key; 32 | node->value = value; 33 | 34 | node->next_array = 35 | (SkipListNode **)malloc((level + 1) * sizeof(SkipListNode *)); 36 | for (int i = 0; i <= level; i++) { 37 | node->next_array[i] = NULL; 38 | } 39 | 40 | return node; 41 | } 42 | 43 | void skip_list_free_node(SkipList *list, SkipListNode *node) 44 | { 45 | if (list->free_key_func && node->value) { 46 | list->free_key_func(node->key); 47 | } 48 | 49 | if (list->free_value_func && node->value) { 50 | list->free_value_func(node->value); 51 | } 52 | 53 | free(node->next_array); 54 | free(node); 55 | } 56 | 57 | SkipList *skip_list_new(SkipListCompareFunc compare_func, 58 | SkipListFreeKeyFunc free_key_func, 59 | SkipListFreeValueFunc free_value_func) 60 | { 61 | SkipList *list = (SkipList *)malloc(sizeof(SkipList)); 62 | list->compare_func = compare_func; 63 | list->free_key_func = free_key_func; 64 | list->free_value_func = free_value_func; 65 | list->level = 0; 66 | 67 | list->head = 68 | skip_list_node_new(SKIP_LIST_MAX_LEVEL, SKIP_LIST_NIL, SKIP_LIST_NIL); 69 | 70 | return list; 71 | } 72 | 73 | void skip_list_free(SkipList *list) 74 | { 75 | SkipListNode *node = list->head; 76 | 77 | while (node != NULL) { 78 | SkipListNode *next = node->next_array[0]; 79 | skip_list_free_node(list, node); 80 | node = next; 81 | } 82 | 83 | free(list); 84 | } 85 | 86 | static int skip_list_random_level(SkipList *list) 87 | { 88 | int level = 0; 89 | while ((rand() & RAND_MAX) < (RAND_MAX / SKIP_LIST_RANDOM_FACTOR)) { 90 | level++; 91 | if (level >= SKIP_LIST_MAX_LEVEL) 92 | break; 93 | } 94 | return level; 95 | } 96 | 97 | SkipListNode * 98 | skip_list_insert(SkipList *list, SkipListKey key, SkipListValue value) 99 | { 100 | SkipListNode **updates = (SkipListNode **)malloc((SKIP_LIST_MAX_LEVEL + 1) * 101 | sizeof(SkipListNode *)); 102 | 103 | for (int i = SKIP_LIST_MAX_LEVEL; i >= 0; i--) { 104 | if (i == SKIP_LIST_MAX_LEVEL) { 105 | updates[i] = list->head; 106 | } else { 107 | updates[i] = updates[i + 1]; 108 | } 109 | SkipListNode *next = updates[i]->next_array[i]; 110 | while (next != NULL && list->compare_func(key, next->key) > 0) { 111 | updates[i] = next; 112 | next = next->next_array[i]; 113 | } 114 | } 115 | 116 | int level = skip_list_random_level(list); 117 | SkipListNode *node = skip_list_node_new(level, key, value); 118 | 119 | // update next_array on each level 120 | for (int i = 0; i <= level; i++) { 121 | node->next_array[i] = updates[i]->next_array[i]; 122 | updates[i]->next_array[i] = node; 123 | } 124 | 125 | if (level > list->level) 126 | list->level = level; 127 | free(updates); 128 | 129 | return node; 130 | } 131 | 132 | SkipListNode *skip_list_remove_node(SkipList *list, SkipListKey key) 133 | { 134 | SkipListNode *prev = list->head; 135 | for (int i = list->level; i >= 0; i--) { 136 | SkipListNode *next = prev->next_array[i]; 137 | while (next != NULL) { 138 | int cmp = list->compare_func(key, next->key); 139 | if (cmp > 0) { 140 | prev = next; 141 | next = next->next_array[i]; 142 | } else if (cmp < 0) { 143 | break; 144 | } else { 145 | SkipListNode **updates = (SkipListNode **)malloc( 146 | (SKIP_LIST_MAX_LEVEL + 1) * sizeof(SkipListNode *)); 147 | 148 | SkipListNode *node = next; 149 | updates[i] = prev; 150 | 151 | for (int j = i - 1; j >= 0; j--) { 152 | while (prev->next_array[j] != node) 153 | prev = prev->next_array[j]; 154 | updates[j] = prev; 155 | } 156 | 157 | // update next_array on each level 158 | for (int j = 0; j <= i; j++) { 159 | updates[j]->next_array[j] = node->next_array[j]; 160 | } 161 | 162 | for (int j = list->level; j >= 0; j--) { 163 | if (list->head->next_array[j] == NULL) { 164 | list->level--; 165 | } else { 166 | break; 167 | } 168 | } 169 | 170 | free(updates); 171 | return node; 172 | } 173 | } 174 | } 175 | 176 | return NULL; 177 | } 178 | 179 | SkipListValue skip_list_find(SkipList *list, SkipListKey key) 180 | { 181 | SkipListNode *prev = list->head; 182 | for (int i = list->level; i >= 0; i--) { 183 | SkipListNode *next = prev->next_array[i]; 184 | while (next != NULL) { 185 | int cmp = list->compare_func(key, next->key); 186 | if (cmp > 0) { 187 | prev = next; 188 | next = next->next_array[i]; 189 | } else if (cmp < 0) { 190 | break; 191 | } else { 192 | return next->value; 193 | } 194 | } 195 | } 196 | 197 | return SKIP_LIST_NIL; 198 | } 199 | 200 | void skip_list_print(SkipList *list) 201 | { 202 | printf("\n Print Skip List: \n"); 203 | for (int i = 0; i <= list->level; i++) { 204 | printf("Level %d: ", i); 205 | SkipListNode *cursor = list->head->next_array[i]; 206 | while (cursor != NULL) { 207 | printf("%4d", *(int *)cursor->key); 208 | cursor = cursor->next_array[i]; 209 | } 210 | printf("\n"); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/skip_list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file skip_list.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Skip List. 7 | * 8 | * @date 2020-03-29 9 | * 10 | * @copyright Copyright (c) 2020, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_SKIP_LIST_H 15 | #define RETHINK_C_SKIP_LIST_H 16 | 17 | /** Max level of the @ref SkipList **/ 18 | #define SKIP_LIST_MAX_LEVEL 16 19 | /** Random level factor of the @ref SkipList **/ 20 | #define SKIP_LIST_RANDOM_FACTOR 4 21 | 22 | /** 23 | * @brief The type of a key to be stored in a @ref SkipListNode. 24 | * (void *) can be changed to int, char *, or other types if needed. 25 | */ 26 | typedef void *SkipListKey; 27 | 28 | /** 29 | * @brief The type of a key to be stored in a @ref SkipListNode. 30 | * (void *) can be changed to int, char *, or other types if needed. 31 | */ 32 | typedef void *SkipListValue; 33 | 34 | /** 35 | * @brief Definition of a @ref SkipListNode. 36 | * 37 | */ 38 | typedef struct _SkipListNode { 39 | SkipListKey key; 40 | SkipListValue value; 41 | struct _SkipListNode **next_array; 42 | } SkipListNode; 43 | 44 | typedef int (*SkipListCompareFunc)(SkipListKey data1, SkipListKey data2); 45 | typedef void (*SkipListFreeKeyFunc)(SkipListKey key); 46 | typedef void (*SkipListFreeValueFunc)(SkipListValue value); 47 | 48 | /** 49 | * @brief Definition of a @ref SkipList. 50 | * 51 | */ 52 | typedef struct _SkipList { 53 | /** Current level of the @ref SkipList **/ 54 | int level; 55 | /** The head node of the @ref SkipList **/ 56 | SkipListNode *head; 57 | 58 | /** Compare two node key when do searching in SkipList. */ 59 | SkipListCompareFunc compare_func; 60 | SkipListFreeKeyFunc free_key_func; 61 | SkipListFreeValueFunc free_value_func; 62 | } SkipList; 63 | 64 | /** 65 | * @brief Allcate a new SkipList. 66 | * 67 | * @param compare_func Compare two node value when do searching in 68 | * SkipList. 69 | * @param free_key_func Free key callback function. 70 | * @param free_value_func Free value callback function. 71 | * @return SkipList* The new SkipList if success, otherwise return 72 | * NULL. 73 | */ 74 | SkipList *skip_list_new(SkipListCompareFunc compare_func, 75 | SkipListFreeKeyFunc free_key_func, 76 | SkipListFreeValueFunc free_value_func); 77 | 78 | /** 79 | * @brief Delete a SkipList and free back memory. 80 | * 81 | * @param list The SkipList to delete. 82 | */ 83 | void skip_list_free(SkipList *list); 84 | 85 | /** 86 | * @brief Free a node in a SkipList. 87 | * 88 | * @param list The SkipList. 89 | * @param node The node. 90 | */ 91 | void skip_list_free_node(SkipList *list, SkipListNode *node); 92 | 93 | /** 94 | * @brief Insert a Key/Value to a SkipList. 95 | * 96 | * @param list The SkipList. 97 | * @param key The key to insert. 98 | * @param value The value to insert. 99 | * @return SkipListNode* The new inserted SkipListNode if success, 100 | * otherwise return NULL. 101 | */ 102 | SkipListNode * 103 | skip_list_insert(SkipList *list, SkipListKey key, SkipListValue value); 104 | 105 | /** 106 | * @brief Remove a SkipListNode from a SkipList. 107 | * 108 | * @param list The SkipList. 109 | * @param key The Key to find @SkipListNode to remove. 110 | * @return SkipListNode* The removed SkipListNode if success, 111 | * otherwise return NULL. 112 | */ 113 | SkipListNode *skip_list_remove_node(SkipList *list, SkipListKey key); 114 | 115 | /** 116 | * @brief Find a SkipListNode value in a SkipList. 117 | * 118 | * @param list The SkipList. 119 | * @param key The SkipListNode value to lookup. 120 | * @return SkipListValue The matched value of node if success, otherwise 121 | * NULL. 122 | */ 123 | SkipListValue skip_list_find(SkipList *list, SkipListKey key); 124 | 125 | /** 126 | * @brief Print a @ref SkipList. 127 | * 128 | * @param list The SkipList. 129 | */ 130 | void skip_list_print(SkipList *list); 131 | 132 | #endif /* #ifndef RETHINK_C_SKIP_LIST_H */ 133 | -------------------------------------------------------------------------------- /src/sparse_graph.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sparse_graph.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to sparse_graph.h 5 | * @date 2019-09-05 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "sparse_graph.h" 12 | #include "def.h" 13 | #include "dup.h" 14 | #include "queue.h" 15 | 16 | #include 17 | #include 18 | 19 | struct _AdjacencyArc { 20 | int vertex; 21 | int weight; 22 | struct _AdjacencyArc *next; 23 | }; 24 | 25 | struct _AdjacencyList { 26 | unsigned int out_degree; 27 | struct _AdjacencyArc *first_arc; 28 | }; 29 | 30 | AdjacencyList *adjacency_list_new() 31 | { 32 | AdjacencyList *list = (AdjacencyList *)malloc(sizeof(AdjacencyList)); 33 | list->out_degree = 0; 34 | list->first_arc = NULL; 35 | return list; 36 | } 37 | 38 | void adjacency_list_free(AdjacencyList *list) 39 | { 40 | AdjacencyArc *arc = list->first_arc; 41 | AdjacencyArc *pre_arc = NULL; 42 | while (arc != NULL) { 43 | pre_arc = arc; 44 | arc = arc->next; 45 | free(pre_arc); 46 | } 47 | 48 | free(list); 49 | } 50 | 51 | SparseGraph *sparse_graph_new(unsigned int num_vertex) 52 | { 53 | SparseGraph *graph = arraylist_new(adjacency_list_free, num_vertex); 54 | for (int i = 0; i < num_vertex; ++i) { 55 | arraylist_append(graph, adjacency_list_new()); 56 | } 57 | return graph; 58 | } 59 | 60 | void sparse_graph_free(SparseGraph *graph) 61 | { 62 | arraylist_free(graph); 63 | } 64 | 65 | int sparse_graph_is_linked(SparseGraph *graph, int vertex1, int vertex2) 66 | { 67 | AdjacencyList *list = (AdjacencyList *)graph->data[vertex1]; 68 | if (list == NULL) { 69 | return 0; 70 | } 71 | 72 | AdjacencyArc *arc = list->first_arc; 73 | 74 | while (arc != NULL) { 75 | if (arc->vertex == vertex2) 76 | return 1; 77 | arc = arc->next; 78 | } 79 | 80 | return 0; 81 | } 82 | 83 | AdjacencyArc *sparse_graph_new_arc(int vertex, int weight) 84 | { 85 | AdjacencyArc *arc = (AdjacencyArc *)malloc(sizeof(AdjacencyArc)); 86 | arc->vertex = vertex; 87 | arc->weight = weight; 88 | arc->next = NULL; 89 | return arc; 90 | } 91 | 92 | int sparse_graph_link(SparseGraph *graph, int vertex1, int vertex2) 93 | { 94 | AdjacencyList *list = (AdjacencyList *)graph->data[vertex1]; 95 | if (list == NULL) { 96 | return -1; 97 | } 98 | 99 | AdjacencyArc *arc = list->first_arc; 100 | AdjacencyArc *pre_arc = NULL; 101 | while (arc != NULL) { 102 | if (arc->vertex == vertex2) 103 | return 1; 104 | pre_arc = arc; 105 | arc = arc->next; 106 | } 107 | 108 | AdjacencyArc *new_arc = sparse_graph_new_arc(vertex2, 1); 109 | if (pre_arc = NULL) { 110 | list->first_arc = new_arc; 111 | } else { 112 | pre_arc->next = new_arc; 113 | } 114 | ++(list->out_degree); 115 | 116 | return 0; 117 | } 118 | 119 | int *sparse_graph_topo_sort(SparseGraph *graph) 120 | { 121 | int *sorted_vertexes = (int *)malloc(graph->length * sizeof(int)); 122 | int *in_degrees = (int *)malloc(graph->length * sizeof(int)); 123 | memset(in_degrees, 0, graph->length * sizeof(int)); 124 | 125 | for (int i = 0; i < graph->length; ++i) { 126 | AdjacencyList *alist = (AdjacencyList *)graph->data[i]; 127 | AdjacencyArc *arc = alist->first_arc; 128 | while (arc != NULL) { 129 | ++(in_degrees[arc->vertex]); 130 | arc = arc->next; 131 | } 132 | } 133 | 134 | Queue *queue = queue_new(); 135 | for (int i = 0; i < graph->length; ++i) { 136 | if (in_degrees[i] == 0) { 137 | queue_push_tail(queue, intdup(i)); 138 | } 139 | } 140 | 141 | int num = 0; 142 | while (!queue_is_empty(queue)) { 143 | int *v = (int *)queue_pop_head(queue); 144 | sorted_vertexes[num++] = *v; 145 | 146 | AdjacencyList *alist = (AdjacencyList *)graph->data[*v]; 147 | AdjacencyArc *arc = alist->first_arc; 148 | while (arc != NULL) { 149 | --(in_degrees[arc->vertex]); 150 | arc = arc->next; 151 | } 152 | --(in_degrees[*v]); 153 | free(v); 154 | 155 | for (int i = 0; i < graph->length; ++i) { 156 | if (in_degrees[i] == 0) { 157 | queue_push_tail(queue, intdup(i)); 158 | } 159 | } 160 | } 161 | 162 | queue_free(queue); 163 | free(in_degrees); 164 | return sorted_vertexes; 165 | } 166 | -------------------------------------------------------------------------------- /src/sparse_graph.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file graph.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Adjacency Matrix. 7 | * 8 | * @date 2019-07-21 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_SPARSE_GRAPH_H 15 | #define RETHINK_C_SPARSE_GRAPH_H 16 | 17 | #include "arraylist.h" 18 | 19 | typedef struct _AdjacencyArc AdjacencyArc; 20 | typedef struct _AdjacencyList AdjacencyList; 21 | typedef ArrayList SparseGraph; 22 | 23 | /** 24 | * @brief Malloc a new Sparse Graph. 25 | * 26 | * @param num_vertex The number of vertexes. 27 | * @return SparseGraph* The new Sparse Graph. 28 | */ 29 | SparseGraph *sparse_graph_new(unsigned int num_vertex); 30 | 31 | /** 32 | * @brief Delete a Sparse Graph. 33 | * 34 | * @param graph The Sparse Graph. 35 | */ 36 | void sparse_graph_free(SparseGraph *graph); 37 | 38 | /** 39 | * @brief Link two vertexes in a Sparse Graph. 40 | * 41 | * @param graph The Sparse Graph. 42 | * @param vertex1 43 | * @param vertex2 44 | * @return int 45 | */ 46 | int sparse_graph_link(SparseGraph *graph, int vertex1, int vertex2); 47 | 48 | /** 49 | * @brief Topological sorting by Khan algorithm. 50 | * 51 | * @param graph 52 | * @return Queue* 53 | */ 54 | int *sparse_graph_topo_sort(SparseGraph *graph); 55 | 56 | #endif /* #ifndef RETHINK_C_SPARSE_GRAPH_H */ -------------------------------------------------------------------------------- /src/sunday.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sunday.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to sunday.h 5 | * @date 2019-08-19 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "sunday.h" 12 | #include "def.h" 13 | #include 14 | 15 | STATIC void 16 | sunday_calculate_bad_chars(const char *pattern, int len, int *bad_chars) 17 | { 18 | for (int i = 0; i < 256; ++i) { 19 | bad_chars[i] = -1; 20 | } 21 | 22 | for (int i = len - 1; i >= 0; --i) { 23 | int ch = pattern[i]; 24 | if (bad_chars[ch] < 0) { 25 | bad_chars[ch] = i; 26 | } 27 | } 28 | } 29 | 30 | int sunday_text_match(const char *text, 31 | unsigned int text_len, 32 | const char *pattern, 33 | unsigned int pat_len) 34 | { 35 | int bad_chars[256]; 36 | sunday_calculate_bad_chars(pattern, pat_len, bad_chars); 37 | 38 | int move = 0; 39 | for (int i = 0; i < text_len; /* no ++i */) { 40 | for (int j = 0; j < pat_len; /* no ++j */) { 41 | if (text[i] == pattern[j]) { 42 | ++i; 43 | ++j; 44 | } else { 45 | move = pat_len - bad_chars[(int)text[pat_len + move]]; 46 | i = move; 47 | j = 0; 48 | } 49 | } 50 | 51 | /* here means j == pat_len */ 52 | return move; 53 | } 54 | 55 | return -1; 56 | } 57 | 58 | int sunday_string_match(const char *text, const char *pattern) 59 | { 60 | return sunday_text_match(text, strlen(text), pattern, strlen(pattern)); 61 | } 62 | -------------------------------------------------------------------------------- /src/sunday.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file sunday.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Sunday algorithm. 7 | * 8 | * @date 2019-08-19 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_SUNDAY_H 15 | #define RETHINK_C_SUNDAY_H 16 | 17 | /** 18 | * @brief Sunday algorithm to find the match substring. 19 | * 20 | * @param text The text string. 21 | * @param text_len The length of text. 22 | * @param pattern The pattern string. 23 | * @param pat_len The length of pattern string. 24 | * @return int The first match index, -1 if no match. 25 | */ 26 | int sunday_text_match(const char *text, 27 | unsigned int text_len, 28 | const char *pattern, 29 | unsigned int pat_len); 30 | 31 | /** 32 | * @brief Sunday algorithm to find the match substring. 33 | * 34 | * @param text The text string. 35 | * @param pattern The pattern string. 36 | * @return int The first match index, -1 if no match. 37 | */ 38 | int sunday_string_match(const char *text, const char *pattern); 39 | 40 | #endif /* #ifndef RETHINK_C_SUNDAY_H */ 41 | -------------------------------------------------------------------------------- /src/text.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file text.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to text.h 5 | * @date 2019-08-15 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "text.h" 12 | #include "def.h" 13 | #include 14 | #include 15 | 16 | /** 17 | * @brief All ways append '\0' to text, for dapat c string. 18 | * 19 | */ 20 | 21 | /** 22 | * @brief Definition of a @ref Text. 23 | * 24 | */ 25 | struct _Text { 26 | char *data; 27 | unsigned int length; 28 | unsigned int _allocated; 29 | }; 30 | 31 | static inline Text *text_new_with_size(unsigned int size) 32 | { 33 | Text *text = (Text *)malloc(sizeof(Text)); 34 | text->_allocated = size; 35 | text->length = 0; 36 | text->data = (char *)malloc(text->_allocated * sizeof(char)); 37 | return text; 38 | } 39 | 40 | Text *text_new() 41 | { 42 | return text_new_with_size(16); /** initial default. */ 43 | } 44 | 45 | Text *text_from(const char *string) 46 | { 47 | size_t len = strlen(string); 48 | Text *text = text_new_with_size(len + 1); 49 | strcpy(text->data, string); 50 | text->length = len; 51 | return text; 52 | } 53 | 54 | Text *text_n_from(const char *string, int length) 55 | { 56 | Text *text = text_new_with_size(length + 1); 57 | strncpy(text->data, string, length); 58 | text->data[length] = '\0'; 59 | text->length = length; 60 | return text; 61 | } 62 | 63 | void text_free(Text *text) 64 | { 65 | free(text->data); 66 | free(text); 67 | } 68 | 69 | Text *text_clone(const Text *text) 70 | { 71 | Text *clone = text_new_with_size(text->_allocated); 72 | strncpy(clone->data, text->data, text->length + 1); 73 | clone->length = text->length; 74 | return clone; 75 | } 76 | 77 | const char *text_char_string(const Text *text) 78 | { 79 | return text->data; 80 | } 81 | 82 | unsigned int text_length(const Text *text) 83 | { 84 | return text->length; 85 | } 86 | 87 | char text_char_at(const Text *text, unsigned int index) 88 | { 89 | if (index >= text->length) { 90 | return CHAR_NIL; 91 | } else { 92 | return text->data[index]; 93 | } 94 | } 95 | 96 | int text_compare(const Text *text1, const Text *text2) 97 | { 98 | for (unsigned int i = 0; i < text1->length; ++i) { 99 | if (text1->data[i] > text2->data[i]) { 100 | return 1; 101 | } else if (text1->data[i] < text2->data[i]) { 102 | return -1; 103 | } else { 104 | continue; 105 | } 106 | } 107 | 108 | if (text1->length > text2->length) { 109 | return 1; 110 | } else if (text1->length < text2->length) { 111 | return -1; 112 | } else { 113 | return 0; 114 | } 115 | } 116 | 117 | int text_equal(const Text *text1, const Text *text2) 118 | { 119 | return text_compare(text1, text2) == 0; 120 | } 121 | 122 | Text *text_append(Text *text, char ch) 123 | { 124 | if ((text->length + 1) >= text->_allocated) { 125 | text->_allocated += 16; 126 | text->data = (char *)realloc(text->data, text->_allocated); 127 | } 128 | 129 | text->data[text->length] = ch; 130 | ++(text->length); 131 | text->data[text->length] = '\0'; 132 | return text; 133 | } 134 | -------------------------------------------------------------------------------- /src/text.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file text.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Text string. (similar to string in C++.) 7 | * 8 | * The most difference between Text and char string is: 9 | * 10 | * Text can contain '\0', NIL, or any charactor. 11 | * 12 | * @date 2019-08-15 13 | * 14 | * @copyright Copyright (c) 2019, hutusi.com 15 | * 16 | */ 17 | 18 | #ifndef RETHINK_C_TEXT_H 19 | #define RETHINK_C_TEXT_H 20 | 21 | /** 22 | * @brief Definition of a @ref Text. 23 | * 24 | */ 25 | typedef struct _Text Text; 26 | 27 | #define CHAR_NIL 0 28 | 29 | /** 30 | * @brief Allocate a new empty Text. 31 | * 32 | * @return Text* The new Text if success, otherwise NULL. 33 | */ 34 | Text *text_new(); 35 | 36 | /** 37 | * @brief New a new Text from a string. 38 | * 39 | * @param string The original string. 40 | * @return Text* Return new Text if success, otherwise NULL. 41 | */ 42 | Text *text_from(const char *string); 43 | 44 | /** 45 | * @brief New a new Text from a string with length. 46 | * 47 | * @param string The original string. 48 | * @param length The length of the string. 49 | * @return Text* The new Text if success, otherwise NULL. 50 | */ 51 | Text *text_n_from(const char *string, int length); 52 | 53 | /** 54 | * @brief Delete a Text and free back memory. 55 | * 56 | * @param text The Text to delete. 57 | */ 58 | void text_free(Text *text); 59 | 60 | /** 61 | * @brief Clone a new text from text. 62 | * 63 | * @param text The text. 64 | * @return Text* The clone new text. 65 | */ 66 | Text *text_clone(const Text *text); 67 | 68 | /** 69 | * @brief Convert a text as a const char string. 70 | * 71 | * @param text The text. 72 | * @return const char* The char string. 73 | */ 74 | const char *text_char_string(const Text *text); 75 | 76 | /** 77 | * @brief Get the length of a text. 78 | * 79 | * @param text The text. 80 | * @return unsigned int The length. 81 | */ 82 | unsigned int text_length(const Text *text); 83 | 84 | /** 85 | * @brief Get the indicated index charactor of a text. 86 | * 87 | * @param text The text. 88 | * @param index The indicated index. 89 | * @return char The charactor. 90 | */ 91 | char text_char_at(const Text *text, unsigned int index); 92 | 93 | /** 94 | * @brief Compare two text. 95 | * 96 | * @param text1 One text. 97 | * @param text2 Another text. 98 | * @return int 1 if the first text greater than the second; -1 if the 99 | * second text greater than the first; 0 if two text have same 100 | * content. 101 | */ 102 | int text_compare(const Text *text1, const Text *text2); 103 | 104 | /** 105 | * @brief Judge the equality of two text's content. 106 | * 107 | * @param text1 One text. 108 | * @param text2 Another text. 109 | * @return int Return 1 if equal, otherwise return 0. 110 | */ 111 | int text_equal(const Text *text1, const Text *text2); 112 | 113 | /** 114 | * @brief Append a charactor to a Text. 115 | * 116 | * @param text The Text. 117 | * @param ch The charactor. 118 | * @return Text* The appended Text. 119 | */ 120 | Text *text_append(Text *text, char ch); 121 | 122 | #endif /* #ifndef RETHINK_C_TEXT_H */ 123 | -------------------------------------------------------------------------------- /src/trie.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file trie.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Refer to trie.h 5 | * @date 2019-08-11 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "trie.h" 12 | #include "compare.h" 13 | #include "def.h" 14 | #include "hash.h" 15 | #include 16 | 17 | static TrieNode *trie_new_node(char ch) 18 | { 19 | TrieNode *node = (TrieNode *)malloc(sizeof(TrieNode)); 20 | node->data = ch; 21 | node->ending = false; 22 | node->children = hash_table_new( 23 | hash_char, 24 | char_equal, 25 | free, 26 | NULL); /** value will be freed in root's recursive free func. */ 27 | return node; 28 | } 29 | 30 | Trie *trie_new() 31 | { 32 | Trie *trie = (Trie *)malloc(sizeof(Trie)); 33 | trie->root = trie_new_node((char)0); 34 | return trie; 35 | } 36 | 37 | static void trie_free_node_recursive(TrieNode *node) 38 | { 39 | if (node == NULL) 40 | return; 41 | 42 | HashTableEntity *iterator = hash_table_first_entity(node->children); 43 | while (iterator != NULL) { 44 | HashTableEntity *prev = iterator; 45 | iterator = hash_table_next_entity(node->children, prev); 46 | 47 | TrieNode *child = (TrieNode *)(prev->value); 48 | trie_free_node_recursive(child); 49 | } 50 | 51 | hash_table_free(node->children); 52 | free(node); 53 | } 54 | 55 | void trie_free(Trie *trie) 56 | { 57 | // free root node will free all nodes 58 | trie_free_node_recursive(trie->root); 59 | free(trie); 60 | } 61 | 62 | static char *trie_char_dup(char value) 63 | { 64 | char *dup = (char *)malloc(sizeof(char)); 65 | *dup = value; 66 | return dup; 67 | } 68 | 69 | int trie_insert(Trie *trie, const char *str, unsigned int len) 70 | { 71 | TrieNode *rover = trie->root; 72 | for (int i = 0; i < len; ++i) { 73 | TrieNode *node = hash_table_get(rover->children, (void *)&(str[i])); 74 | if (node == HASH_TABLE_VALUE_NULL) { 75 | node = trie_new_node(str[i]); 76 | hash_table_insert(rover->children, trie_char_dup(str[i]), node); 77 | } 78 | rover = node; 79 | } 80 | 81 | rover->ending = true; 82 | return 0; 83 | } 84 | 85 | TrieNode *trie_last_node(const Trie *trie, const char *str, unsigned int len) 86 | { 87 | TrieNode *rover = trie->root; 88 | for (int i = 0; i < len; ++i) { 89 | TrieNode *node = hash_table_get(rover->children, (void *)&(str[i])); 90 | if (node == HASH_TABLE_VALUE_NULL) { 91 | return NULL; 92 | } 93 | rover = node; 94 | } 95 | return rover; 96 | } 97 | 98 | int trie_delete(Trie *trie, const char *str, unsigned int len) 99 | { 100 | TrieNode *last = trie_last_node(trie, str, len); 101 | if (last != NULL) { 102 | last->ending = false; 103 | return 0; 104 | } else { 105 | return -1; 106 | } 107 | } 108 | 109 | bool trie_include(const Trie *trie, const char *str, unsigned int len) 110 | { 111 | TrieNode *last = trie_last_node(trie, str, len); 112 | return last != NULL && last->ending == true; 113 | } 114 | -------------------------------------------------------------------------------- /src/trie.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file trie.h 3 | * 4 | * @author hutusi (hutusi@outlook.com) 5 | * 6 | * @brief Trie Tree. 7 | * 8 | * @date 2019-08-11 9 | * 10 | * @copyright Copyright (c) 2019, hutusi.com 11 | * 12 | */ 13 | 14 | #ifndef RETHINK_C_TRIE_H 15 | #define RETHINK_C_TRIE_H 16 | 17 | #include "hash_table.h" 18 | #include 19 | 20 | /** 21 | * @brief Definition of a @ref TrieNode. 22 | * 23 | */ 24 | typedef struct _TrieNode { 25 | /** Value of the node. */ 26 | char data; 27 | bool ending; 28 | HashTable *children; 29 | } TrieNode; 30 | 31 | /** 32 | * @brief Definition of a @ref Trie. 33 | * 34 | */ 35 | typedef struct _Trie { 36 | TrieNode *root; 37 | } Trie; 38 | 39 | /** 40 | * @brief Allcate a new Trie. 41 | * 42 | * @return Trie* The new Trie if success, otherwise NULL. 43 | */ 44 | Trie *trie_new(); 45 | 46 | /** 47 | * @brief Delete a Trie and free back memory. 48 | * 49 | * @param trie The Trie to delete. 50 | */ 51 | void trie_free(Trie *trie); 52 | 53 | /** 54 | * @brief Insert a string into a Trie. 55 | * 56 | * @param trie The Trie. 57 | * @param str The string. 58 | * @param len The length of the string. 59 | * @return int 0 if success. 60 | */ 61 | int trie_insert(Trie *trie, const char *str, unsigned int len); 62 | 63 | /** 64 | * @brief Delete a string into a Trie. 65 | * 66 | * Just mark the ending as 'false'. 67 | * 68 | * @param trie The Trie. 69 | * @param str The string. 70 | * @param len The length of the string. 71 | * @return int 0 if success. 72 | */ 73 | int trie_delete(Trie *trie, const char *str, unsigned int len); 74 | 75 | /** 76 | * @brief Check if a Trie include a string (full match). 77 | * 78 | * @param trie The Trie. 79 | * @param str The string. 80 | * @param len The length of the string. 81 | * @return true Include a full match. 82 | * @return false Not include a full match. 83 | */ 84 | bool trie_include(const Trie *trie, const char *str, unsigned int len); 85 | 86 | /** 87 | * @brief Get the last node of a Trie by a string. 88 | * 89 | * @param trie The Trie. 90 | * @param str The string. 91 | * @param len The length of the string. 92 | * @return TrieNode* The last match node. 93 | */ 94 | TrieNode *trie_last_node(const Trie *trie, const char *str, unsigned int len); 95 | 96 | #endif /* #ifndef RETHINK_C_TRIE_H */ 97 | -------------------------------------------------------------------------------- /src/vector.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file vector.c 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief 5 | * @date 2019-08-30 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #include "vector.h" 12 | #include "def.h" 13 | #include 14 | #include 15 | 16 | Vector *vector_new(unsigned int num_dimensions, ...) 17 | { 18 | Vector *vector = (Vector *)malloc(sizeof(Vector)); 19 | if (vector == NULL) { 20 | return NULL; 21 | } 22 | vector->num_dimensions = num_dimensions; 23 | vector->coordinates = (double *)malloc(sizeof(double) * num_dimensions); 24 | if (vector->coordinates == NULL) { 25 | free(vector); 26 | return NULL; 27 | } 28 | 29 | va_list vl; 30 | va_start(vl, num_dimensions); 31 | for (int i = 0; i < num_dimensions; ++i) { 32 | vector->coordinates[i] = va_arg(vl, double); 33 | } 34 | va_end(vl); 35 | 36 | return vector; 37 | } 38 | 39 | void vector_free(Vector *vector) 40 | { 41 | free(vector->coordinates); 42 | free(vector); 43 | } 44 | -------------------------------------------------------------------------------- /src/vector.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file vector.h 3 | * @author hutusi (hutusi@outlook.com) 4 | * @brief Vector. 5 | * @date 2019-08-30 6 | * 7 | * @copyright Copyright (c) 2019, hutusi.com 8 | * 9 | */ 10 | 11 | #ifndef RETHINK_C_VECTOR_H 12 | #define RETHINK_C_VECTOR_H 13 | 14 | /** 15 | * @brief Definition of a @ref Vector. 16 | * 17 | */ 18 | typedef struct _Vector { 19 | double *coordinates; 20 | unsigned int num_dimensions; 21 | } Vector; 22 | 23 | /** 24 | * @brief Malloc a new Vector. 25 | * 26 | * @param num_dimensions 27 | * @param ... The coordinates, should be double. e.g., 1.0, not 1. 28 | * @return Vector* The new Vector. 29 | */ 30 | Vector *vector_new(unsigned int num_dimensions, ...); 31 | 32 | /** 33 | * @brief Delete a Vector and free back memory. 34 | * 35 | * @param vector The Vector to delete. 36 | */ 37 | void vector_free(Vector *vector); 38 | 39 | #endif /* #ifndef RETHINK_C_VECTOR_H */ 40 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(testcases alloc-testing.c test_helper.c test_arraylist.c test_list.c 2 | test_queue.c test_bitmap.c test_matrix.c 3 | test_bstree.c test_avltree.c test_rbtree.c test_heap.c test_skip_list.c 4 | test_bignum.c test_dijkstra.c test_prime.c test_hash_table.c 5 | test_kmp.c test_bm.c test_sunday.c test_trie.c test_ac.c test_text.c 6 | test_huffman.c test_distance.c test_vector.c) 7 | target_compile_options(testcases PRIVATE ${COMPILE_OPTIONS}) 8 | target_include_directories(testcases PRIVATE ${INCLUDE_DIRECTORIES}) 9 | -------------------------------------------------------------------------------- /test/alloc-testing.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005-2008, Simon Howard 3 | Permission to use, copy, modify, and/or distribute this software 4 | for any purpose with or without fee is hereby granted, provided 5 | that the above copyright notice and this permission notice appear 6 | in all copies. 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 8 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 10 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 11 | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 13 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #define ALLOC_TESTING_C 24 | 25 | #include "alloc-testing.h" 26 | 27 | /* All allocated blocks are given this magic number */ 28 | 29 | #define ALLOC_TEST_MAGIC 0x72ec82d2 30 | 31 | /* This value is written to memory after it is freshly allocated, to ensure 32 | * that code under test does not rely on memory being initialised by 33 | * malloc(). */ 34 | 35 | #define MALLOC_PATTERN 0xBAADF00D 36 | 37 | /* This value is written to memory after it is freed, to ensure that code 38 | * does not rely on memory that has been freed. */ 39 | 40 | #define FREE_PATTERN 0xDEADBEEF 41 | 42 | /** 43 | * All blocks allocated by the testing framework are preceded by a structure 44 | * of this type. 45 | */ 46 | 47 | typedef struct _BlockHeader BlockHeader; 48 | 49 | struct _BlockHeader { 50 | unsigned int magic_number; 51 | size_t bytes; 52 | }; 53 | 54 | /* Count of the current number of allocated bytes. */ 55 | 56 | static size_t allocated_bytes = 0; 57 | 58 | /* Limit on number of allocations that are possible. Each time an allocation 59 | * is made, this is decremented. When it reaches zero, no more allocations 60 | * are allowed. If this has a negative value, the limit is disabled. */ 61 | 62 | signed int allocation_limit = -1; 63 | 64 | /* Get the block header for an allocated pointer. */ 65 | 66 | static BlockHeader *alloc_test_get_header(void *ptr) 67 | { 68 | BlockHeader *result; 69 | 70 | /* Go back from the start of the memory block to get the header. */ 71 | 72 | result = ((BlockHeader *)ptr) - 1; 73 | 74 | assert(result->magic_number == ALLOC_TEST_MAGIC); 75 | 76 | return result; 77 | } 78 | 79 | /* Overwrite a block of memory with a repeated pattern. */ 80 | 81 | static void alloc_test_overwrite(void *ptr, size_t length, unsigned int pattern) 82 | { 83 | unsigned char *byte_ptr; 84 | int pattern_seq; 85 | unsigned char b; 86 | size_t i; 87 | 88 | byte_ptr = ptr; 89 | 90 | for (i = 0; i < length; ++i) { 91 | pattern_seq = (int)(i & 3); 92 | b = (unsigned char)((pattern >> (8 * pattern_seq)) & 0xff); 93 | byte_ptr[i] = b; 94 | } 95 | } 96 | 97 | /* Base malloc function used by other functions. */ 98 | 99 | void *alloc_test_malloc(size_t bytes) 100 | { 101 | BlockHeader *header; 102 | void *ptr; 103 | 104 | /* Check if we have reached the allocation limit. */ 105 | 106 | if (allocation_limit == 0) { 107 | return NULL; 108 | } 109 | 110 | /* Allocate the requested block with enough room for the block header 111 | * as well. */ 112 | 113 | header = malloc(sizeof(BlockHeader) + bytes); 114 | 115 | if (header == NULL) { 116 | return NULL; 117 | } 118 | 119 | header->magic_number = ALLOC_TEST_MAGIC; 120 | header->bytes = bytes; 121 | 122 | /* Fill memory with MALLOC_PATTERN, to ensure that code under test 123 | * does not rely on memory being initialised to zero. */ 124 | 125 | ptr = header + 1; 126 | alloc_test_overwrite(ptr, bytes, MALLOC_PATTERN); 127 | 128 | /* Update counter */ 129 | 130 | allocated_bytes += bytes; 131 | 132 | /* Decrease the allocation limit */ 133 | 134 | if (allocation_limit > 0) { 135 | --allocation_limit; 136 | } 137 | 138 | /* Skip past the header and return the block itself */ 139 | 140 | return header + 1; 141 | } 142 | 143 | /* Base free function */ 144 | 145 | void alloc_test_free(void *ptr) 146 | { 147 | BlockHeader *header; 148 | size_t block_size; 149 | 150 | /* Must accept NULL as a valid pointer to free. */ 151 | 152 | if (ptr == NULL) { 153 | return; 154 | } 155 | 156 | /* Get the block header and do a sanity check */ 157 | 158 | header = alloc_test_get_header(ptr); 159 | block_size = header->bytes; 160 | assert(allocated_bytes >= block_size); 161 | 162 | /* Trash the allocated block to foil any code that relies on memory 163 | * that has been freed. */ 164 | 165 | alloc_test_overwrite(ptr, header->bytes, FREE_PATTERN); 166 | 167 | /* Trash the magic number in the block header to stop the same block 168 | * from being freed again. */ 169 | 170 | header->magic_number = 0; 171 | 172 | /* Free the allocated memory. */ 173 | 174 | free(header); 175 | 176 | /* Update counter */ 177 | 178 | allocated_bytes -= block_size; 179 | } 180 | 181 | void *alloc_test_realloc(void *ptr, size_t bytes) 182 | { 183 | BlockHeader *header; 184 | void *new_ptr; 185 | size_t bytes_to_copy; 186 | 187 | /* Allocate the new block */ 188 | 189 | new_ptr = alloc_test_malloc(bytes); 190 | 191 | if (new_ptr == NULL) { 192 | return NULL; 193 | } 194 | 195 | /* Copy over the old data and free the old block, if there was any. */ 196 | 197 | if (ptr != NULL) { 198 | header = alloc_test_get_header(ptr); 199 | 200 | bytes_to_copy = header->bytes; 201 | 202 | if (bytes_to_copy > bytes) { 203 | bytes_to_copy = bytes; 204 | } 205 | 206 | memcpy(new_ptr, ptr, bytes_to_copy); 207 | 208 | alloc_test_free(ptr); 209 | } 210 | 211 | return new_ptr; 212 | } 213 | 214 | void *alloc_test_calloc(size_t nmemb, size_t bytes) 215 | { 216 | void *result; 217 | size_t total_bytes = nmemb * bytes; 218 | 219 | /* Allocate the block. */ 220 | 221 | result = alloc_test_malloc(total_bytes); 222 | 223 | if (result == NULL) { 224 | return NULL; 225 | } 226 | 227 | /* Initialise to zero. */ 228 | 229 | memset(result, 0, total_bytes); 230 | 231 | return result; 232 | } 233 | 234 | char *alloc_test_strdup(const char *string) 235 | { 236 | char *result; 237 | 238 | result = alloc_test_malloc(strlen(string) + 1); 239 | 240 | if (result == NULL) { 241 | return NULL; 242 | } 243 | 244 | strcpy(result, string); 245 | 246 | return result; 247 | } 248 | 249 | void alloc_test_set_limit(signed int alloc_count) 250 | { 251 | allocation_limit = alloc_count; 252 | } 253 | 254 | size_t alloc_test_get_allocated(void) 255 | { 256 | return allocated_bytes; 257 | } -------------------------------------------------------------------------------- /test/alloc-testing.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005-2008, Simon Howard 3 | Permission to use, copy, modify, and/or distribute this software 4 | for any purpose with or without fee is hereby granted, provided 5 | that the above copyright notice and this permission notice appear 6 | in all copies. 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 8 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 9 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 10 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 11 | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 13 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 | CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /** 18 | * @file alloc-testing.h 19 | * 20 | * @brief Memory allocation testing framework. 21 | * 22 | * This file uses the preprocessor to redefine the standard C dynamic memory 23 | * allocation functions for testing purposes. This allows checking that 24 | * code under test correctly frees back all memory allocated, as well as 25 | * the ability to impose artificial limits on allocation, to test that 26 | * code correctly handles out-of-memory scenarios. 27 | */ 28 | 29 | #ifndef ALLOC_TESTING_H 30 | #define ALLOC_TESTING_H 31 | 32 | #include 33 | 34 | /* Don't redefine the functions in the alloc-testing.c, as we need the 35 | * standard malloc/free functions. */ 36 | 37 | #ifndef ALLOC_TESTING_C 38 | #undef malloc 39 | #define malloc alloc_test_malloc 40 | #undef free 41 | #define free alloc_test_free 42 | #undef realloc 43 | #define realloc alloc_test_realloc 44 | #undef calloc 45 | #define calloc alloc_test_calloc 46 | #undef strdup 47 | #define strdup alloc_test_strdup 48 | #endif 49 | 50 | /** 51 | * Allocate a block of memory. 52 | * 53 | * @param bytes Number of bytes to allocate. 54 | * @return Pointer to the new block, or NULL if it was not 55 | * possible to allocate the new block. 56 | */ 57 | 58 | void *alloc_test_malloc(size_t bytes); 59 | 60 | /** 61 | * Free a block of memory. 62 | * 63 | * @param ptr Pointer to the block to free. 64 | */ 65 | 66 | void alloc_test_free(void *ptr); 67 | 68 | /** 69 | * Reallocate a previously-allocated block to a new size, preserving 70 | * contents. 71 | * 72 | * @param ptr Pointer to the existing block. 73 | * @param bytes Size of the new block, in bytes. 74 | * @return Pointer to the new block, or NULL if it was not 75 | * possible to allocate the new block. 76 | */ 77 | 78 | void *alloc_test_realloc(void *ptr, size_t bytes); 79 | 80 | /** 81 | * Allocate a block of memory for an array of structures, initialising 82 | * the contents to zero. 83 | * 84 | * @param nmemb Number of structures to allocate for. 85 | * @param bytes Size of each structure, in bytes. 86 | * @return Pointer to the new memory block for the array, 87 | * or NULL if it was not possible to allocate the 88 | * new block. 89 | */ 90 | 91 | void *alloc_test_calloc(size_t nmemb, size_t bytes); 92 | 93 | /** 94 | * Allocate a block of memory containing a copy of a string. 95 | * 96 | * @param string The string to copy. 97 | * @return Pointer to the new memory block containing the 98 | * copied string, or NULL if it was not possible 99 | * to allocate the new block. 100 | */ 101 | 102 | char *alloc_test_strdup(const char *string); 103 | 104 | /** 105 | * Set an artificial limit on the amount of memory that can be 106 | * allocated. 107 | * 108 | * @param alloc_count Number of allocations that are possible after 109 | * this call. For example, if this has a value 110 | * of 3, malloc() can be called successfully 111 | * three times, but all allocation attempts 112 | * after this will fail. If this has a negative 113 | * value, the allocation limit is disabled. 114 | */ 115 | 116 | void alloc_test_set_limit(signed int alloc_count); 117 | 118 | /** 119 | * Get a count of the number of bytes currently allocated. 120 | * 121 | * @return The number of bytes currently allocated by 122 | * the allocation system. 123 | */ 124 | 125 | size_t alloc_test_get_allocated(void); 126 | 127 | #endif /* #ifndef ALLOC_TESTING_H */ -------------------------------------------------------------------------------- /test/test_ac.c: -------------------------------------------------------------------------------- 1 | #include "ac.h" 2 | #include "text.h" 3 | #include "hash_table.h" 4 | #include "arraylist.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "alloc-testing.h" 11 | #include "test_helper.h" 12 | 13 | static int ac_trie_insert_str(ACTrie *trie, const char *str) 14 | { 15 | return ac_trie_insert(trie, str, strlen(str)); 16 | } 17 | 18 | // static ACTrieNode *ac_trie_find_str(ACTrie *trie, const char *str) 19 | // { 20 | // return ac_trie_last_node(trie, str, strlen(str)); 21 | // } 22 | 23 | static int ac_trie_delete_str(ACTrie *trie, const char *str) 24 | { 25 | return ac_trie_delete(trie, str, strlen(str)); 26 | } 27 | 28 | static HashTable *ac_trie_matct_str(ACTrie *trie, const char *str) 29 | { 30 | return ac_trie_match(trie, str, strlen(str)); 31 | } 32 | 33 | void test_ac_trie_free() 34 | { 35 | ACTrie *trie = ac_trie_new(); 36 | ac_trie_insert_str(trie, "hello"); 37 | HashTableEntity *entity = hash_table_first_entity(trie->root->children); 38 | assert(entity != NULL); 39 | ASSERT_CHAR_EQ(*((char *)entity->key), 'h'); 40 | ac_trie_free(trie); 41 | } 42 | 43 | void test_ac_trie_insert() 44 | { 45 | ACTrie *trie = ac_trie_new(); 46 | 47 | ac_trie_insert_str(trie, "hello"); 48 | ac_trie_insert_str(trie, "hifi"); 49 | ac_trie_insert_str(trie, "hi world"); 50 | ac_trie_insert_str(trie, "here"); 51 | ac_trie_insert_str(trie, "heroine"); 52 | ac_trie_insert_str(trie, "legend"); 53 | ac_trie_insert_str(trie, "kelly"); 54 | 55 | // ACTrieNode *node; 56 | // HashTable *children; 57 | // node = ac_trie_find_str(trie, "he"); 58 | // ASSERT_CHAR_EQ(node->data, 'e'); 59 | // children = node->children; 60 | // ASSERT_INT_EQ(hash_table_size(children), 2); 61 | 62 | assert(ac_trie_delete_str(trie, "legend") == 0); 63 | 64 | ac_trie_free(trie); 65 | } 66 | 67 | void test_ac_trie_match_simple() 68 | { 69 | ACTrie *trie = ac_trie_new(); 70 | ac_trie_insert_str(trie, "li"); 71 | ac_trie_insert_str(trie, "she"); 72 | ac_trie_insert_str(trie, "her"); 73 | ac_trie_set_failure(trie); 74 | HashTable *match_table = ac_trie_matct_str(trie, "lisherliso"); 75 | ASSERT_INT_EQ(hash_table_size(match_table), 3); 76 | 77 | Text *key = text_from("li"); 78 | ArrayList *match = (ArrayList *)hash_table_get(match_table, key); 79 | ASSERT_INT_EQ(match->length, 2); 80 | // ASSERT_INT_POINTER_EQ(match->data[0], 4); 81 | 82 | text_free(key); 83 | hash_table_free(match_table); 84 | ac_trie_free(trie); 85 | } 86 | 87 | void test_ac_trie_match() 88 | { 89 | ACTrie *trie = ac_trie_new(); 90 | 91 | ac_trie_insert_str(trie, "hello"); 92 | ac_trie_insert_str(trie, "hifi"); 93 | ac_trie_insert_str(trie, "her"); 94 | ac_trie_insert_str(trie, "era"); 95 | ac_trie_insert_str(trie, "eraser"); 96 | 97 | ac_trie_set_failure(trie); 98 | // ASSERT_INT_EQ(ac_trie_matct_str(trie, "let, hello, hereaser herine."), 5); 99 | HashTable *match_table = ac_trie_matct_str(trie, "let, hello, hereaser herine. helloherahelloheraserhihhh."); 100 | ASSERT_INT_EQ(hash_table_size(match_table), 4); 101 | 102 | /** hello: 3 her: 4 era: 2 eraser: 1 */ 103 | Text *hello = text_from("hello"); 104 | Text *her = text_from("her"); 105 | Text *era = text_from("era"); 106 | Text *eraser = text_from("eraser"); 107 | ArrayList *match; 108 | match = (ArrayList *)hash_table_get(match_table, hello); 109 | ASSERT_INT_EQ(match->length, 3); 110 | ASSERT_INT_POINTER_EQ(match->data[0], 5); 111 | 112 | match = (ArrayList *)hash_table_get(match_table, her); 113 | ASSERT_INT_EQ(match->length, 4); 114 | ASSERT_INT_POINTER_EQ(match->data[0], 12); 115 | 116 | match = (ArrayList *)hash_table_get(match_table, era); 117 | ASSERT_INT_EQ(match->length, 2); 118 | 119 | match = (ArrayList *)hash_table_get(match_table, eraser); 120 | ASSERT_INT_EQ(match->length, 1); 121 | 122 | text_free(hello); 123 | text_free(her); 124 | text_free(era); 125 | text_free(eraser); 126 | 127 | hash_table_free(match_table); 128 | ac_trie_free(trie); 129 | } 130 | 131 | void test_ac() 132 | { 133 | test_ac_trie_free(); 134 | test_ac_trie_insert(); 135 | test_ac_trie_match_simple(); 136 | test_ac_trie_match(); 137 | } 138 | -------------------------------------------------------------------------------- /test/test_arraylist.c: -------------------------------------------------------------------------------- 1 | #include "arraylist.h" 2 | #include 3 | #include 4 | 5 | #include "alloc-testing.h" 6 | #include "test_helper.h" 7 | 8 | void test_arraylist() 9 | { 10 | ArrayList *arraylist; 11 | int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; 12 | 13 | arraylist = arraylist_new(NULL, 3); 14 | arraylist_append(arraylist, &values[0]); 15 | arraylist_append(arraylist, &values[1]); 16 | 17 | assert(arraylist->length == 2); 18 | assert(arraylist->_allocated = 3); 19 | 20 | assert(arraylist->data[0] == &values[0]); 21 | assert(arraylist->data[1] == &values[1]); 22 | 23 | arraylist_prepend(arraylist, &values[2]); 24 | arraylist_prepend(arraylist, &values[3]); 25 | 26 | assert(arraylist->length == 4); 27 | assert(arraylist->_allocated = 6); 28 | assert(arraylist->data[0] == &values[3]); 29 | assert(arraylist->data[1] == &values[2]); 30 | assert(arraylist->data[2] == &values[0]); 31 | assert(arraylist->data[3] == &values[1]); 32 | 33 | arraylist_push(arraylist, &values[4]); 34 | arraylist_push(arraylist, &values[5]); 35 | arraylist_push(arraylist, &values[6]); 36 | 37 | assert(arraylist->length == 7); 38 | assert(arraylist->data[arraylist->length - 1] == &values[6]); 39 | 40 | assert(arraylist_pop(arraylist) == &values[6]); 41 | assert(arraylist->length == 6); 42 | assert(arraylist_pop(arraylist) == &values[5]); 43 | assert(arraylist_pop(arraylist) == &values[4]); 44 | assert(arraylist_pop(arraylist) == &values[1]); 45 | assert(arraylist->length == 3); 46 | 47 | arraylist_free(arraylist); 48 | } 49 | 50 | void test_arraylist_index_of(void) 51 | { 52 | int entries[] = {89, 4, 23, 42, 16, 15, 8, 99, 50, 30}; 53 | int num_entries = sizeof(entries) / sizeof(int); 54 | ArrayList *arraylist = arraylist_new(NULL, num_entries); 55 | 56 | for (int i = 0; i < num_entries; ++i) { 57 | arraylist_append(arraylist, &entries[i]); 58 | } 59 | 60 | for (int i = 0; i < num_entries; ++i) { 61 | assert(arraylist_index_of(arraylist, int_compare, &entries[i]) == i); 62 | } 63 | 64 | arraylist_free(arraylist); 65 | } 66 | 67 | void test_arraylist_sort(void) 68 | { 69 | int entries[] = {89, 4, 23, 42, 4, 16, 15, 4, 8, 99, 50, 30, 4}; 70 | int sorted[] = {4, 4, 4, 4, 8, 15, 16, 23, 30, 42, 50, 89, 99}; 71 | unsigned int num_entries = sizeof(entries) / sizeof(int); 72 | 73 | ArrayList *arraylist = arraylist_new(NULL, num_entries); 74 | 75 | for (int i = 0; i < num_entries; ++i) { 76 | arraylist_prepend(arraylist, &entries[i]); 77 | } 78 | 79 | arraylist_sort(arraylist, int_compare); 80 | assert(arraylist->length == num_entries); 81 | 82 | for (int i = 0; i < num_entries; ++i) { 83 | int *value; 84 | 85 | value = (int *)arraylist->data[i]; 86 | // printf("=== [%d],[%d]===\n", *value, sorted[i]); 87 | assert(*value == sorted[i]); 88 | } 89 | 90 | arraylist_free(arraylist); 91 | } 92 | -------------------------------------------------------------------------------- /test/test_avltree.c: -------------------------------------------------------------------------------- 1 | #include "avltree.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | AVLTree *create_avl_tree(int size) 10 | { 11 | AVLTree *tree = avl_tree_new(int_compare, free, NULL); 12 | // int arr[] = {5, 6, 3, 2, 8, 1, 4, 0, 9, 7}; 13 | 14 | for (int i = 0; i < size; ++i) { 15 | int *key = intdup(i); 16 | int *value = key; 17 | assert(avl_tree_insert(tree, key, value)); 18 | } 19 | 20 | return tree; 21 | } 22 | 23 | void test_avltree_insert() 24 | { 25 | AVLTree *tree = create_avl_tree(100); 26 | 27 | unsigned int height = avl_tree_subtree_height(tree->root); 28 | assert(height <= 7); 29 | 30 | avl_tree_free(tree); 31 | } 32 | 33 | void test_avltree_delete() 34 | { 35 | AVLTree *tree = create_avl_tree(10); 36 | 37 | int *key = intdup(7); 38 | AVLTreeNode *node = avl_tree_find_node(tree, key); 39 | assert(int_equal(node->key, key)); 40 | 41 | AVLTreeNode *removed = avl_tree_remove_node(tree, node); 42 | assert(removed == node); 43 | assert(tree->num_nodes == 9); 44 | 45 | // printf("root => [%d]\n", *((int *)tree->root->key)); 46 | unsigned int height = avl_tree_subtree_height(tree->root); 47 | assert(height <= 3); 48 | // avl_tree_subtree_print(tree->root, height); 49 | 50 | free(key); 51 | avl_tree_free_node(tree, removed); 52 | avl_tree_free(tree); 53 | } 54 | 55 | void test_avltree_print() 56 | { 57 | AVLTree *tree = create_avl_tree(100); 58 | 59 | printf("root => [%d]\n", *((int *)tree->root->key)); 60 | unsigned int height = avl_tree_subtree_height(tree->root); 61 | avl_tree_subtree_print(tree->root, height); 62 | 63 | avl_tree_free(tree); 64 | } 65 | 66 | void test_avltree() 67 | { 68 | test_avltree_insert(); 69 | test_avltree_delete(); 70 | // test_avltree_print(); 71 | } 72 | -------------------------------------------------------------------------------- /test/test_bignum.c: -------------------------------------------------------------------------------- 1 | #include "bignum.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "alloc-testing.h" 8 | #include "test_helper.h" 9 | 10 | void test_bignum() 11 | { 12 | char num[100]; 13 | 14 | strcpy(num, "0000000"); 15 | assert(bignum_int_sanitize(num) == Positive); 16 | assert(strcmp(num, "0") == 0); 17 | 18 | strcpy(num, "0000123400"); 19 | assert(bignum_int_sanitize(num) == Positive); 20 | assert(strcmp(num, "123400") == 0); 21 | 22 | strcpy(num, "+0000123400 "); 23 | assert(bignum_int_sanitize(num) == Positive); 24 | assert(strcmp(num, "123400") == 0); 25 | 26 | strcpy(num, " +0000123400 "); 27 | assert(bignum_int_sanitize(num) == Positive); 28 | assert(strcmp(num, "123400") == 0); 29 | 30 | strcpy(num, "-0000000"); 31 | assert(bignum_int_sanitize(num) == Negative); 32 | assert(strcmp(num, "0") == 0); 33 | 34 | strcpy(num, "-0000123400"); 35 | assert(bignum_int_sanitize(num) == Negative); 36 | assert(strcmp(num, "123400") == 0); 37 | 38 | strcpy(num, "-0000123400 "); 39 | assert(bignum_int_sanitize(num) == Negative); 40 | assert(strcmp(num, "123400") == 0); 41 | 42 | strcpy(num, " -0000123400 "); 43 | assert(bignum_int_sanitize(num) == Negative); 44 | assert(strcmp(num, "123400") == 0); 45 | 46 | strcpy(num, " A-0000123400 "); 47 | assert(bignum_int_sanitize(num) == NaN); 48 | assert(strcmp(num, "0") == 0); 49 | 50 | strcpy(num, ""); 51 | assert(bignum_int_sanitize(num) == NaN); 52 | assert(strcmp(num, "0") == 0); 53 | 54 | strcpy(num, "ABC"); 55 | assert(bignum_int_sanitize(num) == NaN); 56 | assert(strcmp(num, "0") == 0); 57 | 58 | strcpy(num, "+-123"); 59 | assert(bignum_int_sanitize(num) == NaN); 60 | assert(strcmp(num, "0") == 0); 61 | } 62 | 63 | void test_bignum_int_addition() 64 | { 65 | char sum[100]; 66 | assert(bignum_int_addition("123", "123", sum) > 0); 67 | assert(strcmp(sum, "246") == 0); 68 | 69 | assert(bignum_int_addition("55555", "999999999976", sum) > 0); 70 | assert(strcmp(sum, "1000000055531") == 0); 71 | 72 | assert(bignum_int_addition("1111", "111", sum) > 0); 73 | assert(strcmp(sum, "1222") == 0); 74 | 75 | assert(bignum_int_addition("0", "0", sum) > 0); 76 | assert(strcmp(sum, "0") == 0); 77 | 78 | assert(bignum_int_addition("0", "121", sum) > 0); 79 | assert(strcmp(sum, "121") == 0); 80 | } 81 | 82 | void test_bignum_int_subtraction() 83 | { 84 | char diff[100]; 85 | assert(bignum_int_subtraction("123", "123", diff) > 0); 86 | assert(strcmp(diff, "0") == 0); 87 | 88 | assert(bignum_int_subtraction("246", "123", diff) > 0); 89 | assert(strcmp(diff, "123") == 0); 90 | 91 | assert(bignum_int_subtraction("1234", "456", diff) > 0); 92 | assert(strcmp(diff, "778") == 0); 93 | 94 | assert(bignum_int_subtraction("0", "0", diff) > 0); 95 | assert(strcmp(diff, "0") == 0); 96 | 97 | assert(bignum_int_subtraction("999999999976", "99999", diff) > 0); 98 | assert(strcmp(diff, "999999899977") == 0); 99 | 100 | assert(bignum_int_subtraction("99999", "999999999976", diff) < 0); 101 | assert(strcmp(diff, "999999899977") == 0); 102 | } 103 | 104 | void test_bignum_int_multiplication() 105 | { 106 | char prod[100]; 107 | assert(bignum_int_multiplication("1", "1", prod) > 0); 108 | assert(strcmp(prod, "1") == 0); 109 | 110 | assert(bignum_int_multiplication("245", "121", prod) > 0); 111 | assert(strcmp(prod, "29645") == 0); 112 | 113 | assert(bignum_int_multiplication("3456789", "121", prod) > 0); 114 | assert(strcmp(prod, "418271469") == 0); 115 | 116 | assert(bignum_int_multiplication("0", "0", prod) > 0); 117 | assert(strcmp(prod, "0") == 0); 118 | } 119 | 120 | void test_bignum_int_division() 121 | { 122 | char quotient[100]; 123 | char remainder[100]; 124 | assert(bignum_int_division("1", "1", quotient, remainder) > 0); 125 | assert(strcmp(quotient, "1") == 0); 126 | assert(strcmp(remainder, "0") == 0); 127 | 128 | assert(bignum_int_division("123", "12345", quotient, remainder) > 0); 129 | assert(strcmp(quotient, "0") == 0); 130 | assert(strcmp(remainder, "123") == 0); 131 | 132 | assert(bignum_int_division("123456789", "123", quotient, remainder) > 0); 133 | assert(strcmp(quotient, "1003713") == 0); 134 | assert(strcmp(remainder, "90") == 0); 135 | 136 | assert(bignum_int_division("123456789", "456", quotient, remainder) > 0); 137 | assert(strcmp(quotient, "270738") == 0); 138 | assert(strcmp(remainder, "261") == 0); 139 | 140 | assert(bignum_int_division("0", "12345", quotient, remainder) > 0); 141 | assert(strcmp(quotient, "0") == 0); 142 | assert(strcmp(remainder, "0") == 0); 143 | 144 | assert(bignum_int_division("0", "0", quotient, remainder) > 0); 145 | assert(strcmp(quotient, "NaN") == 0); 146 | assert(bignum_int_division("123", "0", quotient, remainder) > 0); 147 | assert(strcmp(quotient, "NaN") == 0); 148 | } 149 | -------------------------------------------------------------------------------- /test/test_bm.c: -------------------------------------------------------------------------------- 1 | #include "bm.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | extern void 10 | bm_calculate_bad_chars(const char *pattern, int len, int *bad_chars); 11 | extern void 12 | bm_calculate_good_suffixes(const char *pattern, int len, int *good_suffixes); 13 | 14 | void test_bm_calculate_bad_chars() 15 | { 16 | int bad_chars[256]; 17 | bm_calculate_bad_chars("abcdcdddf", 9, bad_chars); 18 | assert(bad_chars[0] == -1); 19 | 20 | assert(bad_chars['a'] == 0); 21 | assert(bad_chars['b'] == 1); 22 | assert(bad_chars['c'] == 4); 23 | assert(bad_chars['d'] == 7); 24 | assert(bad_chars['e'] == -1); 25 | assert(bad_chars['f'] == 8); 26 | } 27 | 28 | void test_bm_calculate_good_suffixes() 29 | { 30 | int good_suffixes[100]; 31 | 32 | bm_calculate_good_suffixes("abcd", 4, good_suffixes); 33 | assert(good_suffixes[0] == -1); 34 | assert(good_suffixes[1] == -1); 35 | assert(good_suffixes[2] == -1); 36 | assert(good_suffixes[3] == -1); 37 | assert(good_suffixes[4] == -1); 38 | 39 | bm_calculate_good_suffixes("aaaa", 4, good_suffixes); 40 | assert(good_suffixes[0] == -1); 41 | assert(good_suffixes[1] == 2); 42 | assert(good_suffixes[2] == 1); 43 | assert(good_suffixes[3] == 0); 44 | assert(good_suffixes[4] == -1); 45 | 46 | bm_calculate_good_suffixes("ababa", 5, good_suffixes); 47 | assert(good_suffixes[0] == -1); 48 | assert(good_suffixes[1] == 2); 49 | assert(good_suffixes[2] == 1); 50 | assert(good_suffixes[3] == 0); 51 | assert(good_suffixes[4] == -1); 52 | assert(good_suffixes[5] == -1); 53 | 54 | bm_calculate_good_suffixes("baaa", 4, good_suffixes); 55 | assert(good_suffixes[0] == -1); 56 | assert(good_suffixes[1] == 2); 57 | assert(good_suffixes[2] == 1); 58 | assert(good_suffixes[3] == -1); 59 | assert(good_suffixes[4] == -1); 60 | } 61 | 62 | void test_bm_string_match() 63 | { 64 | assert(bm_string_match("abcabc", "abc") == 0); 65 | assert(bm_string_match("abcabc", "abcd") == -1); 66 | assert(bm_string_match("abcabcd", "abcd") == 3); 67 | assert(bm_string_match("bcabaaaa", "aaaa") == 4); 68 | assert(bm_string_match("bcabaaabaaaa", "aaaa") == 8); 69 | 70 | ASSERT_INT_EQ(bm_string_match("bbcabcdababcdabcdabde", "abcdabd"), 13); 71 | ASSERT_INT_EQ(bm_string_match("here is a simple example", "example"), 17); 72 | 73 | ASSERT_INT_EQ(bm_string_match("abcaacbabbacab", "abcbab"), -1); 74 | ASSERT_INT_EQ(bm_string_match("abbadcababacab", "babac"), 7); 75 | 76 | ASSERT_INT_EQ(bm_string_match("aaaaaaaaaaaaaaaa", "baaa"), -1); 77 | ASSERT_INT_EQ(bm_string_match("abcacabcbcbacabc", "cbacabc"), 9); 78 | 79 | ASSERT_INT_EQ(bm_string_match("ababcabcabcabc", "abcabcabc"), 2); 80 | ASSERT_INT_EQ(bm_string_match("aaaabaaaaaaaaa", "baaaaaaaaa"), 4); 81 | } 82 | 83 | void test_bm() 84 | { 85 | test_bm_calculate_bad_chars(); 86 | test_bm_calculate_good_suffixes(); 87 | test_bm_string_match(); 88 | } 89 | -------------------------------------------------------------------------------- /test/test_bstree.c: -------------------------------------------------------------------------------- 1 | #include "bstree.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | typedef struct _CBValue { 10 | void *data[100]; 11 | int index; 12 | int length; 13 | } CBValue; 14 | static void bs_tree_traverse_callback(BSTreeNode *node, void *args) 15 | { 16 | CBValue *value = (CBValue *)args; 17 | value->data[(value->index)++] = node->data; 18 | } 19 | 20 | // static void bs_tree_traverse_print(BSTreeNode *node, void *args) 21 | // { 22 | // printf("%d, ", *((int *)node->data)); 23 | // } 24 | 25 | void test_bstree() 26 | { 27 | int entries[] = {38, 23, 42, 4, 16, 15, 8, 99, 50, 30}; 28 | int sorted[] = {4, 8, 15, 16, 23, 30, 38, 42, 50, 99}; 29 | int num_entries = sizeof(entries) / sizeof(int); 30 | 31 | BSTree *tree = bs_tree_new(int_compare); 32 | BSTreeNode *node; 33 | for (int i = 0; i < num_entries; ++i) { 34 | node = bs_tree_insert(tree, &entries[i]); 35 | assert(int_equal(node->data, &entries[i])); 36 | } 37 | 38 | node = bs_tree_lookup_data(tree, &entries[3]); 39 | assert(int_equal(node->data, &entries[3])); 40 | 41 | CBValue cb; 42 | cb.index = 0; 43 | bs_tree_inorder_traverse(tree, bs_tree_traverse_callback, &cb); 44 | assert(cb.index == 10); 45 | for (int i = 0; i < num_entries; ++i) { 46 | // printf("%d ", *(int *)cb.data[i]); 47 | assert(int_equal(cb.data[i], &sorted[i])); 48 | } 49 | 50 | /** 51 | 38 52 | /\ 53 | 23 42 54 | /\ /\ 55 | 4 30 99 56 | /\ / 57 | 16 50 58 | / 59 | 15 60 | / 61 | 8 62 | */ 63 | // 38, 23, 42, 4, 16, 15, 8, 99, 50, 30 => 4 64 | node = bs_tree_remove_node(tree, bs_tree_lookup_data(tree, &entries[3])); 65 | free(node); 66 | // 38, 23, 42, 4, 16, 15, 8, 99, 50, 30 => 16 67 | node = bs_tree_remove_node(tree, bs_tree_lookup_data(tree, &entries[4])); 68 | free(node); 69 | // 38, 23, 42, 4, 16, 15, 8, 99, 50, 30 => 38 70 | node = bs_tree_remove_node(tree, bs_tree_lookup_data(tree, &entries[0])); 71 | free(node); 72 | 73 | // 8, 15, 23, 30, 42, 50, 99 74 | int remain[] = {8, 15, 23, 30, 42, 50, 99}; 75 | cb.index = 0; 76 | bs_tree_inorder_traverse(tree, bs_tree_traverse_callback, &cb); 77 | // printf("len === %d = %d ===\n", cb.index, tree->num_nodes); 78 | assert(cb.index == tree->num_nodes); 79 | for (int i = 0; i < tree->num_nodes; ++i) { 80 | // printf("%d ", *(int *)cb.data[i]); 81 | assert(int_equal(cb.data[i], &remain[i])); 82 | } 83 | 84 | bs_tree_free(tree); 85 | } 86 | 87 | void test_bstree_remove() 88 | { 89 | int entries[] = {38, 23, 42, 4, 16, 15, 8, 99, 50, 30, 90 | 2, 1, 3, 20, 120, 40, 39, 41, 45, 60}; 91 | 92 | int num_entries = sizeof(entries) / sizeof(int); 93 | 94 | BSTree *tree = bs_tree_new(int_compare); 95 | BSTreeNode *node; 96 | for (int i = 0; i < num_entries; ++i) { 97 | node = bs_tree_insert(tree, &entries[i]); 98 | assert(int_equal(node->data, &entries[i])); 99 | } 100 | 101 | // 38, 23, 42, 4, 16, 15, 8, 99, 50, 30, 2, 1, 3, 20, 120, 40, 39, 41, 45, 102 | // 60 1, 2, 3, 4, 8, 15, 16, 20, 23, 30, 38, 39, 40, 41, 42, 45, 50, 60, 99, 103 | // 120 bs_tree_inorder_traverse(tree, bs_tree_traverse_print, NULL); 104 | // printf("\n==========\n"); 105 | 106 | /* 107 | 38 108 | /\ 109 | 23 42 110 | /\ /\ 111 | 4 30 40 99 112 | /\ /\ /\ 113 | 2 16 39 41 50 120 114 | /\ /\ /\ 115 | 1 3 15 20 45 60 116 | / 117 | 8 118 | */ 119 | 120 | for (int i = 2; i < num_entries; i += 3) { 121 | node = 122 | bs_tree_remove_node(tree, bs_tree_lookup_data(tree, &entries[i])); 123 | free(node); 124 | } 125 | // bs_tree_inorder_traverse(tree, bs_tree_traverse_print, NULL); 126 | // printf("\n==========\n"); 127 | 128 | for (int i = 0; i < num_entries; i += 3) { 129 | node = 130 | bs_tree_remove_node(tree, bs_tree_lookup_data(tree, &entries[i])); 131 | free(node); 132 | } 133 | // bs_tree_inorder_traverse(tree, bs_tree_traverse_print, NULL); 134 | // printf("\n==========\n"); 135 | 136 | for (int i = 1; i < num_entries; i += 3) { 137 | node = 138 | bs_tree_remove_node(tree, bs_tree_lookup_data(tree, &entries[i])); 139 | free(node); 140 | } 141 | // bs_tree_inorder_traverse(tree, bs_tree_traverse_print, NULL); 142 | // printf("\n==========\n"); 143 | 144 | assert(tree->num_nodes == 0); 145 | bs_tree_free(tree); 146 | } 147 | -------------------------------------------------------------------------------- /test/test_dijkstra.c: -------------------------------------------------------------------------------- 1 | #include "dijkstra.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | static int max_in_array(int *distances, int num) 10 | { 11 | int max = -1; 12 | for (int i = 0; i < num; ++i) { 13 | if (distances[i] < 0) { 14 | max = -1; 15 | break; 16 | } else if (distances[i] > max) { 17 | max = distances[i]; 18 | } else { 19 | } 20 | } 21 | return max; 22 | } 23 | 24 | static void test_dijkstra_1() 25 | { 26 | AdjacencyMatrix *graph = adjacency_matrix_new(DirectedWeighted, 4); 27 | adjacency_matrix_reset(graph, -1); 28 | adjacency_matrix_set(graph, 1, 0, 1); 29 | adjacency_matrix_set(graph, 1, 2, 1); 30 | adjacency_matrix_set(graph, 2, 3, 1); 31 | int *distances = (int *)malloc(sizeof(int) * 4); 32 | 33 | dijkstra(graph, 1, distances); 34 | assert(max_in_array(distances, 4) == 2); 35 | 36 | free(distances); 37 | adjacency_matrix_free(graph); 38 | } 39 | 40 | static void test_dijkstra_2() 41 | { 42 | AdjacencyMatrix *graph = adjacency_matrix_new(DirectedWeighted, 2); 43 | adjacency_matrix_reset(graph, -1); 44 | adjacency_matrix_set(graph, 0, 1, 1); 45 | int *distances = (int *)malloc(sizeof(int) * 4); 46 | 47 | dijkstra(graph, 1, distances); 48 | assert(max_in_array(distances, 2) == -1); 49 | 50 | free(distances); 51 | adjacency_matrix_free(graph); 52 | } 53 | 54 | static void test_dijkstra_3() 55 | { 56 | AdjacencyMatrix *graph = adjacency_matrix_new(DirectedWeighted, 4); 57 | adjacency_matrix_reset(graph, -1); 58 | adjacency_matrix_set(graph, 0, 1, 1); 59 | adjacency_matrix_set(graph, 1, 2, 1); 60 | adjacency_matrix_set(graph, 2, 3, 1); 61 | adjacency_matrix_set(graph, 3, 0, 1); 62 | int *distances = (int *)malloc(sizeof(int) * 4); 63 | 64 | dijkstra(graph, 1, distances); 65 | assert(max_in_array(distances, 4) == 3); 66 | 67 | free(distances); 68 | adjacency_matrix_free(graph); 69 | } 70 | 71 | static void test_dijkstra_4() 72 | { 73 | AdjacencyMatrix *graph = adjacency_matrix_new(DirectedWeighted, 4); 74 | adjacency_matrix_reset(graph, -1); 75 | adjacency_matrix_set(graph, 0, 1, 1); 76 | adjacency_matrix_set(graph, 1, 2, 1); 77 | adjacency_matrix_set(graph, 2, 3, 1); 78 | adjacency_matrix_set(graph, 0, 3, 1); 79 | int *distances = (int *)malloc(sizeof(int) * 4); 80 | 81 | dijkstra(graph, 0, distances); 82 | assert(max_in_array(distances, 4) == 2); 83 | 84 | free(distances); 85 | adjacency_matrix_free(graph); 86 | } 87 | 88 | static void test_dijkstra_5() 89 | { 90 | AdjacencyMatrix *graph = adjacency_matrix_new(DirectedWeighted, 3); 91 | adjacency_matrix_reset(graph, -1); 92 | adjacency_matrix_set(graph, 0, 1, 1); 93 | adjacency_matrix_set(graph, 1, 2, 2); 94 | adjacency_matrix_set(graph, 0, 2, 2); 95 | int *distances = (int *)malloc(sizeof(int) * 3); 96 | 97 | dijkstra(graph, 0, distances); 98 | assert(max_in_array(distances, 3) == 2); 99 | 100 | free(distances); 101 | adjacency_matrix_free(graph); 102 | } 103 | 104 | void test_dijkstra() 105 | { 106 | test_dijkstra_1(); 107 | test_dijkstra_2(); 108 | test_dijkstra_3(); 109 | test_dijkstra_4(); 110 | test_dijkstra_5(); 111 | } 112 | 113 | // https://leetcode.com/problems/network-delay-time/ 114 | int networkDelayTime( 115 | int **times, int timesSize, int *timesColSize, int N, int K) 116 | { 117 | AdjacencyMatrix *graph = adjacency_matrix_new(DirectedWeighted, N + 1); 118 | int *distances = (int *)malloc(sizeof(int) * (N + 1)); 119 | adjacency_matrix_reset(graph, -1); 120 | 121 | for (int i = 0; i < timesSize; ++i) { 122 | adjacency_matrix_set(graph, times[i][0], times[i][1], times[i][2]); 123 | } 124 | 125 | dijkstra(graph, K, distances); 126 | int time = max_in_array(distances, N + 1); 127 | 128 | free(distances); 129 | adjacency_matrix_free(graph); 130 | return time; 131 | } 132 | -------------------------------------------------------------------------------- /test/test_distance.c: -------------------------------------------------------------------------------- 1 | #include "distance.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | void test_euclidiean_distance() 10 | { 11 | Vector *v1 = vector_new(2, 0.0, 1.0); 12 | Vector *v2 = vector_new(2, 3.0, 5.0); 13 | double distance = euclidiean_distance(v1, v2); 14 | ASSERT_DOUBLE_EQ(distance, 5.0, 0.0); 15 | vector_free(v1); 16 | vector_free(v2); 17 | } 18 | 19 | void test_distance() 20 | { 21 | test_euclidiean_distance(); 22 | } 23 | -------------------------------------------------------------------------------- /test/test_graph.c: -------------------------------------------------------------------------------- 1 | #include "graph.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | static AdjacencyMatrix *init_ud_uw_graph() 10 | { 11 | AdjacencyMatrix *graph = adjacency_matrix_new(UndirectedUnweighted, 10); 12 | adjacency_matrix_link(graph, 0, 1); 13 | adjacency_matrix_link(graph, 0, 2); 14 | adjacency_matrix_link(graph, 0, 3); 15 | adjacency_matrix_link(graph, 0, 4); 16 | adjacency_matrix_link(graph, 0, 5); 17 | 18 | adjacency_matrix_link(graph, 1, 2); 19 | adjacency_matrix_link(graph, 1, 3); 20 | adjacency_matrix_link(graph, 1, 4); 21 | adjacency_matrix_link(graph, 1, 5); 22 | adjacency_matrix_link(graph, 1, 6); 23 | 24 | adjacency_matrix_link(graph, 2, 3); 25 | adjacency_matrix_link(graph, 2, 4); 26 | adjacency_matrix_link(graph, 2, 5); 27 | adjacency_matrix_link(graph, 2, 6); 28 | adjacency_matrix_link(graph, 2, 7); 29 | 30 | adjacency_matrix_link(graph, 3, 4); 31 | adjacency_matrix_link(graph, 3, 5); 32 | adjacency_matrix_link(graph, 3, 6); 33 | adjacency_matrix_link(graph, 3, 7); 34 | 35 | adjacency_matrix_link(graph, 4, 5); 36 | adjacency_matrix_link(graph, 4, 6); 37 | adjacency_matrix_link(graph, 4, 7); 38 | 39 | adjacency_matrix_link(graph, 5, 6); 40 | adjacency_matrix_link(graph, 5, 7); 41 | 42 | adjacency_matrix_link(graph, 6, 7); 43 | 44 | adjacency_matrix_link(graph, 7, 8); 45 | 46 | return graph; 47 | } 48 | 49 | void test_graph_bfs() 50 | { 51 | AdjacencyMatrix *graph = init_ud_uw_graph(); 52 | ASSERT_INT_EQ(adjacency_matrix_bfs(graph, 0, 9), -1); 53 | ASSERT_INT_EQ(adjacency_matrix_bfs(graph, 0, 8), 0); 54 | adjacency_matrix_free(graph); 55 | } 56 | 57 | void test_graph_dfs() 58 | { 59 | AdjacencyMatrix *graph = init_ud_uw_graph(); 60 | ASSERT_INT_EQ(adjacency_matrix_dfs(graph, 0, 9), -1); 61 | ASSERT_INT_EQ(adjacency_matrix_dfs(graph, 0, 8), 0); 62 | adjacency_matrix_free(graph); 63 | } 64 | 65 | void test_graph() 66 | { 67 | test_graph_bfs(); 68 | test_graph_dfs(); 69 | } 70 | -------------------------------------------------------------------------------- /test/test_hash_table.c: -------------------------------------------------------------------------------- 1 | #include "hash.h" 2 | #include "hash_table.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "alloc-testing.h" 9 | #include "test_helper.h" 10 | 11 | void test_hash_table_string() 12 | { 13 | HashTable *hash_table = 14 | hash_table_new(hash_string, string_equal, free, free); 15 | char *key = strdup("abc"); 16 | char *value = strdup("efg"); 17 | assert(hash_table_insert(hash_table, key, value) == 0); 18 | // assert(hash_table->length == 1); 19 | assert(string_equal(hash_table_get(hash_table, key), value)); 20 | 21 | key = strdup("aaaa"); 22 | value = strdup("bbbb"); 23 | assert(hash_table_insert(hash_table, key, value) == 0); 24 | // assert(hash_table->length == 2); 25 | assert(string_equal(hash_table_get(hash_table, key), value)); 26 | 27 | value = strdup("new new"); 28 | assert(hash_table_set(hash_table, "abc", value) == 0); 29 | // assert(hash_table->length == 2); 30 | assert(string_equal(hash_table_get(hash_table, "abc"), value)); 31 | 32 | assert(hash_table_delete(hash_table, "abc") == 0); 33 | // assert(hash_table->length == 1); 34 | assert(hash_table_get(hash_table, "abc") == HASH_TABLE_VALUE_NULL); 35 | 36 | hash_table_free(hash_table); 37 | } 38 | 39 | void test_hash_table_int() 40 | { 41 | HashTable *hash_table = hash_table_new(hash_int, int_equal, free, free); 42 | int *key = intdup(1); 43 | int *value = intdup(2); 44 | assert(hash_table_insert(hash_table, key, value) == 0); 45 | // assert(hash_table->length == 1); 46 | assert(int_equal(hash_table_get(hash_table, key), value)); 47 | 48 | hash_table_free(hash_table); 49 | } 50 | 51 | #define MAX_TABLE_SIZE 10000 52 | 53 | void test_hash_table_enlarge() 54 | { 55 | char buf[10]; 56 | HashTable *hash_table = 57 | hash_table_new(hash_string, string_equal, free, NULL); 58 | for (int i = 0; i < MAX_TABLE_SIZE; ++i) { 59 | sprintf(buf, "%i", i); 60 | char *key = strdup(buf); 61 | char *value = key; 62 | 63 | assert(hash_table_insert(hash_table, key, value) == 0); 64 | } 65 | 66 | // ===hash_table size [10000], [16384], [4573] 67 | // printf("===hash_table size [%d], [%d], [%d]", 68 | // hash_table->length, 69 | // hash_table->_allocated, 70 | // hash_table->_collisions); 71 | // assert(hash_table->length == MAX_TABLE_SIZE); 72 | 73 | for (int i = 0; i < MAX_TABLE_SIZE; ++i) { 74 | sprintf(buf, "%i", i); 75 | assert(string_equal(hash_table_get(hash_table, buf), buf)); 76 | } 77 | 78 | hash_table_free(hash_table); 79 | } 80 | 81 | void test_hash_table_first_last() 82 | { 83 | HashTable *hash_table = hash_table_new(hash_int, int_equal, free, free); 84 | 85 | assert(hash_table_insert(hash_table, intdup(1), intdup(2)) == 0); 86 | assert(hash_table_insert(hash_table, intdup(3), intdup(4)) == 0); 87 | assert(hash_table_insert(hash_table, intdup(5), intdup(6)) == 0); 88 | ASSERT_INT_EQ(hash_table_size(hash_table), 3); 89 | 90 | int count = 0; 91 | for (HashTableEntity *iterator = hash_table_first_entity(hash_table); 92 | iterator != NULL; 93 | iterator = hash_table_next_entity(hash_table, iterator)) { 94 | ++count; 95 | } 96 | ASSERT_INT_EQ(count, 3); 97 | 98 | count = 0; 99 | for (HashTableEntity *iterator = hash_table_last_entity(hash_table); 100 | iterator != NULL; 101 | iterator = hash_table_prev_entity(hash_table, iterator)) { 102 | ++count; 103 | } 104 | ASSERT_INT_EQ(count, 3); 105 | 106 | /** this is forbidden!!! */ 107 | // for (HashTableEntity *iterator = hash_table_last_entity(hash_table); 108 | // iterator != NULL; 109 | // iterator = hash_table_prev_entity(hash_table, iterator)) { 110 | // hash_table_delete(hash_table, iterator->key); 111 | // } 112 | // ASSERT_INT_EQ(hash_table_size(hash_table), 0); 113 | 114 | HashTableEntity *iterator = hash_table_last_entity(hash_table); 115 | while (iterator != NULL) { 116 | HashTableEntity *prev = iterator; 117 | iterator = hash_table_prev_entity(hash_table, prev); 118 | hash_table_delete(hash_table, prev->key); 119 | } 120 | ASSERT_INT_EQ(hash_table_size(hash_table), 0); 121 | 122 | hash_table_free(hash_table); 123 | } 124 | 125 | void test_hash_table_iterate() 126 | { 127 | char buf[10]; 128 | HashTable *hash_table = 129 | hash_table_new(hash_string, string_equal, free, NULL); 130 | for (int i = 0; i < MAX_TABLE_SIZE; ++i) { 131 | sprintf(buf, "%i", i); 132 | char *key = strdup(buf); 133 | char *value = key; 134 | 135 | assert(hash_table_insert(hash_table, key, value) == 0); 136 | } 137 | ASSERT_INT_EQ(hash_table_size(hash_table), MAX_TABLE_SIZE); 138 | 139 | int count = 0; 140 | for (HashTableEntity *iterator = hash_table_first_entity(hash_table); 141 | iterator != NULL; 142 | iterator = hash_table_next_entity(hash_table, iterator)) { 143 | ++count; 144 | } 145 | ASSERT_INT_EQ(count, MAX_TABLE_SIZE); 146 | 147 | count = 0; 148 | for (HashTableEntity *iterator = hash_table_last_entity(hash_table); 149 | iterator != NULL; 150 | iterator = hash_table_prev_entity(hash_table, iterator)) { 151 | ++count; 152 | } 153 | ASSERT_INT_EQ(count, MAX_TABLE_SIZE); 154 | 155 | // HashTableEntity *iterator = hash_table_last_entity(hash_table); 156 | // while (iterator != NULL) 157 | // { 158 | // HashTableEntity *prev = iterator; 159 | // iterator = hash_table_prev_entity(hash_table, prev); 160 | // hash_table_delete(hash_table, prev->key); 161 | // } 162 | // ASSERT_INT_EQ(hash_table_size(hash_table), 0); 163 | 164 | hash_table_free(hash_table); 165 | } 166 | 167 | void test_hash_table() 168 | { 169 | test_hash_table_string(); 170 | test_hash_table_int(); 171 | test_hash_table_enlarge(); 172 | test_hash_table_first_last(); 173 | test_hash_table_iterate(); 174 | } 175 | -------------------------------------------------------------------------------- /test/test_heap.c: -------------------------------------------------------------------------------- 1 | #include "heap.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | void test_heap() 10 | { 11 | int arr[] = {19, 13, 5, 6, 14, 15, 20, 3, 2, 8, 12 | 1, 16, 17, 4, 10, 18, 9, 7, 11, 12}; 13 | Heap *heap = heap_new(MAX_HEAP, int_compare, NULL); 14 | 15 | int size = sizeof(arr) / sizeof(int); 16 | for (int i = 0; i < size; ++i) { 17 | assert(heap_insert(heap, &(arr[i])) == 0); 18 | } 19 | 20 | // HeapValue top = heap_pop(heap); 21 | // assert(*(int *)top == 20); 22 | // assert(heap->num_data == 19); 23 | 24 | for (int i = 20; i >= 1; --i) { 25 | assert(heap->num_data == i); 26 | assert(*(int *)heap_pop(heap) == i); 27 | } 28 | 29 | heap_free(heap); 30 | } 31 | -------------------------------------------------------------------------------- /test/test_helper.c: -------------------------------------------------------------------------------- 1 | #include "test_helper.h" 2 | #include 3 | #include 4 | 5 | #include "alloc-testing.h" 6 | 7 | #define SWAP(a, b, tmp) tmp=a; a=b; b=tmp; 8 | 9 | int string_equal(void *str1, void *str2) 10 | { 11 | return strcmp((char *)str1, (char *)str2) == 0; 12 | } 13 | 14 | int *generate_random_numbers(int from, int to) 15 | { 16 | int count = to - from + 1; 17 | int *arr = (int *)malloc(sizeof(int) * count); 18 | 19 | for (int i = 0; i < count; i++) { 20 | arr[i] = i + from; 21 | } 22 | 23 | int tmp; 24 | for (int i = 0; i < count; i++) { 25 | int j = rand()%count; 26 | SWAP(arr[i], arr[j], tmp); 27 | } 28 | 29 | return arr; 30 | } 31 | -------------------------------------------------------------------------------- /test/test_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef RETHINK_C_TEST_HELPER_H 2 | #define RETHINK_C_TEST_HELPER_H 3 | 4 | #include "compare.h" 5 | #include "dup.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef ALLOC_TESTING 13 | #include "alloc-testing.h" 14 | #endif 15 | 16 | #define ASSERT(cond, msg) \ 17 | if (!(cond)) { \ 18 | printf(msg); \ 19 | assert(0); \ 20 | } 21 | 22 | #define ASSERT_INT_EQ(a, b) \ 23 | if ((a) != (b)) { \ 24 | printf("\nassert: Left [%d] not equal to Right[%d]\n", a, b); \ 25 | assert(a == b); \ 26 | } 27 | 28 | static inline void assert_double_eq(double a, double b, double tolerance) 29 | { 30 | if (fabs(a - b) > tolerance) { 31 | printf("\nassert: Left [%f] not equal to Right[%f] with tolerance " 32 | "[%f] \n", 33 | a, 34 | b, 35 | tolerance); 36 | assert(0); 37 | } 38 | } 39 | 40 | #define ASSERT_DOUBLE_EQ assert_double_eq 41 | 42 | #define ASSERT_CHAR_EQ(a, b) \ 43 | if ((a) != (b)) { \ 44 | printf("\nassert: Left [%c] not equal to Right[%c]\n", a, b); \ 45 | assert(a == b); \ 46 | } 47 | 48 | #define ASSERT_STRING_EQ(a, b) \ 49 | if (strcmp(a, b) != 0) { \ 50 | printf("\nassert: Left [%s] not equal to Right[%s]\n", a, b); \ 51 | assert(0); \ 52 | } 53 | 54 | #define ASSERT_INT_POINTER_EQ(pointer, value) \ 55 | ASSERT_INT_EQ(*((int *)(pointer)), value) 56 | 57 | // inline int *intdup(int value) 58 | // { 59 | // int *dup = (int *)malloc(sizeof(int)); 60 | // *dup = value; 61 | // return dup; 62 | // } 63 | 64 | // inline int string_equal(void *str1, void *str2) 65 | // { 66 | // return strcmp((char *)str1, (char *)str2) == 0; 67 | // } 68 | 69 | int string_equal(void *str1, void *str2); 70 | 71 | int *generate_random_numbers(int from, int to); 72 | 73 | #endif /* RETHINK_C_TEST_HELPER_H */ 74 | -------------------------------------------------------------------------------- /test/test_kmp.c: -------------------------------------------------------------------------------- 1 | #include "kmp.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | extern int *kmp_calculate_next(const char *string, int len); 10 | 11 | void test_kmp_calculate_next() 12 | { 13 | int *next; 14 | 15 | next = kmp_calculate_next("abc", 3); 16 | assert(next[0] == 0); 17 | assert(next[1] == 0); 18 | assert(next[2] == 0); 19 | free(next); 20 | 21 | next = kmp_calculate_next("aaa", 3); 22 | assert(next[0] == 0); 23 | assert(next[1] == 1); 24 | assert(next[2] == 2); 25 | free(next); 26 | 27 | next = kmp_calculate_next("abababab", 8); 28 | assert(next[0] == 0); 29 | assert(next[1] == 0); 30 | assert(next[2] == 1); 31 | assert(next[3] == 2); 32 | assert(next[4] == 3); 33 | assert(next[5] == 4); 34 | assert(next[6] == 5); 35 | assert(next[7] == 6); 36 | free(next); 37 | 38 | next = kmp_calculate_next("abcdabd", 7); 39 | assert(next[0] == 0); 40 | assert(next[1] == 0); 41 | assert(next[2] == 0); 42 | assert(next[3] == 0); 43 | assert(next[4] == 1); 44 | assert(next[5] == 2); 45 | assert(next[6] == 0); 46 | free(next); 47 | 48 | next = kmp_calculate_next("abcabaaabcda", 12); 49 | assert(next[0] == 0); 50 | assert(next[1] == 0); 51 | assert(next[2] == 0); 52 | assert(next[3] == 1); 53 | assert(next[4] == 2); 54 | assert(next[5] == 1); 55 | assert(next[6] == 1); 56 | assert(next[7] == 1); 57 | assert(next[8] == 2); 58 | assert(next[9] == 3); 59 | assert(next[10] == 0); 60 | assert(next[11] == 1); 61 | free(next); 62 | } 63 | 64 | void test_kmp_string_match() 65 | { 66 | assert(kmp_string_match("abcabc", "abc") == 0); 67 | assert(kmp_string_match("abcabc", "abcd") < 0); 68 | assert(kmp_string_match("abcabcd", "abcd") == 3); 69 | assert(kmp_string_match("bcabaaaa", "aaaa") == 4); 70 | assert(kmp_string_match("bbcabcdababcdabcdabde", "abcdabd") == 13); 71 | } 72 | 73 | void test_kmp() 74 | { 75 | test_kmp_calculate_next(); 76 | test_kmp_string_match(); 77 | } 78 | -------------------------------------------------------------------------------- /test/test_list.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | void check_list_integrity(List *list) 10 | { 11 | ListNode *prev = NULL; 12 | ListNode *rover = list->head; 13 | int i = 0; 14 | 15 | while (rover != NULL) { 16 | assert(rover->prev == prev); 17 | prev = rover; 18 | rover = rover->next; 19 | ++i; 20 | } 21 | assert(list->length == i); 22 | } 23 | 24 | void test_list() 25 | { 26 | List *list; 27 | int values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 28 | 29 | list = list_new(); 30 | list_append(list, &values[0]); 31 | list_append(list, &values[1]); 32 | 33 | assert(list->length == 2); 34 | // printf("==== %d == %d ====", list->head->data, &values[0]); 35 | assert(list->head->data == &values[0]); 36 | assert(list->tail->data == &values[1]); 37 | 38 | list_prepend(list, &values[2]); 39 | list_prepend(list, &values[3]); 40 | assert(list->length == 4); 41 | assert(list->head->data == &values[3]); 42 | 43 | list_prepend(list, &values[4]); 44 | list_prepend(list, &values[5]); 45 | assert(list->length == 6); 46 | 47 | // check 48 | check_list_integrity(list); 49 | 50 | // 5,4,3,2,0,1 51 | assert(list_nth_node(list, 0) == list->head); 52 | assert(list_nth_node(list, 5) == list->tail); 53 | assert(list_nth_node(list, 4) == list->tail->prev); 54 | assert(list_nth_node(list, 6) == NULL); 55 | 56 | // printf("==== %d == %d ====", list->head->data, &values[0]); 57 | assert(int_equal(list_nth_data(list, 0), list->head->data)); 58 | assert(int_equal(list_nth_data(list, 5), list->tail->data)); 59 | assert(int_equal(list_nth_data(list, 4), list->tail->prev->data)); 60 | assert(list_nth_data(list, 7) == LIST_NULL); 61 | 62 | // ListValue *list_to_array(List *list); 63 | ListValue *array = list_to_array(list); 64 | assert(array[0] == list->head->data); 65 | assert(array[1] == list_nth_data(list, 1)); 66 | assert(array[2] == list_nth_data(list, 2)); 67 | free(array); 68 | 69 | ListNode *tail = list->tail; 70 | assert(list_find_node(list, tail) == list->tail); 71 | // 5,4,3,2,0,1 72 | assert(list_find_data(list, int_equal, &values[2]) == 73 | list_nth_node(list, 3)); 74 | 75 | ListNode *node = list_nth_node(list, 3); 76 | node = list_remove_node(list, node); 77 | free(node); 78 | assert(list->length == 5); 79 | assert(int_equal(list_nth_data(list, 3), &values[0])); 80 | node = list_remove_node(list, list->head); 81 | free(node); 82 | assert(list->length == 4); 83 | assert(int_equal(list_nth_data(list, 0), &values[4])); 84 | // check 85 | check_list_integrity(list); 86 | 87 | assert(list_remove_data(list, int_equal, &values[4]) == 0); 88 | // has been removed 89 | assert(list_remove_data(list, int_equal, &values[4]) == -1); 90 | assert(list_remove_data(list, int_equal, &values[3]) == 0); 91 | assert(list_remove_data(list, int_equal, &values[0]) == 0); 92 | assert(list_remove_data(list, int_equal, &values[1]) == 0); 93 | 94 | assert(list->length == 0); 95 | assert(list->head == NULL); 96 | assert(list->tail == NULL); 97 | // check 98 | check_list_integrity(list); 99 | 100 | // free list 101 | list_free(list); 102 | } 103 | 104 | void test_list_sort() 105 | { 106 | int entries[] = {89, 4, 23, 42, 4, 16, 15, 4, 8, 99, 50, 30, 4}; 107 | int sorted[] = {4, 4, 4, 4, 8, 15, 16, 23, 30, 42, 50, 89, 99}; 108 | int num_entries = sizeof(entries) / sizeof(int); 109 | List *list = list_new(); 110 | 111 | for (int i = 0; i < num_entries; ++i) { 112 | assert(list_prepend(list, &entries[i]) == 0); 113 | } 114 | 115 | list_sort(list, int_compare); 116 | assert(list->length == num_entries); 117 | // check 118 | check_list_integrity(list); 119 | 120 | for (int i = 0; i < num_entries; ++i) { 121 | int *value = (int *)list_nth_data(list, i); 122 | assert(*value == sorted[i]); 123 | } 124 | 125 | list_free(list); 126 | } 127 | -------------------------------------------------------------------------------- /test/test_matrix.c: -------------------------------------------------------------------------------- 1 | #include "matrix.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | void test_matrix() {} 10 | 11 | void test_matrix_2_dimensions() 12 | { 13 | unsigned int dimensions = 2; 14 | unsigned int width = 3; 15 | unsigned int height = 5; 16 | Matrix *matrix = matrix_new(dimensions, height, width); 17 | matrix_reset(matrix); 18 | 19 | for (int row = 0; row < height; ++row) { 20 | for (int col = 0; col < width; ++col) { 21 | assert(matrix_get(matrix, dimensions, row, col) == 0); 22 | } 23 | } 24 | 25 | int values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 26 | matrix_set(matrix, &values[1], dimensions, 1, 2); 27 | assert(int_equal(matrix_get(matrix, dimensions, 1, 2), &values[1])); 28 | assert(int_equal(matrix_get(matrix, dimensions, 1, 2), 29 | matrix->data[1 * width + 2])); 30 | 31 | matrix_set(matrix, &values[2], dimensions, 4, 2); 32 | assert(int_equal(matrix_get(matrix, dimensions, 4, 2), &values[2])); 33 | assert(int_equal(matrix_get(matrix, dimensions, 4, 2), 34 | matrix->data[4 * width + 2])); 35 | 36 | matrix_free(matrix); 37 | } 38 | -------------------------------------------------------------------------------- /test/test_prime.c: -------------------------------------------------------------------------------- 1 | #include "prime.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | void test_prime_1() 10 | { 11 | BitMap *sieve = prime_number_sieve(100); 12 | 13 | assert(prime_number_sieve_check(sieve, 2)); 14 | assert(prime_number_sieve_check(sieve, 3)); 15 | assert(prime_number_sieve_check(sieve, 11)); 16 | 17 | assert(prime_number_sieve_check(sieve, 83)); 18 | assert(prime_number_sieve_check(sieve, 89)); 19 | assert(prime_number_sieve_check(sieve, 97)); 20 | 21 | assert(!prime_number_sieve_check(sieve, 88)); 22 | assert(!prime_number_sieve_check(sieve, 99)); 23 | assert(!prime_number_sieve_check(sieve, 81)); 24 | 25 | assert(!prime_number_sieve_check(sieve, 1)); 26 | assert(!prime_number_sieve_check(sieve, 0)); 27 | 28 | prime_number_sieve_free(sieve); 29 | } 30 | 31 | void test_prime_2() 32 | { 33 | /** 1 billion, take long time. */ 34 | // BitMap *sieve = prime_number_sieve(1000000000); 35 | // unsigned int count = prime_number_sieve_count(sieve); 36 | // printf("Prime numbers count: ==%u==", count); 37 | // assert(count == 50847534); 38 | // prime_number_sieve_free(sieve); 39 | } 40 | 41 | void test_prime_3() 42 | { 43 | /** 1 million. */ 44 | BitMap *sieve = prime_number_sieve(1000000); 45 | unsigned int count = prime_number_sieve_count(sieve); 46 | // printf("Prime numbers count: ==%u==", count); 47 | assert(count == 78498); 48 | prime_number_sieve_free(sieve); 49 | } 50 | 51 | void test_prime() 52 | { 53 | test_prime_1(); 54 | test_prime_2(); 55 | test_prime_3(); 56 | } 57 | -------------------------------------------------------------------------------- /test/test_queue.c: -------------------------------------------------------------------------------- 1 | #include "queue.h" 2 | #include 3 | #include 4 | 5 | #include "alloc-testing.h" 6 | #include "test_helper.h" 7 | 8 | void test_queue() 9 | { 10 | Queue *queue; 11 | int values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; 12 | 13 | queue = queue_new(); 14 | assert(queue_is_empty(queue)); 15 | 16 | queue_push_head(queue, &values[0]); 17 | queue_push_head(queue, &values[1]); 18 | queue_push_head(queue, &values[2]); 19 | 20 | assert(!queue_is_empty(queue)); 21 | assert(queue_peek_head(queue) == &values[2]); 22 | assert(queue_pop_head(queue) == &values[2]); 23 | assert(queue_pop_head(queue) == &values[1]); 24 | assert(queue_pop_head(queue) == &values[0]); 25 | assert(queue_is_empty(queue)); 26 | 27 | queue_push_tail(queue, &values[0]); 28 | queue_push_tail(queue, &values[1]); 29 | queue_push_tail(queue, &values[2]); 30 | 31 | assert(queue_peek_head(queue) == &values[0]); 32 | assert(queue_peek_tail(queue) == &values[2]); 33 | assert(queue_pop_tail(queue) == &values[2]); 34 | assert(queue_pop_tail(queue) == &values[1]); 35 | assert(queue_pop_tail(queue) == &values[0]); 36 | 37 | queue_free(queue); 38 | } 39 | -------------------------------------------------------------------------------- /test/test_rbtree.c: -------------------------------------------------------------------------------- 1 | #include "rbtree.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | RBTree *create_rb_tree(int size) 10 | { 11 | RBTree *tree = rb_tree_new(int_compare, free, NULL); 12 | // int arr[] = {5, 6, 3, 2, 8, 1, 4, 0, 9, 7}; 13 | 14 | for (int i = 0; i < size; ++i) { 15 | int *key = intdup(i); 16 | int *value = key; 17 | assert(rb_tree_insert(tree, key, value)); 18 | } 19 | 20 | return tree; 21 | } 22 | 23 | void test_rbtree_insert() 24 | { 25 | RBTree *tree = create_rb_tree(100); 26 | 27 | unsigned int height = rb_tree_subtree_height(tree->root); 28 | assert(height <= 7); 29 | 30 | rb_tree_free(tree); 31 | } 32 | 33 | void test_rbtree_delete() 34 | { 35 | RBTree *tree = create_rb_tree(10); 36 | 37 | int *key = intdup(7); 38 | RBTreeNode *node = rb_tree_find_node(tree, key); 39 | assert(int_equal(node->key, key)); 40 | 41 | RBTreeNode *removed = rb_tree_remove_node(tree, node); 42 | assert(removed == node); 43 | assert(tree->num_nodes == 9); 44 | 45 | // printf("root => [%d]\n", *((int *)tree->root->key)); 46 | unsigned int height = rb_tree_subtree_height(tree->root); 47 | assert(height <= 3); 48 | // rb_tree_subtree_print(tree->root, height); 49 | 50 | free(key); 51 | rb_tree_free_node(tree, removed); 52 | rb_tree_free(tree); 53 | } 54 | 55 | void test_rbtree_print() 56 | { 57 | RBTree *tree = create_rb_tree(100); 58 | 59 | printf("root => [%d]\n", *((int *)tree->root->key)); 60 | unsigned int height = rb_tree_subtree_height(tree->root); 61 | rb_tree_subtree_print(tree->root, height); 62 | 63 | rb_tree_free(tree); 64 | } 65 | 66 | // void test_rb_tree_rotate() 67 | // { 68 | // RBTree *tree = create_rb_tree(3); 69 | 70 | // printf("root => [%d]\n", *((int *)tree->root->key)); 71 | // unsigned int height = rb_tree_subtree_height(tree->root); 72 | // rb_tree_subtree_print(tree->root, height); 73 | 74 | // RBTreeNode *mid = tree->root->right; 75 | // RBTreeNode *new_node = rb_tree_rotate(tree, mid); 76 | 77 | // printf("new => [%d]\n", *((int *)new_node->key)); 78 | 79 | // rb_tree_subtree_print(tree->root, height); 80 | 81 | // rb_tree_free(tree); 82 | // } 83 | 84 | void test_rbtree() 85 | { 86 | // test_rb_tree_rotate(); 87 | test_rbtree_insert(); 88 | test_rbtree_delete(); 89 | // test_rbtree_print(); 90 | } 91 | -------------------------------------------------------------------------------- /test/test_skip_list.c: -------------------------------------------------------------------------------- 1 | #include "skip_list.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | void test_skip_list_insert() 10 | { 11 | SkipList *list = skip_list_new(int_compare, NULL, NULL); 12 | int *arr = generate_random_numbers(0, 99); 13 | 14 | for (int i = 0; i < 100; ++i) { 15 | int *key = &(arr[i]); 16 | int *value = key; 17 | assert(skip_list_insert(list, key, value)); 18 | } 19 | 20 | skip_list_print(list); 21 | 22 | int k = 20; 23 | assert(k == *((int *)skip_list_find(list, &k))); 24 | 25 | SkipListNode *node = skip_list_remove_node(list, &(arr[9])); 26 | skip_list_free_node(list, node); 27 | 28 | skip_list_print(list); 29 | 30 | skip_list_free(list); 31 | free(arr); 32 | } 33 | 34 | void test_skip_list() 35 | { 36 | test_skip_list_insert(); 37 | } 38 | -------------------------------------------------------------------------------- /test/test_sunday.c: -------------------------------------------------------------------------------- 1 | #include "sunday.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | void test_sunday_string_match() 10 | { 11 | assert(sunday_string_match("abcabc", "abc") == 0); 12 | assert(sunday_string_match("abcabc", "abcd") == -1); 13 | assert(sunday_string_match("abcabcd", "abcd") == 3); 14 | assert(sunday_string_match("bcabaaaa", "aaaa") == 4); 15 | assert(sunday_string_match("bcabaaabaaaa", "aaaa") == 8); 16 | 17 | ASSERT_INT_EQ(sunday_string_match("bbcabcdababcdabcdabde", "abcdabd"), 13); 18 | ASSERT_INT_EQ(sunday_string_match("here is a simple example", "example"), 17); 19 | 20 | ASSERT_INT_EQ(sunday_string_match("abcaacbabbacab", "abcbab"), -1); 21 | ASSERT_INT_EQ(sunday_string_match("abbadcababacab", "babac"), 7); 22 | 23 | ASSERT_INT_EQ(sunday_string_match("aaaaaaaaaaaaaaaa", "baaa"), -1); 24 | ASSERT_INT_EQ(sunday_string_match("abcacabcbcbacabc", "cbacabc"), 9); 25 | 26 | ASSERT_INT_EQ(sunday_string_match("ababcabcabcabc", "abcabcabc"), 2); 27 | ASSERT_INT_EQ(sunday_string_match("aaaabaaaaaaaaa", "baaaaaaaaa"), 4); 28 | } 29 | 30 | void test_sunday() 31 | { 32 | test_sunday_string_match(); 33 | } 34 | -------------------------------------------------------------------------------- /test/test_text.c: -------------------------------------------------------------------------------- 1 | #include "text.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "alloc-testing.h" 8 | #include "test_helper.h" 9 | 10 | static void test_text_new() 11 | { 12 | Text *text = text_new(); 13 | ASSERT_INT_EQ(text_length(text), 0); 14 | ASSERT_CHAR_EQ(text_char_at(text, 0), CHAR_NIL); 15 | text_free(text); 16 | } 17 | 18 | static void test_text_clone() 19 | { 20 | Text *text = text_n_from("hello,world", 5); 21 | ASSERT_INT_EQ(text_length(text), 5); 22 | ASSERT_CHAR_EQ(text_char_at(text, 0), 'h'); 23 | ASSERT_CHAR_EQ(text_char_at(text, 4), 'o'); 24 | ASSERT_CHAR_EQ(text_char_at(text, 5), CHAR_NIL); 25 | ASSERT_CHAR_EQ(text_char_at(text, 6), CHAR_NIL); 26 | 27 | Text *clone = text_clone(text); 28 | ASSERT_INT_EQ(text_length(clone), 5); 29 | ASSERT_CHAR_EQ(text_char_at(clone, 0), 'h'); 30 | ASSERT_CHAR_EQ(text_char_at(clone, 4), 'o'); 31 | ASSERT_CHAR_EQ(text_char_at(clone, 5), CHAR_NIL); 32 | ASSERT_CHAR_EQ(text_char_at(clone, 6), CHAR_NIL); 33 | 34 | text_free(text); 35 | text_free(clone); 36 | } 37 | 38 | void test_text_compare() 39 | { 40 | Text *text1 = text_from("hello, world"); 41 | Text *text2 = text_from("hello, world, my world."); 42 | assert(!text_equal(text1, text2)); 43 | ASSERT_INT_EQ(text_compare(text1, text2), -1); 44 | 45 | Text *text3 = text_n_from("hello, world, my world.", 12); 46 | assert(text_equal(text1, text3)); 47 | 48 | text_free(text1); 49 | text_free(text2); 50 | text_free(text3); 51 | } 52 | 53 | void test_text() 54 | { 55 | test_text_new(); 56 | test_text_clone(); 57 | test_text_compare(); 58 | } 59 | -------------------------------------------------------------------------------- /test/test_trie.c: -------------------------------------------------------------------------------- 1 | #include "trie.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "alloc-testing.h" 8 | #include "test_helper.h" 9 | 10 | static int trie_insert_str(Trie *trie, const char *str) 11 | { 12 | return trie_insert(trie, str, strlen(str)); 13 | } 14 | 15 | static TrieNode *trie_find_str(Trie *trie, const char *str) 16 | { 17 | return trie_last_node(trie, str, strlen(str)); 18 | } 19 | 20 | static int trie_delete_str(Trie *trie, const char *str) 21 | { 22 | return trie_delete(trie, str, strlen(str)); 23 | } 24 | 25 | static bool trie_include_str(Trie *trie, const char *str) 26 | { 27 | return trie_include(trie, str, strlen(str)); 28 | } 29 | 30 | void test_trie_free() 31 | { 32 | Trie *trie = trie_new(); 33 | trie_insert_str(trie, "hello"); 34 | HashTableEntity *entity = hash_table_first_entity(trie->root->children); 35 | assert(entity != NULL); 36 | ASSERT_CHAR_EQ(*((char *)entity->key), 'h'); 37 | trie_free(trie); 38 | } 39 | 40 | void test_trie_insert() 41 | { 42 | Trie *trie = trie_new(); 43 | 44 | trie_insert_str(trie, "hello"); 45 | trie_insert_str(trie, "hifi"); 46 | trie_insert_str(trie, "hi world"); 47 | trie_insert_str(trie, "here"); 48 | trie_insert_str(trie, "heroine"); 49 | trie_insert_str(trie, "legend"); 50 | trie_insert_str(trie, "kelly"); 51 | 52 | TrieNode *node; 53 | HashTable *children; 54 | node = trie_find_str(trie, "he"); 55 | ASSERT_CHAR_EQ(node->data, 'e'); 56 | children = node->children; 57 | ASSERT_INT_EQ(hash_table_size(children), 2); 58 | 59 | assert(trie_include_str(trie, "legend")); 60 | assert(trie_delete_str(trie, "legend") == 0); 61 | assert(!trie_include_str(trie, "legend")); 62 | 63 | trie_free(trie); 64 | } 65 | 66 | void test_trie() 67 | { 68 | test_trie_free(); 69 | test_trie_insert(); 70 | } 71 | -------------------------------------------------------------------------------- /test/test_vector.c: -------------------------------------------------------------------------------- 1 | #include "vector.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "alloc-testing.h" 7 | #include "test_helper.h" 8 | 9 | void test_vector() 10 | { 11 | Vector *v1 = vector_new(2, 0.0, 1.0); 12 | ASSERT_INT_EQ(v1->num_dimensions, 2); 13 | ASSERT_DOUBLE_EQ(v1->coordinates[0], 0, 0.0); 14 | ASSERT_DOUBLE_EQ(v1->coordinates[1], 1, 0.0); 15 | vector_free(v1); 16 | 17 | Vector *v2 = vector_new(4, 3.0, 5.0, -3.0, 1.0); 18 | ASSERT_INT_EQ(v2->num_dimensions, 4); 19 | ASSERT_DOUBLE_EQ(v2->coordinates[0], 3, 0.0); 20 | ASSERT_DOUBLE_EQ(v2->coordinates[1], 5, 0.0); 21 | ASSERT_DOUBLE_EQ(v2->coordinates[2], -3, 0.0); 22 | ASSERT_DOUBLE_EQ(v2->coordinates[3], 1, 0.0); 23 | vector_free(v2); 24 | 25 | Vector *v3 = vector_new(0, 3.0, 5.0); 26 | ASSERT_INT_EQ(v3->num_dimensions, 0); 27 | vector_free(v3); 28 | } 29 | -------------------------------------------------------------------------------- /test/testmain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "alloc-testing.h" 5 | 6 | extern void test_arraylist(); 7 | extern void test_arraylist_index_of(); 8 | extern void test_arraylist_sort(); 9 | extern void test_list(); 10 | extern void test_list_sort(); 11 | extern void test_queue(); 12 | extern void test_bitmap(); 13 | extern void test_bitmap_words(); 14 | extern void test_matrix(); 15 | extern void test_matrix_2_dimensions(); 16 | extern void test_bstree(); 17 | extern void test_bstree_remove(); 18 | extern void test_avltree(); 19 | extern void test_rbtree(); 20 | extern void test_heap(); 21 | extern void test_skip_list(); 22 | extern void test_bignum(); 23 | extern void test_bignum_int_addition(); 24 | extern void test_bignum_int_subtraction(); 25 | extern void test_bignum_int_multiplication(); 26 | extern void test_bignum_int_division(); 27 | extern void test_dijkstra(); 28 | extern void test_prime(); 29 | extern void test_hash_table(); 30 | extern void test_kmp(); 31 | extern void test_bm(); 32 | extern void test_trie(); 33 | extern void test_ac(); 34 | extern void test_text(); 35 | extern void test_huffman(); 36 | extern void test_distance(); 37 | extern void test_vector(); 38 | 39 | typedef void (*TestcaseFunc)(void); 40 | 41 | static TestcaseFunc all_tests[] = {test_arraylist, 42 | test_arraylist_index_of, 43 | test_arraylist_sort, 44 | test_list, 45 | test_list_sort, 46 | test_queue, 47 | test_bitmap, 48 | test_bitmap_words, 49 | test_matrix, 50 | test_matrix_2_dimensions, 51 | test_bstree, 52 | test_bstree_remove, 53 | test_avltree, 54 | test_rbtree, 55 | test_heap, 56 | test_skip_list, 57 | test_bignum, 58 | test_bignum_int_addition, 59 | test_bignum_int_subtraction, 60 | test_bignum_int_multiplication, 61 | test_bignum_int_division, 62 | test_dijkstra, 63 | test_prime, 64 | test_hash_table, 65 | test_kmp, 66 | test_bm, 67 | test_trie, 68 | test_ac, 69 | test_text, 70 | test_huffman, 71 | test_distance, 72 | test_vector, 73 | NULL}; 74 | 75 | static void run_test(TestcaseFunc test) 76 | { 77 | alloc_test_set_limit(-1); 78 | test(); 79 | assert(alloc_test_get_allocated() == 0); 80 | printf("."); 81 | } 82 | 83 | int main(int argc, char *argv[]) 84 | { 85 | printf("======= Tests[%lu testcases] start ======= \n", 86 | sizeof(all_tests) / sizeof(TestcaseFunc)); 87 | 88 | for (int i = 0; all_tests[i] != NULL; ++i) { 89 | run_test(all_tests[i]); 90 | } 91 | 92 | printf("\n======= Tests finished ======= \n"); 93 | return 0; 94 | } 95 | --------------------------------------------------------------------------------