BST树称作二叉搜索树(Binary Search Tree)或者二叉排序树(Binary Sort Tree) ,它或者是一颗空树;或者是具有下
列性质的二叉树:
- 若左子树不为空,则左子树上所有节点的值均小于它的根节点的值
- 若右子树不为空,则右子树上所有节点的值均大于它的根节点的值
- 左右子树也分别满足二叉搜索树性质
特点:每一个节点都满足左孩子的值 (不为空) < 父节点的值<右孩子的值(不为空)。
二分查找就是利用了bst树的性质。
BST树的插入:
1.BST为空,生成新的根节点。
2.不为空,从根节点开始进行比较,找到合适的位置,生成新的节点,并把节点的地址写入父节点相应的地址域。
//非递归插入
void insert(const T & val)
{
if (_root == nullptr)
{
_root = new Node(val);
return;
}
Node *parent = nullptr;
Node *cur = _root;
while (cur != nullptr)
{
if (cur->_data == val)
{
return;
}
else if(cur->_data < val)
{
parent = cur;
cur=cur->_right;
}
else
{
parent = cur;
cur = cur->_left;
}
}
if (val < parent->_data)
{
parent->_left = new Node(val);
}
else
{
parent->_right = new Node(val);
}
}
BST的删除操作
- 没有孩子的节点,父节点地址域置为nullptr
- 有一个,孩子写入父节点
- 有两个,找到待删除孩子的前驱或后继节点,用前驱或者后继节点把待删除节点的值覆盖,然后直接删除前驱或者后继节点就可以了。前驱(当前节点左子树中值最大的节点)
void remove(const T & val)
{
if (_root == nullptr)
{
return;
}
Node *parent = nullptr;
Node *cur = _root;
while (cur != nullptr)
{
if (cur->_data==val)
{
break;
}
else if (cur->_data< val)
{
parent = cur;
cur = cur->_right;
}
else
{
parent = cur;
cur = cur->_left;
}
}
if (cur == nullptr) //没找到
{
return;
}
//先进行处理情况3
if (cur->_left != nullptr && cur->_right != nullptr)
{
parent = cur;
Node *pre = cur->_left;
while (pre->_right != nullptr)
{
parent = pre;
pre = pre->_right;
}
cur->_data = pre->_data;
cur = pre; //cur指向前驱节点,转化为情况1或者2
}
//统一处理情况1和2 cur指向删除节点
Node *child = cur->_left;
if (child != nullptr)
{
child = cur->_right;
}
//删除根节点
if (parent == nullptr)
{
_root = child;
}
else
{
//把待删除节点的孩子写到父节点相应的地址域
if (parent->_left == cur)
{
parent->_left = child;
}
else
{
parent->_right = child;
}
}
delete cur;
}
//递归删除
void remove(const T &val)
{
root_ = remove(root_, val);
}
// 递归删除操作实现
Node* remove(Node *node, const T &val)
{
if (node == nullptr)
return nullptr;
if (node->data_ == val) // 找到待删除节点
{
// 情况3
if (node->left_ != nullptr && node->right_ != nullptr)
{
// 找前驱节点
Node *pre = node->left_;
while (pre->right_ != nullptr)
{
pre = pre->right_;
}
node->data_ = pre->data_;
// 通过递归直接删除前驱节点
node->left_ = remove(node->left_, pre->data_);
}
else // 情况1和情况2
{
if (node->left_ != nullptr)
{
// 删除节点以后,把非空的左孩子返回,回溯时更新其父节点地址域
Node *left = node->left_;
delete node;
return left;
}
else if (node->right_ != nullptr)
{
// 删除节点以后,把非空的右孩子返回,回溯时更新其父节点地址域
Node *right = node->right_;
delete node;
return right;
}
else // 删除的是没有孩子的节点 叶子节点
{
delete node;
return nullptr; // 回溯时更新其父节点地址域为nullptr
}
}
}
else if (comp_(node->data_, val))
{
node->right_ = remove(node->right_, val);
}
else
{
node->left_ = remove(node->left_, val);
}
return node; // 把当前节点返回给父节点,更新父节点相应的地址域
}
BST树的查询
bool query(const T & val)
{
Node *cur = _root;
while (cur != nullptr)
{
if (cur->_data == val)
{
return true;
}
else if (cur->_data < val)
{
cur = cur->_right;
}
else
{
cur = cur->_left;
}
}
return false;
}
中序遍历
递归版本:一层一层的打印
//递归层遍历
void levelorder()
{
int h = high();
for (int i = 0; i < h; ++i)
{
levelorder(_root,i);
}
cout << endl;
}
//层数
int high()
{
return high(_root);
}
int high(Node * node)
{
if (node == nullptr)
{
return 0;
}
int left = high(node->_left) ;
int right = high(node->_right) ;
return left > right ? left + 1 : right + 1;
}
void levelorder(Node *node, int i)
{
if (node == nullptr)
{
return ;
}
if (i == 0)
{
cout << node->_data << " ";
return;
}
levelorder(node->_left,i-1);
levelorder(node->_right,i-1);
}
//非递归层序
void n_levelorder()
{
if (_root == nullptr)
{
return;
}
queue<Node*> q;
q.push(_root);
while (!q.empty())
{
Node* front = q.front();
q.pop();
cout << front->_data << " ";
if (front->_left != nullptr)
{
q.push(front->_left);
}
if (front->_right != nullptr)
{
q.push(front->_right);
}
}
}
非递归:
前序遍历
前序为:58 24 0 5 34 41 67 62 42 69 78
//递归
void preorder()
{
preorder(_root);
cout << endl;
}
void preorder(Node *node)
{
if (node != nullptr)
{
cout << node->_data << " ";
preorder(node->_left);
preorder(node->_right);
}
}
//非递归
void n_preOrder()
{
if (_root == nullptr)
{
return;
}
stack<Node*> s;
s.push(_root);
while (!s.empty())
{
Node *top = s.top();
s.pop();
cout << top->_data<< " "; // V
if (top->_right != nullptr)
{
s.push(top->_right); // R
}
if (top->_left != nullptr)
{
s.push(top->_left); // L
}
}
cout << endl;
}
中序遍历
中序为:0 5 24 34 41 58 62 64 67 69 78
//非递归中序遍历
void n_inOrder()
{
if (_root == nullptr)
{
return;
}
stack<Node*> s;
Node* cur = _root;
while (!s.empty() || cur != nullptr)
{
if (cur != nullptr)
{
s.push(cur);
cur = cur->_left;
}
else
{
Node* top = s.top();
s.pop();
cout << top->_data << " ";
cur = top->_right;
}
}
}
后序遍历
后序为:5 0 41 34 24 64 62 78 69 67 58
//非递归后序遍历
void n_postOrder()
{
cout << "非递归后序遍历:";
if (_root == nullptr)
{
return;
}
stack<Node*> s1;
stack<Node*> s2;
s1.push(_root);
while (!s1.empty())
{
Node *top = s1.top();
s1.pop();
s2.push(top); // V
if (top->_left != nullptr)
{
s1.push(top->_left); // L
}
if (top->_right != nullptr)
{
s1.push(top->_right); // R
}
}
while (!s2.empty())
{
cout << s2.top()->_data << " ";
s2.pop();
}
cout << endl;
}
BST树区间元素搜索的查找
利用中序遍历之后为有序的从大到小的性质。
void findValues(vector<T> &vec, int i, int j)
{
findValues(root_, vec, i, j);
}
// 求满足区间的元素值[i, j]实现
void findValues(Node *node, vector<T> &vec, int i, int j)
{
if (node != nullptr)
{
// 在当前节点的左子树中搜索
if (node->data_ > i)
{
findValues(node->left_, vec, i, j); // L
}
if (node->data_ >= i && node->data_ <= j)// V
{
vec.push_back(node->data_); // 存储满足区间元素的值
}
// 在当前节点的右子树中搜索
if (node->data_ < j)
{
findValues(node->right_, vec, i, j); // R
}
}
}
判断一个二叉树是否为BST树
// 判断二叉树是否是BST树
bool isBSTree()
{
Node *pre = nullptr;
return isBSTree(root_, pre);
}
// 判断二叉树是否是BST树的实现 利用BST树中序遍历是一个升序的特点
bool isBSTree(Node *node, Node *&pre)
{
if (node == nullptr)
{
return true;
}
if (!isBSTree(node->left_, pre)) // L 主要判断使递归结束的条件
{
return false;
}
// V
if (pre != nullptr)
{
if (node->data < pre->data_) // 主要判断使递归结束的条件
{
return false;
}
}
pre = node; // 更新中序遍历的前驱节点
return isBSTree(node->right_, pre); // R
}
判断子树问题实现
// 判断子树问题
bool isChildTree(BSTree<T> &child)
{
// 在当前二叉树上找child的根节点
if (child.root_ == nullptr)
{
return true;
}
Node *cur = root_;
while (cur != nullptr)
{
if (cur->data_ == child.root_->data_)
{
break;
}
else if (cur->data_ < child.root_->data_)
{
cur = cur->right_;
}
else
{
cur = cur->left_;
}
}
if (cur == nullptr)
{
return false;
}
return isChildTree(cur, child.root_);
}
// 判断子树问题实现
bool isChildTree(Node *father, Node *child)
{
if (father == nullptr && child == nullptr)
{
return true;
}
if (father == nullptr) // 子树里面有的节点,当前二叉树没有
{
return false;
}
if (child == nullptr)
{
return true;
}
// 判断值不相同
if (father->data_ != child->data_) // V
{
return false;
}
return isChildTree(father->left_, child->left_) // L
&& isChildTree(father->right_, child->right_); // R
}
最近公共祖先节点
// 最近公共祖先节点
int getLCA(int val1, int val2)
{
Node *node = getLCA(root_, val1, val2);
if (node == nullptr)
{
throw "no LCA!";
}
else
{
return node->data_;
}
}
// 最近公共祖先节点实现
Node* getLCA(Node *node, int val1, int val2)
{
if (node == nullptr)
{
return nullptr;
}
if( (node->data_ < val1) && (node->data_<val2))
{
return getLCA(node->right_, val1, val2);
}
else if ((val1 < node->data_) && (val2 < node->data_))
{
return getLCA(node->left_, val1, val2);
}
else
{
return node;
}
}
镜像翻转
// 镜像翻转
void mirror01()
{
mirror01(root_);
}
// 镜像翻转
void mirror01(Node *node)
{
if (node == nullptr)
return;
// V
Node *tmp = node->left_;
node->left_ = node->right_;
node->right_ = tmp;
mirror01(node->left_); // L
mirror01(node->right_); // R
}
镜像对称
如图,在二叉树中间两边互相对称。
// 镜像对称
bool mirror02()
{
if (root_ == nullptr)
return true;
return mirror02(root_->left_, root_->right_);
}
// 镜像对称
bool mirror02(Node *node1, Node *node2)
{
if (node1 == nullptr && node2 == nullptr)
{
return true;
}
if (node1 == nullptr || node2 == nullptr)
{
return false;
}
if (node1->data_ != node2->data_)
{
return false;
}
return mirror02(node1->left_, node2->right_)
&& mirror02(node1->right_, node2->left_);
}
重建二叉树
我们利用前序遍历和中序遍历的特征,前序遍历的第一个是根节点,在中序遍历找到这个节点,该节点之前为该节点的左子树,之后为右子树。
// 重建二叉树
void rebuild(int pre[], int i, int j, int in[], int m, int n)
{
root_ = _rebuild(pre, i, j, in, m, n);
}
// 重建二叉树递归实现
Node* _rebuild(int pre[], int i, int j, int in[], int m, int n)
{
if (i > j || m > n)
{
return nullptr;
}
// 创建当前子树的根节点
Node *node = new Node(pre[i]); // 拿前序的第一个数字创建子树根节点 V
for (int k = m; k <= n; ++k)
{
if (pre[i] == in[k]) // 在中序遍历中找子树根节点的下标k
{
node->left_ = _rebuild(pre, i+1, i+(k-m), in, m, k-1); // L
node->right_ = _rebuild(pre, i+(k-m)+1, j, in, k+1, n); // R
return node;
}
}
return node;
}
判断BST树是否为平衡树
任意节点左右高度差不超过1
// 判断平衡树 效率比较低
bool isBalance(Node *node)
{
if (node == nullptr)
return true;
if (!isBalance(node->left_)) // L
return false;
if (!isBalance(node->right_)) // R
return false;
int left = high(node->left_);
int right = high(node->right_);
return abs(left - right) <= 1; // V
}
// 判断平衡树
bool isBalance()
{
int l = 0;
bool flag = true;
isBalance02(root_, l, flag);
return flag;
}
// 判断平衡树 效率高 递归过程中,记录了节点的高度值 返回节点高度值
int isBalance02(Node *node, int l, bool &flag)
{
if (node == nullptr)
{
return l;
}
int left = isBalance02(node->left_, l + 1, flag); // L
if (!flag)
return left;
int right = isBalance02(node->right_, l + 1, flag); // R
if (!flag)
return right;
// V
if (abs(left - right) > 1) // 节点失衡了
{
flag = false;
}
return max(left, right);
}
求中序遍历倒数第K个节点
// 求中序倒数第K个节点
int getVal(int k)
{
Node *node = getVal(root_, k);
if (node == nullptr)
{
string err = "no No.";
err += k;
throw err;
}
else
{
return node->data_;
}
}
int i = 1;
Node* getVal(Node *node, int k)
{
if (node == nullptr)
return nullptr;
Node *left = getVal(node->right_, k); // R
if (left != nullptr)
return left;
// V
if (i++ == k) // 在VRL的顺序下,找到正数第k个元素
{
return node;
}
return getVal(node->left_, k); // L
}
析构
~BSTree()
{
if (root_ != nullptr)
{
queue<Node*> s;
s.push(root_);
while (!s.empty())
{
Node *front = s.front();
s.pop();
if (front->left_ != nullptr)
{
s.push(front->left_);
}
if (front->right_ != nullptr)
{
s.push(front->right_);
}
delete front;
}
}
}