二叉搜索树的概念
如果左子树不为空,则左子树上所有结点的权值都要小于该点的权值
如果右子树不为空,则右子树上所有的结点的权值都要大于该点的权值
二叉查找树上的结点的权值唯一,且结点左右子树都是二叉查找树,并且左子树的权值都要小于右子树的权值
相应操作的实现:
插入操作:
1.根节点为空则新元素直接作为根节点插入,否则传入的参数与根结点进行比较
2.value等于当前结点的话直接返回,小于当前结点跳第3步,大于当前结点跳第4步
3.判断当前结点是否存在左子,如果存在左子,则递归左子,否则直接插入
4.判断当前结点是否存在右子,如果存在右子,则递归右子,否则直接插入
相应实现代码如下:
void insert(Type value) {
if (data == value) { //已存在元素的话,就退出
return;
}
else if (data < value) { //向右子树插入
if (rchild == nullptr) {
rchild = new Node<Type>(value);
}
else {
rchild->insert(value);
}
}
else { //向左子树插入
if (lchild == nullptr) {
lchild = new Node<Type>(value);
}
else {
lchild->insert(value);
}
搜索操作和插入操作算法是一致的
Node* search(Type value) {
if (data == value) { //如果就是的话,返回当前对象
return this;
}
else if(data < value){
if (rchild == nullptr) {
return nullptr;
}
else {
rchild->search(value);
}
}
else {
if (lchild == nullptr) {
return nullptr;
}
else {
lchild->search(value);
}
}
}
删除操作:
二叉搜索树的删除操作较为繁琐
首先需要找到删除结点的前驱或是后继,
前驱是指值比它小的节点中最大的一个节点
后继是指值比它大的节点中最小的一个节点
找前驱的步骤:
1.找到当前节点的左孩子,如果左孩子不存在,则无前驱
2.若存在左子,则在左子上向右遍历,遍历到最后一个右子就是节点的前驱
找后继的步骤:
1.找到当前节点的右孩子,如果右孩子不存在,则无后继
2.若存在右孩子,则在右子上不断向左遍历,遍历到最后一个左子就是节点的后继
相关的代码如下:
Node<Type>* predecessor() {
Node<Type>* temp = lchild;
while (temp != nullptr && temp->rchild != nullptr) {
temp = temp->rchild;
}
return temp; //前驱
}
Node<Type>* successor() {
Node<Type>* temp = rchild;
while (temp != nullptr && temp->lchild != nullptr) {
temp = temp->lchild;
}
return temp; //后继
}
有了前驱和后继,就可以执行删除操作了
删除节点分成两种情况:
1.删除度为1或0的节点(只有一个孩子或者它是叶子节点)
2.删除度超过1的节点
删除度为0或1的节点的操作比较简单
1.如果是左子,将被删除节点的左子的父亲节点更新为被删除节点的父亲节点
2.如果是右子,将被删除节点的右子的父亲节点更新为被删除节点的父亲节点
3.将被删节点的父亲节点的(左子或右子)更新为被删节点的(左子或右子)
4,删除被删节点
//删除度为1或0的节点
void remove_node(Node<Type>* delete_node) {
Node<Type>* temp = nullptr;
if (delete_node->lchild != nullptr) {
temp = delete_node->lchild;
temp->father = delete_node->father;
}
if (delete_node->rchild != nullptr) {
temp = delete_node->rchild;
temp->father = delete_node->father;
}
if (delete_node->father->lchild == delete_node) {
delete_node->father->lchild = temp;
}
else {
delete_node->father->rchild = temp;
}
delete_node->lchild = nullptr;
delete_node->rchild = nullptr;
delete delete_node;
}
有了以上叶子节点的删除法,我们就可以删除度为2以上的节点,方法如下:
1.通过搜索函数定位到要被删除的节点,如果节点不存在,直接返回null
2.寻找这个被删结点的前驱或后继,如果前驱或后继存在,则将当前的值与前驱或后继的值进行交换,如果不存在,则直接删除当前结点。
3.交换后,删除前驱或后继结点
代码如下:
bool delete_tree(Type value) {
Node<Type>*current_node = nullptr, *delete_node = nullptr;
current_node = search(value);
if (current_node == nullptr) {
return false; //直接返回错误
}
if (current_node->lchild != nullptr) {
delete_node = current_node->predecessor();
}
else if (current_node->rchild != nullptr) {
delete_node = current_node->successor();
}
else {
delete_node = current_node;
}
//删除结点
current_node->data = delete_node->data;
remove_node(delete_node);
return true;
}
整颗二叉搜索树的完整代码如下:
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
template <typename Type> class Node {
public:
Type data;
Node<Type> *lchild, *rchild, *father;
Node(Type _data, Node<Type> *_father = NULL) {
data = _data;
lchild = NULL;
rchild = NULL;
father = _father;
}
~Node() {
if (lchild != NULL) {
delete lchild;
}
if (rchild != NULL) {
delete rchild;
}
}
void insert(Type value) {
if (value == data) {
return;
}
else if (value > data) {
if (rchild == NULL) {
rchild = new Node<Type>(value, this);
}
else {
rchild->insert(value);
}
}
else {
if (lchild == NULL) {
lchild = new Node<Type>(value, this);
}
else {
lchild->insert(value);
}
}
}
Node<Type>* search(Type value) {
if (data == value) {
return this;
}
else if (value > data) {
if (rchild == NULL) {
return NULL;
}
else {
return rchild->search(value);
}
}
else {
if (lchild == NULL) {
return NULL;
}
else {
return lchild->search(value);
}
}
}
Node<Type>* predecessor() {
Node<Type>* temp = lchild;
while (temp != nullptr && temp->rchild != nullptr) {
temp = temp->rchild;
}
return temp; //前驱
}
Node<Type>* successor() {
Node<Type>* temp = rchild;
while (temp != nullptr && temp->lchild != nullptr) {
temp = temp->lchild;
}
return temp; //后继
}
void remove_node(Node<Type>* delete_node) { //度为1或0
Node<Type>* temp = nullptr;
if (delete_node->lchild != nullptr) {
temp = delete_node->lchild;
temp->father = delete_node->father;
}
if (delete_node->rchild != nullptr) {
temp = delete_node->rchild;
temp->father = delete_node->father;
}
if (delete_node->father->lchild == delete_node) {
delete_node->father->lchild = temp;
}
else {
delete_node->father->rchild = temp;
}
delete_node->lchild = nullptr;
delete_node->rchild = nullptr;
delete delete_node;
}
bool delete_tree(Type value) {
Node<Type>*current_node = nullptr, *delete_node = nullptr;
current_node = search(value);
if (current_node == nullptr) {
return false; //直接返回错误
}
if (current_node->lchild != nullptr) {
delete_node = current_node->predecessor();
}
else if (current_node->rchild != nullptr) {
delete_node = current_node->successor();
}
else {
delete_node = current_node;
}
//删除结点
current_node->data = delete_node->data;
remove_node(delete_node);
return true;
}
void print() {
if (lchild != nullptr) {
lchild->print();
}
cout << data << " ";
if (rchild != nullptr) {
rchild->print();
}
}
};
template <typename Type> class BinaryTree {
private:
Node<Type> *root;
public:
BinaryTree() {
root = NULL;
}
~BinaryTree() {
delete root;
}
void insert(Type value) {
if (root == NULL) {
root = new Node<Type>(value);
}
else {
root->insert(value);
}
}
bool find(Type value) {
if (root == NULL) {
return false;
}
if (root->search(value) == NULL) {
return false;
}
else {
return true;
}
}
bool delete_tree(Type value) {
if (root == nullptr) {
return false;
}
return root->delete_tree(value);
}
void print() {
if (root != nullptr) {
root->print();
}
}
};
int main() {
BinaryTree<int> binarytree;
int m;
cin >> m;
for (int i = 0; i < m; ++i) {
int n;
cin >> n;
binarytree.insert(n);
}
int c;
cin >> c;
for (int i = 0; i < c; ++i) {
int cl;
cin >> cl;
binarytree.delete_tree(cl);
}
binarytree.print();
system("PAUSE");
return 0;
}