二叉排序树定义
二叉排序树又称二叉查找树,它或者是一棵空的二叉树,或者是具有下列性质的二叉树:
(1)若它的左子树不空,则左子树上所有结点的值均小于根结点的值;
(2)若它的右子树不空,则右子树上所有结点的值均大于根结点的值;
(3)它的左右子树也都是二叉排序树。
树节点类定义
//树节点类
class TNode {
public:
int data;
TNode* left, * right;
TNode(int d) :left(nullptr), right(nullptr), data(d) {}
TNode() :left(nullptr), right(nullptr) {}
};
二叉排序树类定义
实现了树的生成,新节点插入,旧结点删除的功能。
//二叉排序树
class BinarySortTree
{
public:
BinarySortTree(int a[],int n);//构造函数
~BinarySortTree();//析构
void Insert(int value);//插入新节点
void Delete(int value);//删除节点
void PreOrder();//前序遍历
void InOrder();//中序遍历,这两个遍历是为了确定树的形状是否正确
private:
void _del(TNode* cur);
void _pre(TNode* cur);
void _in(TNode* cur);
TNode* root;//根结点
};
树的生成和析构
//构造函数
BinarySortTree::BinarySortTree(int a[], int n)
{
for (int i = 0; i < n; i++)
Insert(a[i]);
}
//析构
BinarySortTree::~BinarySortTree()
{
if(root!=nullptr)
_del(root);
}
void BinarySortTree::_del(TNode* cur)
{
if (cur->left == nullptr && cur->right == nullptr) return;
if (cur->left) _del(cur->left);
if (cur->right) _del(cur->right);
节点插入
主要思路就是寻找需要插入的位置的指针cur
//插入新节点
void BinarySortTree::Insert(int value)
{
if (root==nullptr){//当为空树时
root = new TNode(value);
return;
}
TNode* cur = root;//记录当前指针位置
TNode* prev = nullptr;//记录当前指针的前继,初始为空指针
TNode* newNode = new TNode(value);//创建新节点
while (cur) {//使cur位移到空指针处,那么它的前继就是我们需要插入新节点的地方
if (cur->data > value) {
if (cur->left) {
prev = cur;
cur = cur->left;
}
else {//这种情况应该只存在在初始化时,根结点的左右孩子节点至少存在一个为空时可能会跳转进来
cur->left = newNode;
return;
}
}
if (cur->data <= value) {
if (cur->right) {
prev = cur;
cur = cur->right;
}
else {
cur->right = newNode;
return;
}
}
}
//当当前结点为空时,在前继结点处插入
if (prev->data > value)
prev->left = newNode;
else
prev->right = newNode;
}
节点删除
分为两部分变成,第一部分,寻找与value值相等的cur指针,第二部分执行删除操作。
删除的方法是:
从某个子树中找出一个结点s,其值能代替cur的值,这样,就可以用点s的值去替换结点cur的值,再删除结点s。
这个值应该是大于结点cur的最小者(或者小于结点cur的最大者)。
伪代码
1,若结点cur是叶子,则直接删除结点cur;
2,若结点cur只有左子树,则只需重接cur的左子树;若结点cur只有右子树,则只需重接cur的右子树;
3,若结点cur的左右子树均不空,则
3.1 查找结点cur的右子树上的最左下结点cur以及结点cur的双亲结点temp;
3.2 将结点s数据域替换到被删结点cur的数据域;
3.3若结点cur的右孩子无左子树,则将cur的右子树接到par的右子树上否则,将s的右子树接到结点cur的左子树上;
3.4 删除结点s;
该伪代码仅仅举了一种情况,即cur节点的前继节点prev的左孩子节点的情况,而下面的程序都考虑到了所有情况。其实删除的操作比较麻烦的部分是当cur节点的左右子树都不为空时的情况,需要找到一个值应大于结点cur的最小者(或者小于结点cur的最大者)来代替cur的值。
//删除节点,假定一定存在这个节点
void BinarySortTree::Delete(int value)
{
if (root == nullptr) return;
TNode* cur = root;//记录当前指针位置
TNode* prev = nullptr;//记录当前指针的前继,初始为空指针
while (cur){//使cur位移到cur->data=value处
if (cur->data > value) {
if (cur->left) {
prev = cur;
cur = cur->left;
}
}
else if (cur->data < value) {
if (cur->right) {
prev = cur;
cur = cur->right;
}
}
else if (cur->data == value)
break;
}
if (prev == nullptr) { delete root; return; }//说明此时只有根结点符合要求
if (cur->left == nullptr && cur->right == nullptr) {//当cur为叶子结点时
if (prev->left == cur)
prev->left = nullptr;
else if (prev->right == cur)
prev->right = nullptr;
delete cur;
return;
}
else if (cur->left && cur->right == nullptr) {//当cur的左孩子存在,右孩子不存在时
if (prev->left == cur)
prev->left = cur->left;
else if (prev->right == cur)
prev->right = cur->left;
delete cur;
return;
}
else if (cur->left == nullptr && cur->right) {//当cur的左孩子不存在,右孩子存在时
if (prev->left == cur)
prev->left = cur->right;
else if (prev->right == cur)
prev->right = cur->right;
delete cur;
return;
}
else if (cur->left && cur->right) {//左右孩子都存在时
if (prev->left == cur) {//当cur为prev的左子树时,寻找cur右孩子节点中最左边的叶节点
TNode* temp = cur;
TNode* s = cur->right;
while (s->left != nullptr) {
temp = s;
s = s->left;
}
cur->data = s->data;
if (temp == cur) temp->right = s->right;//当temp未发生移动时,此时即cur的右孩子为叶子结点
else temp->left = s->right;//temp发生了移动,此时要删除s节点
delete s;
return;
}
else if (prev->right == cur) {//当cur为prev的右子树时,寻找cur左孩子节点中最右边的叶节点
TNode* temp = cur;
TNode* s = cur->left;
while (s->right!=nullptr)
{
temp = s;
s = s->right;
}
cur->data = s->data;
if (temp == cur) temp->left = s->left;
else temp->right = s->left;
delete s;
return;
}
}
}
全部代码
BinarySortTree.h
#pragma once
#ifndef BINARYSORTTREE_H
#define BINARYSORTTREE_H
#include<iostream>
using std::cout;
using std::endl;
//树节点类
class TNode {
public:
int data;
TNode* left, * right;
TNode(int d) :left(nullptr), right(nullptr), data(d) {}
TNode() :left(nullptr), right(nullptr) {}
};
//二叉排序树
class BinarySortTree
{
public:
BinarySortTree(int a[],int n);//构造函数
~BinarySortTree();//析构
void Insert(int value);//插入新节点
void Delete(int value);//删除节点
void PreOrder();//前序遍历
void InOrder();//中序遍历,这两个遍历是为了确定树的形状是否正确
private:
void _del(TNode* cur);
void _pre(TNode* cur);
void _in(TNode* cur);
TNode* root;//根结点
};
//构造函数
BinarySortTree::BinarySortTree(int a[], int n)
{
for (int i = 0; i < n; i++)
Insert(a[i]);
}
//析构
BinarySortTree::~BinarySortTree()
{
if(root!=nullptr)
_del(root);
}
//插入新节点
void BinarySortTree::Insert(int value)
{
if (root==nullptr){//当为空树时
root = new TNode(value);
return;
}
TNode* cur = root;//记录当前指针位置
TNode* prev = nullptr;//记录当前指针的前继,初始为空指针
TNode* newNode = new TNode(value);//创建新节点
while (cur) {//使cur位移到空指针处,那么它的前继就是我们需要插入新节点的地方
if (cur->data > value) {
if (cur->left) {
prev = cur;
cur = cur->left;
}
else {//这种情况应该只存在在初始化时,根结点的左右孩子节点至少存在一个为空时可能会跳转进来
cur->left = newNode;
return;
}
}
if (cur->data <= value) {
if (cur->right) {
prev = cur;
cur = cur->right;
}
else {
cur->right = newNode;
return;
}
}
}
//当当前结点为空时,在前继结点处插入
if (prev->data > value)
prev->left = newNode;
else
prev->right = newNode;
}
//删除节点,假定一定存在这个节点
void BinarySortTree::Delete(int value)
{
if (root == nullptr) return;
TNode* cur = root;//记录当前指针位置
TNode* prev = nullptr;//记录当前指针的前继,初始为空指针
while (cur){//使cur位移到cur->data=value处
if (cur->data > value) {
if (cur->left) {
prev = cur;
cur = cur->left;
}
}
else if (cur->data < value) {
if (cur->right) {
prev = cur;
cur = cur->right;
}
}
else if (cur->data == value)
break;
}
if (prev == nullptr) { delete root; return; }//说明此时只有根结点符合要求
if (cur->left == nullptr && cur->right == nullptr) {//当cur为叶子结点时
if (prev->left == cur)
prev->left = nullptr;
else if (prev->right == cur)
prev->right = nullptr;
delete cur;
return;
}
else if (cur->left && cur->right == nullptr) {//当cur的左孩子存在,右孩子不存在时
if (prev->left == cur)
prev->left = cur->left;
else if (prev->right == cur)
prev->right = cur->left;
delete cur;
return;
}
else if (cur->left == nullptr && cur->right) {//当cur的左孩子不存在,右孩子存在时
if (prev->left == cur)
prev->left = cur->right;
else if (prev->right == cur)
prev->right = cur->right;
delete cur;
return;
}
else if (cur->left && cur->right) {//左右孩子都存在时
if (prev->left == cur) {//当cur为prev的左子树时,寻找cur右孩子节点中最左边的叶节点
TNode* temp = cur;
TNode* s = cur->right;
while (s->left != nullptr) {
temp = s;
s = s->left;
}
cur->data = s->data;
if (temp == cur) temp->right = s->right;//当temp未发生移动时,此时即cur的右孩子为叶子结点
else temp->left = s->right;//temp发生了移动,此时要删除s节点
delete s;
return;
}
else if (prev->right == cur) {//当cur为prev的右子树时,寻找cur左孩子节点中最右边的叶节点
TNode* temp = cur;
TNode* s = cur->left;
while (s->right!=nullptr)
{
temp = s;
s = s->right;
}
cur->data = s->data;
if (temp == cur) temp->left = s->left;
else temp->right = s->left;
delete s;
return;
}
}
}
void BinarySortTree::PreOrder()
{
if (root) _pre(root);
}
void BinarySortTree::InOrder()
{
if (root) _in(root);
}
void BinarySortTree::_del(TNode* cur)
{
if (cur->left == nullptr && cur->right == nullptr) return;
if (cur->left) _del(cur->left);
if (cur->right) _del(cur->right);
}
void BinarySortTree::_pre(TNode* cur)
{
if (cur == nullptr) return;
cout << cur->data << " ";
_pre(cur->left);
_pre(cur->right);
}
void BinarySortTree::_in(TNode* cur)
{
if (cur == nullptr) return;
_in(cur->left);
cout << cur->data << " ";
_in(cur->right);
}
#endif // !BINARYSORTTREE_H
main.cpp
#include"BinarySortTree.h"
int main()
{
int a[] = { 1,23,2,4,12,0,3,6 };
BinarySortTree mytree(a, 8);
mytree.PreOrder();
cout << endl;
mytree.InOrder();
cout << endl;
mytree.Delete(0);
mytree.PreOrder();
cout << endl;
mytree.InOrder();
cout << endl;
return 1;
}