# <center><font size=10>AVL_tree.a</font><br><font size=5>AVL樹使用說明書</font><br><font size=4>by 李奕承</font></center> # <center>摘要</center> 本library提供的結構如下 ```c typedef struct avl_node { struct avl_node *left; struct avl_node *right; int height; } avl_node_t; ``` 本 library 提供以下幾種函數 - 節點初始化 - 印出樹 - 插入節點 - 尋找節點 - 尋找最小節點 - 尋找最大節點 - 刪除節點 # <center>使用方法</center> ### 1.帶入標頭檔 ```c #include"AVLSpec.h" ``` ### 2.創造AVL tree 宣告一個 avl_node_t 的空指標用來指向樹的root,此處以 avl_root_a 為例 ```c avl_node_t * avl_root_a = NULL; ``` ### 3.將 avl_node_t 作為成員包入自己的結構中 例如: ```c typedef struct test_avl{ char name; int value; avl_node_t node; //作為成員 }test_avl_t; ``` ### 4.提供用來比較的回調函數指標 以下幾個需要使用者編寫並提供用來比較的回調函數指標 ```c AVL_insert AVL_find AVL_delete ``` ### 5.搭配巨集使用 使用 AVLSpec.h 中提供的巨集,可以在回調函數中依據 avl_node_t 的記憶體位置反向求得使用者結構的記憶體起始位置,轉型後就可以用來讀取要比較的資料。 ```c #define return_to_user_struct_pointer(USER_STRUCT_TYPE, MEMBER_NAME, MEMBER_POINT) ``` ### 6.編譯 - AVLSpec.h 要記得放在引用標頭檔的路徑下 - 編譯時記得加入 AVL_tree.a ``` gcc -I include -Wall -o ./bin/test test.c AVL_tree.a ``` # <center>函數介紹與範例</center> ## 範例使用的結構 下面是範例用到的結構 ```c typedef struct test_avl{ char name; int value; avl_node_t node; }test_avl_t; ``` 下面的回調函數用來比較兩個 test_avl_t 節點中的 value 值 ```c int compare_value(void * elementA, void * elementB) { if(return_to_user_struct_pointer(test_avl_t, node, elementA)->value < return_to_user_struct_pointer(test_avl_t, node, elementB)->value) { return -1; } else if(return_to_user_struct_pointer(test_avl_t, node, elementA)->value == return_to_user_struct_pointer(test_avl_t, node, elementB)->value) { return 0; } else if(return_to_user_struct_pointer(test_avl_t, node, elementA)->value > return_to_user_struct_pointer(test_avl_t, node, elementB)->value) { return 1; } else { return 2; } } ``` 下面的回調函數用給定的值來比較 test_avl_t 節點中的value值 ```c int compare_key(int key, void * in_tree_element) { if(key < return_to_user_struct_pointer(test_avl_t, node, in_tree_element)->value) { return -1; } else if(key == return_to_user_struct_pointer(test_avl_t, node, in_tree_element)->value) { return 0; } else { return 1; } } ``` 下面的回調函數用 avl_node_t 指標取得 test_avl_t 中的value值 ```c int get_value(avl_node_t * element) { return return_to_user_struct_pointer(test_avl_t, node, element)->value; } ``` 下面的回調函數用 avl_node_t 指標取得 test_avl_t 中的name值 ```c int get_name(avl_node_t * element) { return return_to_user_struct_pointer(test_avl_t, node, element)->name; } ``` 下面的回調函數用 avl_node_t 指標取得該節點的樹高 ```c int get_height(avl_node_t * element) { return element->height; } ``` ## 節點初始化 ```c void AVL_init(avl_node_t * node); ``` 當你宣告一個包含 avl_node_t 的結構之後,可以使用這個函數來初始化 avl_node_t 中的值 以下是範例中創建的root指標及結構 ```c avl_node_t * avl_root_a = NULL; test_avl_t a; a.name = 'A'; a.value = 20; AVL_init(&a.node); test_avl_t b; b.name = 'B'; b.value = 4; AVL_init(&b.node); test_avl_t c; c.name = 'C'; c.value = 26; AVL_init(&c.node); test_avl_t d; d.name = 'D'; d.value = 3; AVL_init(&d.node); test_avl_t e; e.name = 'E'; e.value = 9; AVL_init(&e.node); test_avl_t f; f.name = 'F'; f.value = 21; AVL_init(&f.node); test_avl_t g; g.name = 'G'; g.value = 30; AVL_init(&g.node); test_avl_t h; h.name = 'H'; h.value = 2; AVL_init(&h.node); test_avl_t i; i.name = 'I'; i.value = 7; AVL_init(&i.node); test_avl_t j; j.name = 'J'; j.value = 11; AVL_init(&j.node); test_avl_t k; k.name = 'K'; k.value = 15; AVL_init(&k.node); test_avl_t l; l.name = 'L'; l.value = 8; AVL_init(&l.node); ``` ## 印出樹 ```c void printf_AVL_tree(avl_node_t * root, int(*get_data)(avl_node_t * queue_member), int ascii); ``` 使用這個函數可以印出AVL tree ,在之後的範例會用到 ## 插入節點 ```c void AVL_insert(avl_node_t * element, avl_node_t ** root, int(*compare)(void * element, void * in_tree_element)); ``` 使用這個函數可以在 AVL tree 中插入節點 ```c printf("\n--------------------------------------"); printf("\ncase a"); printf("\n--------------------------------------"); AVL_insert(&a.node, &avl_root_a, compare_value); AVL_insert(&b.node, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value); AVL_init(&a.node); AVL_init(&b.node); avl_root_a = NULL; printf("\n----- case a insert 15 -----\n"); AVL_insert(&a.node, &avl_root_a, compare_value); AVL_insert(&b.node, &avl_root_a, compare_value); AVL_insert(&k.node, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value); AVL_init(&a.node); AVL_init(&b.node); AVL_init(&k.node); avl_root_a = NULL; ``` 終端機的輸出 ``` -------------------------------------- case a -------------------------------------- 20 / / 4 ----- case a insert 15 ----- 15 / \ / \ 4 20 ----- case a insert 8 ----- 8 / \ / \ 4 20 ``` ## 尋找節點 ```c avl_node_t * AVL_find(int key, avl_node_t ** root, int(*compare)(int key, void * in_tree_element)); ``` 使用這個函數可以在 AVL tree 中尋找符合key值的節點,以下是範例 ```c printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); printf_AVL_tree(avl_root_a, get_name, 1); printf("\n"); avl_node_t * found = AVL_find(8, &avl_root_a, compare_key); printf("%d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); ``` 終端機的輸出 ``` 9 / \ / \ / \ / \ / \ / \ / \ 4 20 / \ / \ / \ / \ / \ / \ 3 7 11 26 / \ / \ / \ / \ 2 8 21 30 E / \ / \ / \ / \ / \ / \ / \ B A / \ / \ / \ / \ / \ / \ D I J C / \ / \ / \ / \ H L F G who's value is 8 ? : L ``` ## 尋找最小節點 ```c avl_node_t * AVL_find_minimum(avl_node_t * root); ``` 使用這個函數可以在 AVL tree 中尋找key值最小的節點,以下是範例 ```c found = AVL_find_minimum(avl_root_a); printf("who's value is minimum ? : %c\n", return_to_user_struct_pointer(test_avl_t, node, found)->name); ``` 終端機的輸出 ``` 9 / \ / \ / \ / \ / \ / \ / \ 4 20 / \ / \ / \ / \ / \ / \ 3 7 11 26 / \ / \ / \ / \ 2 8 21 30 E / \ / \ / \ / \ / \ / \ / \ B A / \ / \ / \ / \ / \ / \ D I J C / \ / \ / \ / \ H L F G who's value is minimum ? : H ``` ## 尋找最大節點 ```c avl_node_t * AVL_find_maximum(avl_node_t * root); ``` 使用這個函數可以在 AVL tree 中尋找key值最大的節點,以下是範例 ```c found = AVL_find_maximum(avl_root_a); printf("who's value is maximum ? : %c\n", return_to_user_struct_pointer(test_avl_t, node, found)->name); ``` 終端機的輸出 ``` 9 / \ / \ / \ / \ / \ / \ / \ 4 20 / \ / \ / \ / \ / \ / \ 3 7 11 26 / \ / \ / \ / \ 2 8 21 30 E / \ / \ / \ / \ / \ / \ / \ B A / \ / \ / \ / \ / \ / \ D I J C / \ / \ / \ / \ H L F G who's value is maximum ? : G ``` ## 刪除節點 ```c void AVL_delete(avl_node_t * delete_element, avl_node_t ** root, int (*compare)(void * delete_element, void * in_tree_element)); ``` 使用這個函數可以在 AVL tree 中刪除指定key值的節點,以下是範例 ```c found = AVL_find(8, &avl_root_a, compare_key); printf("delete %d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); AVL_delete(found, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); printf("--------------------------------\n"); found = AVL_find(7, &avl_root_a, compare_key); printf("delete %d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); AVL_delete(found, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); printf("--------------------------------\n"); found = AVL_find(11, &avl_root_a, compare_key); printf("delete %d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); AVL_delete(found, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); printf("--------------------------------\n"); found = AVL_find(26, &avl_root_a, compare_key); printf("delete %d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); AVL_delete(found, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); printf("--------------------------------\n"); found = AVL_find(21, &avl_root_a, compare_key); printf("delete %d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); AVL_delete(found, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); printf("--------------------------------\n"); found = AVL_find(30, &avl_root_a, compare_key); printf("delete %d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); AVL_delete(found, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); printf("--------------------------------\n"); found = AVL_find(2, &avl_root_a, compare_key); printf("delete %d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); AVL_delete(found, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); printf("--------------------------------\n"); found = AVL_find(20, &avl_root_a, compare_key); printf("delete %d\n", return_to_user_struct_pointer(test_avl_t, node, found)->value); AVL_delete(found, &avl_root_a, compare_value); printf_AVL_tree(avl_root_a, get_value, 0); printf("\n"); ``` 終端機的輸出 ``` 9 / \ / \ / \ / \ / \ / \ / \ 4 20 / \ / \ / \ / \ / \ / \ 3 7 11 26 / \ / \ / \ / \ 2 8 21 30 -------------------------------- delete 8 9 / \ / \ / \ / \ / \ / \ / \ 4 20 / \ / \ / \ / \ / \ / \ 3 7 11 26 / / \ / / \ 2 21 30 -------------------------------- delete 7 9 / \ / \ / \ / \ / \ / \ / \ 3 20 / \ / \ / \ / \ / \ / \ 2 4 11 26 / \ / \ 21 30 -------------------------------- delete 11 9 / \ / \ / \ / \ / \ / \ / \ 3 26 / \ / \ / \ / \ / \ / \ 2 4 20 30 \ \ 21 -------------------------------- delete 26 9 / \ / \ / \ 3 21 / \ / \ / \ / \ 2 4 20 30 -------------------------------- delete 21 9 / \ / \ / \ 3 30 / \ / / \ / 2 4 20 -------------------------------- delete 30 9 / \ / \ / \ 3 20 / \ / \ 2 4 -------------------------------- delete 2 9 / \ / \ / \ 3 20 \ \ 4 -------------------------------- delete 20 4 / \ / \ 3 9 ```