---
# System prepended metadata

title: binary_search_tree.a 二元搜尋樹使用說明書

---

# <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
```


