1.二叉查找树(BST,Binary Search Tree)
注意和堆排序中的堆区分开。
参考我的博客,常见内排序算法中的堆排序。
定义:1)如果左子树不空,那么左子树的所有节点均小于根节点
2)如果右子树不空,那么右子树的所有节点均大于根节点
3)左右子树也都是BST
1.1二叉查找树的查找
如何在二叉查找树上查找某个为key的节点?
首先比较key和根节点,如果其大小等于根节点,退出;
如果小于根节点,递归搜索左子树;
如果大于根节点,递归搜索右子树。
1.2如何在二叉查找树中插入一个节点
1)如果树上已经有关键字相等的节点,不插入
2)否则,要插入的节点,必定是叶子节点,利用1.1中的查找算法,查找不成功的最后一
个节点必然是要插入节点的父亲节点。然后判定要插入节点是该父亲节点的左孩子还是右孩子。
1.3如何在二叉查找树上删除一个节点
1)找到该节点d
2)删除该节点d并修改相应指针。
我看严蔚敏老师那本树上搞的甚是复杂,我老婆比较厉害,帮我总结了个简单的,先看性质,再看图说话。
性质:对于二叉排序树上的任意一个节点,如果它有子树,则有如下性质, 其左子树的最右侧子树的值是小于它的最大值,
其右子树的最左侧子树的值是大于它的最小值,这个小于它的最大值和大于它的最小值都可以替代删除节点做根。我取左子树的最右侧
子树。
删除节点d,共有四种情况:
1)d的左右子树均NULL,删除d,把d父亲节点的相应指针置NULL。
提醒:注意图片2中的特殊情况,d没有父亲,删除d后,整个树为NULL。
图片1 图片2
2)d的左子树不空,右子树NULL,删除d,把d的左子树链接到d的父亲节点。
提醒:图片4中的特殊情况,d无父亲节点,删除d后,整个树的根需要变动,否则我们将失去树根。
图片3 图片4
3)d的左子树NULL,右子树不空,删除d,把d的右子树链接到d的父亲节点
提醒:图片6中的特殊情况,d无父亲节点,删除d后,整个树根要变动,否则我们将永远失去树根。
图片5 图片6
4)d有左子树和右子树,d转左子树,然后向右直到最右r,修改d的关键字为r的关键字,删除r,将r的左子树链接到r的父亲(r不可能有
右子树)
图片7
1.4二叉查找树的宽度优先遍历
写这个功能,主要是为了测试上面1.1,1.2,1.3几个功能的实现是否正确,可以自己造几个
数据插入,然后调用我写的宽度优先遍历打印出来和自己手工画的做比较。
用了STL中的list做队列,没有自己写队列。
1.5二叉查找树的中序遍历
中序遍历的结果是一个有序序列,这也可以作为一种排序方法。
完整代码(没有实现遍历并删除所有节点,道理都一样,懒得写了,你可自己写):
#include <iostream>
#include <list>
using namespace std;
struct BstTreeNode{
int key;
struct BstTreeNode *left;
struct BstTreeNode *right;
};
struct BstTreeNode *parent = NULL;
struct BstTreeNode *search_result = NULL;
//BST search
bool bst_search(struct BstTreeNode *root, int key) {
if(root == NULL) {
return false;
}
if(key == root->key) {
search_result = root;
return true;
}
if(key < root->key) {
parent = root;
return bst_search(root->left, key);
}
if(key > root->key) {
parent = root;
return bst_search(root->right, key);
}
}
//BST add
bool bst_add(struct BstTreeNode *root, int key) {
parent = NULL;
search_result = NULL;
if(bst_search(root, key)) {
return false; //already have this node
}
else if(parent != NULL){
struct BstTreeNode *node = new BstTreeNode;
node->key = key;
node->left = NULL;
node->right = NULL;
if(key < parent->key)
parent->left = node;
else
parent->right = node;
return true;
}
return false;
}
//BST Delete
//Use C++ reference to record the root of the tree
//
bool bst_delete(struct BstTreeNode * &root, int key) {
parent = NULL;
search_result = NULL;
if(!bst_search(root, key)) {
return false; //have nod this node
}
if(search_result->left == NULL && search_result->right == NULL) {
if(parent != NULL) {
if(search_result == parent->left)
parent->left = NULL;
else if(search_result == parent->right)
parent->right = NULL;
}
else {
root = NULL;
}
delete search_result;
}
else if(search_result->left != NULL && search_result->right == NULL) {
if(parent != NULL) {
if(search_result == parent->left)
parent->left = search_result->left;
else if(search_result == parent->right)
parent->right = search_result->left;
}
else {
root = search_result->left;
}
delete search_result;
}
else if(search_result->left == NULL && search_result->right != NULL) {
if(parent != NULL) {
if(search_result == parent->left)
parent->left = search_result->right;
else if(search_result == parent->right)
parent->right = search_result->right;
}
else {
root = search_result->right;
}
delete search_result;
}
else {
struct BstTreeNode *replace = search_result->left;
struct BstTreeNode *replace_parent= replace;
while(replace->right) {
replace_parent = replace;
replace = replace->right;
}
search_result->key = replace->key;
if(replace == replace_parent->left)
replace_parent->left = replace->left;
else if(replace == replace_parent->right)
replace_parent->right = replace->left;
delete replace;
}
return true;
}
//BST traverse, width first search
//Use STL list as a list structure for ease, I do not implement a list
//Of course, you can implement a list yourself
//
void bst_traverse_wfs(struct BstTreeNode *root) {
list<BstTreeNode *> my_list;
if(root != NULL) {
my_list.push_back(root);
}
else {
return;
}
while(!my_list.empty()) {
struct BstTreeNode *tmp = my_list.front();
if(tmp->left)
my_list.push_back(tmp->left);
if(tmp->right)
my_list.push_back(tmp->right);
cout<<tmp->key<<" ";
my_list.pop_front();
}
cout<<endl;
}
//BST traverse, depth first search, inorder
//Inorder recursive implement
void bst_traverse_dfs_inorder(struct BstTreeNode *root) {
if(root == NULL)
return;
bst_traverse_dfs_inorder(root->left);
cout<<root->key<<" ";
bst_traverse_dfs_inorder(root->right);
}
int main() {
/* 7
* 3 9
* 2 5 10
* 1 4 6
*
*/
struct BstTreeNode *root = new BstTreeNode;
root->key = 7;
root->left = NULL;
root->right = NULL;
//construct & print
bst_add(root,3);
bst_add(root,9);
bst_add(root,2);
bst_add(root,5);
bst_add(root,10);
bst_add(root,1);
bst_add(root,4);
bst_add(root,6);
bst_traverse_wfs(root);
bst_traverse_dfs_inorder(root);
cout<<endl;
cout<<"************************"<<endl;
//delete & print
bst_delete(root, 7);
bst_traverse_wfs(root);
bst_traverse_dfs_inorder(root);
cout<<endl;
cout<<"************************"<<endl;
return 0;
}