/*
* binarySearchTree.cpp
*
* Created on: 2012-4-17
* Author: jiyiqin
* 实现二叉查找树的构造,插入,删除,查找节点等基本操作。
*/
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
class BinarySearchTree{
private:
typedef struct treeNode{
int value;
struct treeNode *parent;
struct treeNode *left;
struct treeNode *right;
}NODE;
NODE *malloc_node(int value, NODE *left, NODE *right){
NODE *newNode = (NODE *)malloc(sizeof(NODE));
newNode->value = value;
newNode->left = left;
newNode->right = right;
return newNode;
}
public:
NODE *root;
BinarySearchTree(){
root = NULL;
}
/**
* 从一个数组构造BST:
* 构造的方法就是从空树开始
* 不断插入新的节点
* */
void buildTree(int node[], int length){
int i;
for(i=0;i<length;i++){
cout<<"insert "<<node[i]<<endl;
insertNode(node[i]);
}
}
/**
* 插入节点:
* 首先要明白,新插入的节点一定是作为叶子(没有孩子)
* 所以说插入的顺序不同,BST的结构会不同
*
* 所以插入操作就变得很简单,不用分不同情况,两步即可:
* (1)找到插入位置(NULL):使用两个指针,一个寻找插入位置,一个指向其父节点;
* (2)插入(作为其父节点的儿子);
* */
void insertNode(int newValue){
NODE *p,*q;
//if this node have exist
if(search(root, newValue) != NULL){
cout<<newValue<<"have existed"<<endl;
return;
}
//insert first node
if(root == NULL){
cout<<"root is null"<<endl;
root = malloc_node(newValue, NULL, NULL);
return;
}
//find insert location
q = root;
while(q != NULL){
p = q;
if(newValue < q->value)
q = q->left;
else
q = q->right;
}
//insert
NODE *newNode = malloc_node(newValue, NULL, NULL);
newNode->parent = p;
if(newNode->value < p->value)
p->left = newNode;
else
p->right = newNode;
}
/**
* 删除节点:分三种情况
* (1) 待删除节点没有孩子
* 直接删除,无需调整
* (2) 待删除节点有一个孩子
* 将待删除节点的父节点指向待删除节点的孩子
* (3) 待删除节点有两个孩子
* 找到待删除节点的后继,同样将其删除(递归),
* 然后用该后继把待删除节点覆盖掉。
* 问:如果不是调整其后继,而是调整其前驱可以么?
* --- 我觉得是可以
* */
void deleteNode(int value){
NODE *parent, *child, *successor;
//返回节点指针
cout<<"delete"<<value<<endl;
NODE *dnode = search(root,value);
if(dnode->left == NULL && dnode->right == NULL){ //没有孩子
//直接将叶子删掉
parent = dnode->parent;
if(parent->left != NULL && dnode->value == parent->left->value)
parent->left = NULL;
else
parent->right = NULL;
}
else if(dnode->left == NULL || dnode->right == NULL){ //一个孩子
//找到待删除节点的孩子(左/右)
if(dnode->left != NULL){
child = dnode->left;
}
else{
child = dnode->right;
}
//将待删除节点的父节点指向其孩子
parent = dnode->parent;
if(parent->left != NULL && dnode->value == parent->left->value)
parent->left = child;
else
parent->right = child;
}
else if(dnode->left != NULL && dnode->right != NULL){ //两个孩子
//找到后继
successor = searchSuccessor(dnode);
//递归删除该后继
deleteNode(successor->value);
//将后继的卫星数据拷贝到"本来应该删除的节点"
dnode->value = successor->value;
}
else{
cout<<"delete error"<<endl;
}
}
/**
* 从node为根的BST上查找value节点
* @return
* NULL: search fail
* not NULL: NODE*
* */
NODE *search(NODE *node, int value){
if(node == NULL || value == node->value)
return node;
if(value < node->value)
return search(node->left, value);
else
return search(node->right, value);
}
/**
* 返回节点的后继
* */
NODE *searchSuccessor(NODE *node){
NODE *p,*q;
//先转向右
p = node;
q = p->right;
if(q == NULL) return NULL;
//再向左走到头
while(q != NULL){
p = q;
q = q->left;
}
return p;
}
/**
* 递归中序遍历
* */
void printTreeByInOrder(NODE *node){
if(node != NULL){
printTreeByInOrder(node->left);
cout<<node->value<<" ";
printTreeByInOrder(node->right);
}
}
/**
* 随机填充一个数组
* */
void radomArray(int a[], int size){
int i;
for(i=0;i<size;i++){
*a++ = rand() % 30;
}
}
};
int main(){
int a[15];
BinarySearchTree bst;
//随机填充数组a
bst.radomArray(a, 15);
//用数组a来构造BST
bst.buildTree(a, 15);
//中序输出
cout<<endl<<"In-Order-Out:";
bst.printTreeByInOrder(bst.root);
//删除一个节点并中序输出
cout<<endl;
bst.deleteNode(a[1]);
cout<<endl<<"In-Order-Out:";
bst.printTreeByInOrder(bst.root);
//删除一个节点并中序输出
cout<<endl;
bst.deleteNode(a[2]);
cout<<endl<<"In-Order-Out:";
bst.printTreeByInOrder(bst.root);
//删除一个节点并中序输出
cout<<endl;
bst.deleteNode(a[4]);
cout<<endl<<"In-Order-Out:";
bst.printTreeByInOrder(bst.root);
return 0;
}
BST的插入和删除
最新推荐文章于 2022-10-27 09:05:33 发布