c/c++ 二叉排序樹
概念:
左樹的所有節點的值(包括子節點)必須小於中心節點,右樹所有節點的值(包括子節點)必須大於中心節點。
不允許有值相同的節點。
二叉排序樹的特點:
- 中序遍歷后,就是從小到大排序了。
- 根節點的最左邊的值,就是樹中最小的值。
- 根節點的最右邊的值,就是樹中最大的值。
創建二叉排序樹的思路:
- 用遞歸的方式
- 和根節點比較大小
- 比根節點小的話,用遞歸去和根節點的左節點比較,至到找到合適的位置
- 比根節點大的話,用遞歸去和根節點的右節點比較,至到找到合適的位置
二叉排序樹的一些實用函數
init_bst | 初始化二叉排序樹 |
---|---|
insert_bst_tree | 插入樹的節點 |
min | 求樹中最小節點 |
max | 求樹中最大節點 |
sort | 排序二叉樹(中序遍歷就是從小到大排序了) |
remove_bst | 刪除節點 |
刪除節點
pattern1:要被刪除的節點是root節點
- 方案1:用根節點左樹中的最大的節點作為新的根節點
刪除45
- 方案2:用根節點又樹中的最小的節點作為新的根節點
刪除45
pattern2:要被刪除的節點是其父節點的左樹,並且要被刪除的節點有右樹
刪除12
pattern3:要被刪除的節點是其父節點的左樹,並且要被刪除的節點無右樹
刪除12
pattern4:要被刪除的節點是其父節點的右樹,並且要被刪除的節點無左樹
刪除53
pattern5:要被刪除的節點是其父節點的右樹,並且要被刪除的節點有左樹
刪除100
bst.h
#ifndef __BST__
#define __BST__
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#define T int
#define FALSE 0
#define TRUE 1
#define BOOL int
typedef struct BSTNode{
T data;
struct BSTNode* left;
struct BSTNode* right;
}BSTNode;
typedef struct BST{
BSTNode* root;
}BST;
//初始化二叉排序樹
void init_bst(BST* bst);
//插入樹的節點
BOOL insert_bst_node(BSTNode** t, T x);
BOOL insert_bst_tree(BST* bst, T x);
//求樹中最小節點
T min(BST* bst);
//求樹中最大節點
T max(BST* bst);
//排序
void sort(BST* bst);
//查找父節點
BSTNode* get_parent(BST* bst, BSTNode* tar);
//刪除節點
BOOL remove_bst(BST* bst, T key);
//搜索節點
BSTNode* search_bst(BST* bst, T key);
//搜索節點
BSTNode* search_bst1(BST* bst, T key);
//清空樹
void clear_bst(BST* bst);
#endif
bst.c
#include "bst.h"
//初始化二叉排序樹
void init_bst(BST* bst){
bst->root = NULL;
}
//插入樹的節點
BOOL insert_bst_node(BSTNode** t, T x){
if(*t == NULL){
*t = (BSTNode*)malloc(sizeof(BSTNode));
assert(NULL != *t);
(*t)->data = x;
(*t)->left = NULL;
(*t)->right = NULL;
return TRUE;
}
else if(x < (*t)->data){
insert_bst_node(&((*t)->left), x);
}
else if(x > (*t)->data){
insert_bst_node(&((*t)->right), x);
}
return FALSE;
}
BOOL insert_bst_tree(BST* bst, T x){
return insert_bst_node(&(bst->root), x);
}
//求樹中最小節點
T min_node(BSTNode* t){
while(t->left != NULL)
t = t->left;
return t->data;
}
T min(BST* bst){
assert(bst->root != NULL);
return min_node(bst->root);
}
//求樹中最大節點
T max_node(BSTNode* t){
while(t->right != NULL){
t = t->right;
}
return t->data;
}
T max(BST* bst){
assert(bst->root != NULL);
return max_node(bst->root);
}
//二叉樹中序排序
void sort_node(BSTNode* t){
if(NULL == t){
return;
}else{
sort_node(t->left);
printf("%d ", t->data);
sort_node(t->right);
}
}
void sort(BST* bst){
assert(NULL != bst->root);
sort_node(bst->root);
}
//搜索節點
BSTNode* search_node(BSTNode* t, T key){
if(NULL == t || t->data == key){
return t;
}
else{
BSTNode* p;
p = search_node(t->left, key);
if(NULL == p){
p = search_node(t->right, key);
}
return p;
}
}
BSTNode* search_bst(BST* bst, T key){
return search_node(bst->root, key);
}
BSTNode* search_node1(BSTNode* t, T key){
if(NULL == t || t->data == key){
return t;
}
else{
if(key < t->data){
search_node1(t->left, key);
}
else{
search_node1(t->right, key);
}
}
}
BSTNode* search_bst1(BST* bst, T key){
return search_node1(bst->root, key);
}
//清空樹
void clear_node(BSTNode** t){
if(NULL != *t){
clear_node(&((*t)->left));
clear_node(&((*t)->right));
free(*t);
*t = NULL;
}
}
void clear_bst(BST* bst){
clear_node(&bst->root);
}
//查找父節點
BSTNode* get_parent_node(BSTNode* t, BSTNode* tar){
if(NULL == t || NULL == tar)return NULL;
if(t->left == tar || t->right == tar){
return t;
}
else{
BSTNode* p = NULL;
p = get_parent_node(t->left, tar);
if(NULL == p){
p = get_parent_node(t->right, tar);
}
return p;
}
}
BSTNode* get_parent(BST* bst, BSTNode* tar){
return get_parent_node(bst->root, tar);
}
BOOL remove_bst(BST* bst, T key){
BSTNode* tar = search_bst(bst, key);
//樹為空或者要刪除的節點不存在,返回失敗
if(bst->root == NULL || NULL == tar) return FALSE;
BSTNode* parent = get_parent(bst, tar);
//因為要被刪除的頂點有左子節點,所以要找到以左子節點為根的右子節點中值最大的
BSTNode* X = NULL;
if(NULL != tar->left){
X = tar->left;
while(X->right != NULL){
X = X->right;
}
//因為要被刪除的頂點的左子節點,有右子節點,所以要找到最大的
if(X != tar->left){
//找到最大節點的父節點
BSTNode* X1 = get_parent(bst, X);
//最大節點的父節點的右邊指向最大節點的左邊
X1->right = X->left;
//最大節點的左邊代替被刪除節點的左邊,右邊代替右邊
X->left = tar->left;
X->right = tar->right;
}
//因為要被刪除的頂點的左子節點,沒有右子節點,所以它就是最大的
else{
X->right = tar->right;
}
}
//因為要被刪除的頂點沒有左子節點,所以要找到以右子節點為根的左子節點中值最小的
else{
X = tar->right;
//要被刪除的節點既沒有左節點,也沒有右節點
if(NULL == X){
//找到父節點
BSTNode* X2 = get_parent(bst, X);
//要被刪除的節點不是根節點
if(parent != NULL){
//要被刪除的頂點在父節點的左邊
if(tar->data < parent->data){
parent->left = X;
}
//要被刪除的頂點在父節點的右邊
else{
parent->right = X;
}
}
else{
bst->root = NULL;
}
free(tar);
return TRUE;
}
while(X->left != NULL){
X = X->left;
}
//因為要被刪除的頂點的右子節點,有左子節點,所以要找到最小的
if(X != tar->right){
//找到最小節點的父節點
BSTNode* X1 = get_parent(bst, X);
//最小節點的父節點的左邊指向最小節點的右邊
X1->left = X->right;
//最小節點的左邊代替被刪除節點的左邊,右邊代替右邊
X->right = tar->right;
X->left = tar->left;
}
}
//要被刪除的節點不是根節點
if(parent != NULL){
//要被刪除的頂點在父節點的左邊
if(tar->data < parent->data){
parent->left = X;
}
//要被刪除的頂點在父節點的右邊
else{
parent->right = X;
}
}
else{
bst->root = X;
}
free(tar);
}
bstmain.c
#include "bst.h"
int main(){
BST bst;
init_bst(&bst);
//patten1 目標節點是root,root沒有右子節點,左子節點中有右子節點
//T ar[] = {45,12,3,37,24,38};
//patten2 目標節點是root,root沒有右子節點,左子節點中沒有右子節點
//T ar[] = {45,12,3};
//patten3 目標節點是root,只有root節點
//T ar[] = {45};
//patten4 目標節點是root,root有右子節點,右子節點中沒有左子節點
//T ar[] = {45,12,53,3,37,100,24};
//patten5 目標節點是root,root有右子節點,右子節點中有左子節點
//T ar[] = {45,12,53,3,37,100,24,61,90,78};
//patten6 目標節點(8)不是root,目標節點有左子節點,左子節點沒有右邊
//T ar[] = {45,12,53,3,27,2,4,24,1,6,5,8,7};
//patten7 目標節點(12)不是root,目標節點有左子節點,左子節點有右邊
//T ar[] = {45,12,53,3,27,2,4,24,1,6,5,8,7};
//patten8 目標節點(120)不是root,目標節點沒有左子節點,右子節點沒有左邊
T ar[] = {45,12,53,3,37,52,100,2,4,24,51,61,120,1,6,90,130,5,8,78,126,140,7,124,127,125};
//T ar[] = {45,12,53,3,37,100,24,61,90,78};
//T ar[] = {45,3,4,12,53};
int n = sizeof(ar) / sizeof(T);
for(int i = 0; i < n; ++i){
insert_bst_tree(&bst, ar[i]);
}
sort(&bst);
printf("\n");
//刪除節點
remove_bst(&bst, 45);
sort(&bst);
printf("\n");
clear_bst(&bst);
}
編譯方法:gcc -g bst.c bstmain.c