# <center><font size=10>binary_search_tree.a</font> <br> <font size=5>二元搜尋樹使用說明書</font> <br> <font size=4>by 李奕承</font></center>
# <center>摘要</center>
本library提供的結構如下
```c
typedef struct node {
struct node* left;
struct node* right;
}btreeNode_t;
```
本 library 提供以下幾種函數
- 初始化
- 插入節點
- 列印二元搜尋樹
- 中序走訪
- 複製樹
- 判斷兩個樹是否相等
- 尋找節點
- 尋找最小節點
- 尋找最大節點
- 層序走訪佇列
- 刪除節點
- 計算level
# <center>使用方法</center>
### 1.帶入標頭檔
```c
#include"bstSpec.h"
```
### 2.在要使用二元搜尋樹的結構中加入 btreeNode_t 作為成員
例如
```c
typedef struct test_tree_node{
int data;
char *name;
btreeNode_t node; // 作為成員
}test_tree_node;
```
### 3.建立樹根
需要先選擇一筆資料建立根節點,之後用來做其他操作,例如:
```c
test_tree_node root;
Bst_init(&root.node);
root.data = 7;
root.name = "David";
```
### 4.編寫並提供回調函數指標
以下幾個需要使用者編寫並提供回調函數指標
```c
insertNode
deleteNode
inOrder
findNode
treeCopy
treeEqual
```
### 5.搭配巨集使用
如果 btreeNode_t 不是在結構中的第一個成員,要使用 btreeNode_t 指標存取其它成員時,可以使用本libary提供的下面這個巨集
```c
#define return_to_user_struct_pointer(USER_STRUCT_TYPE, MEMBER_NAME, MEMBER_POINT)
```
USER_STRUCT_TYPE : 你設計的結構名稱
MEMBER_NAME : btreeNode_t 在你的結構中的成員名稱
MEMBER_POINT : btreeNode_t 在你結構中的指標
### 6.編譯
- bstSpec.h 要記得放在引用標頭檔的路徑下
- 編譯時記得加入 binary_search_tree.a
```
gcc -I include -Wall -o ./bin/test test.c binary_search_tree.a
```
# <center>函數介紹與範例</center>
## 範例使用的結構
下面是範例用到的結構,btreeNode_t 是它的第三個成員
```c
typedef struct test_tree_node{
int data;
char *name;
btreeNode_t node;
}test_tree_node;
```
## 初始化
```c
void Bst_init(btreeNode_t* node);
```
這個函數可以將 btreeNode_t 中的 left 和 right 成員初始化為指向NULL。
可以在你新增一個結構時使用,例如下面的示範,宣告一個測試用的結構,並初始化裡面的 btreeNode_t 成員。
```c
test_tree_node a;
Bst_init(&a.node);
```
## 插入節點
```c
void insertNode(btreeNode_t* insert_element, btreeNode_t** root,
int(*compare)(btreeNode_t* insert_element, btreeNode_t* in_tree_element));
```
這個函數可以將一個節點插入到二元樹中,範例中先宣告一個空的樹 tree_one
```c
btreeNode_t* tree_one = NULL;
```
<font color= #0000FF>本函數的參數中有函數指針,需要使用者傳入用來比較大小的函數。</font>
以下是範例使用的比較函數
```c
int compare_int(btreeNode_t* insert_element, btreeNode_t* in_tree_element)
{
if(return_to_user_struct_pointer(test_tree_node, node, insert_element)->data <
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return -1;
}
if(return_to_user_struct_pointer(test_tree_node, node, insert_element)->data >
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return 1;
}
if(return_to_user_struct_pointer(test_tree_node, node, insert_element)->data ==
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return 2;
}
return 0;
}
```
接著建立幾個用來測試的節點
```c
test_tree_node root;
Bst_init(&root.node);
root.data = 7;
root.name = "David";
test_tree_node a;
Bst_init(&a.node);
a.data = 3;
a.name = "Kent";
test_tree_node b;
Bst_init(&b.node);
b.data = 2;
b.name = "John";
test_tree_node c;
Bst_init(&c.node);
c.data = 8;
c.name = "Alice";
test_tree_node d;
Bst_init(&d.node);
d.data = 4;
d.name = "Alisa";
```
將他們插入到 tree_one 中
```c
insertNode(&root.node, &tree_one, compare_int);
insertNode(&a.node, &tree_one, compare_int);
insertNode(&b.node, &tree_one, compare_int);
insertNode(&c.node, &tree_one, compare_int);
insertNode(&d.node, &tree_one, compare_int);
```
## 列印二元搜尋樹
```c
void printf_tree(btreeNode_t* root, int(*get_data)(btreeNode_t* queue_member));
```
這個函數可以將二元搜尋樹以圖形的形式列印出來。
<font color= #0000FF>本函數的參數中有函數指標,需要使用者傳入用來取得印出資料的函數。</font>
以下是範例使用的函數
```c
int get_data(btreeNode_t* root)
{
return return_to_user_struct_pointer(test_tree_node, node, root)->data;
}
```
將 tree_one 印出來
```c
printf_tree(tree_one, get_data);
```
終端機顯示的圖形
```
7
/ \
/ \
3 8
/ \
2 4
```
## 中序走訪
```c
void inOrder(btreeNode_t* root, void(*print)(btreeNode_t* root));
```
本函數顯示一個樹的中序走訪結果。
<font color= #0000FF>本函數的參數中有函數指標,需要使用者傳入用來印出資料的函數。</font>
以下是範例使用的函數
```c
void print_data(btreeNode_t* root)
{
printf("%d ", return_to_user_struct_pointer(test_tree_node, node, root)->data);
}
```
中序走訪 tree_one
```c
printf("print tree_one : \n");
inOrder(tree_one, print_data);
```
終端機的輸出
```
print tree_one inorder : 2 3 4 7 8
```
## 複製樹
```c
btreeNode_t* treeCopy(btreeNode_t* root, btreeNode_t*(*copy)(btreeNode_t* root));
```
本函數可以複製一個二元搜尋樹。
<font color= #0000FF>本函數的參數中有函數指標,需要使用者傳入用來複製節點的函數。</font>
以下是範例使用的函數
```c
btreeNode_t* copy_test_node(btreeNode_t* root)
{
test_tree_node * new_node = (test_tree_node *)malloc(sizeof(test_tree_node));
*new_node = *return_to_user_struct_pointer(test_tree_node, node, root);
Bst_init(&new_node->node);
return &new_node->node;
}
```
宣告一個空樹指標 tree_two ,將 tree_one 的樹複製給 tree_two 並印出
```c
btreeNode_t* tree_two = treeCopy(tree_one, copy_test_node);
printf_tree(tree_two, get_data);
```
終端機的輸出
```
7
/ \
/ \
3 8
/ \
2 4
```
## 判斷兩個樹是否相等
```c
int treeEqual(btreeNode_t* root_A, btreeNode_t* root_B,
int(*compare)(btreeNode_t* root_A, btreeNode_t* root_B));
```
本函數用來判斷兩個二元搜尋樹是否相等。
<font color= #0000FF>本函數的參數中有函數指標,需要使用者傳入用來比較兩個節點是否相等的函數。</font>
以下是範例使用的函數
```c
int compare_Equal(btreeNode_t* node_a, btreeNode_t* node_b)
{
if(return_to_user_struct_pointer(test_tree_node, node, node_a)->data ==
return_to_user_struct_pointer(test_tree_node, node, node_b)->data)
{
if(strcmp(return_to_user_struct_pointer(test_tree_node, node, node_a)->name,
return_to_user_struct_pointer(test_tree_node, node, node_b)->name) == 0)
{
return 1;
}
}
return 0;
}
```
比較 tree_one 和 tree_two
```c
printf("is tree_one and tree_two Equal? (1:ture 0:false): ");
printf("%d\n", treeEqual(tree_one, tree_two, compare_Equal));
```
終端機的輸出
```
is tree_one and tree_two Equal? (1:ture 0:false): 1
```
## 尋找節點
```c
btreeNode_t* findNode(int key, btreeNode_t* root,
int(*compare)(int key, btreeNode_t* in_tree_element));
```
本函數根據使用者要求的值來尋找符合的節點。
<font color= #0000FF>本函數的參數中有函數指標,需要使用者傳入用來比較節點的函數。</font>
以下是範例使用的函數
```c
int compare_key(int key, btreeNode_t* in_tree_element)
{
if(key <
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return -1;
}
if(key >
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return 1;
}
if(key ==
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return 2;
}
return 0;
}
```
比對 data 尋找並印出該節點的 name 成員
```c
test = findNode(2, tree_one, compare_key);
printf("find who's ID is 2 : ");
if(test != NULL)
{
printf("%s\n", return_to_user_struct_pointer(test_tree_node, node, test)->name);
}
test = findNode(7, tree_one, compare_key);
printf("find who's ID is 7 : ");
if(test != NULL)
{
printf("%s\n", return_to_user_struct_pointer(test_tree_node, node, test)->name);
}
test = findNode(3, tree_one, compare_key);
printf("find who's ID is 3 : ");
if(test != NULL)
{
printf("%s\n", return_to_user_struct_pointer(test_tree_node, node, test)->name);
}
test = findNode(8, tree_one, compare_key);
printf("find who's ID is 8 : ");
if(test != NULL)
{
printf("%s\n", return_to_user_struct_pointer(test_tree_node, node, test)->name);
}
```
終端機的輸出
```
find who's ID is 2 : John
find who's ID is 7 : David
find who's ID is 3 : Kent
find who's ID is 8 : Alice
```
## 尋找最小節點
```c
btreeNode_t* findMinNode(btreeNode_t* root);
```
本函數可以尋找一個二元搜尋樹的最小節點。
以下範例以 tree_one 為例
```c
printf("find minimum node in tree_one : ");
printf("%d\n",
return_to_user_struct_pointer(test_tree_node, node, findMinNode(tree_one))->data);
```
終端機的輸出
```
find minimum node in tree_one : 2
```
## 尋找最大節點
```c
btreeNode_t* findMaxNode(btreeNode_t* root);
```
本函數可以尋找一個二元搜尋樹的最大節點。
以下範例以 tree_one 為例
```c
printf("find maximum node in tree_one : ");
printf("%d\n",
return_to_user_struct_pointer(test_tree_node, node, findMaxNode(tree_one))->data);
```
終端機的輸出
```
find maximum node in tree_one : 8
```
## 層序走訪佇列
```c
void tree_level_to_queue(btreeNode_t* root, btreeNode_t* queue[]);
```
本函數以層序走訪一個二元搜尋樹,並按順序將每個節點的指標存進佇列。
以下範例以 tree_one 為例並印出佇列
```c
printf("print level order of tree_one : ");
btreeNode_t* level_temp[10];
for(int i = 0 ; i < 10 ; i++)
{
level_temp[i] = NULL;
}
tree_level_to_queue(tree_two, level_temp);
for(int i = 0 ; i < 10 ; i++ )
{
if(level_temp[i] != NULL)
{
printf("%d ",
return_to_user_struct_pointer(test_tree_node, node, level_temp[i])->data);
}
}
```
終端機的輸出
```
print level order of tree_one : 7 3 8 2 4
```
## 刪除節點
```c
void deleteNode(btreeNode_t* delete_node, btreeNode_t** root,
int(*compare)(btreeNode_t* delete_node, btreeNode_t* in_tree_element));
```
這個函數可以將一個節點從樹中刪除,當刪除的節點左右都有子樹時,本library會拿右子樹的最小節點來放在被刪除的節點位置。
<font color= #0000FF>本函數的參數中有函數指標,需要使用者傳入用來比較節點的函數。</font>
以下是範例使用的函數
```c
int compare_int(btreeNode_t* insert_element, btreeNode_t* in_tree_element)
{
if(return_to_user_struct_pointer(test_tree_node, node, insert_element)->data <
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return -1;
}
if(return_to_user_struct_pointer(test_tree_node, node, insert_element)->data >
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return 1;
}
if(return_to_user_struct_pointer(test_tree_node, node, insert_element)->data ==
return_to_user_struct_pointer(test_tree_node, node, in_tree_element)->data)
{
return 2;
}
return 0;
}
```
刪除 tree_one 中 data 為 3 的 a 節點,並印出刪除後的樹
```c
deleteNode(&a.node, &tree_one, compare_int);
printf_tree(tree_one, get_data);
```
終端機的輸出
```
7
/ \
/ \
4 8
/
2
```
## 計算level
```c
int count_tree_level(btreeNode_t* root);
```
這個函數可以計算一個二元搜尋樹的level數,本 library 假設樹根 level 為 0
以下範例計算 tree_one 的 level 數並印出
```c
printf("print tree_one level : ");
printf("%d\n", count_tree_level(tree_one));
```
終端機的輸出
```
print tree_one level : 2
```