1. 二叉搜索树概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树
二叉树的中序遍历就相当于从小往大排序
2.二叉搜索树的基本操作
结构体的构建
c
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{
}
};
使用初始化列表初始化变量
类封装搜索二叉树
c
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
private:
Node* _root = nullptr;
};
为了方便使用结构体,我们将搜索二叉树的结构体重定义为Node,对于一个搜索二叉树,我们需要定义一个变量存放二叉树根节点的地址,我们在这里相当于给初始化列表给缺省值了
二叉搜索树的插入
由于二叉搜索树是不能出现重复的,我们在遍历查找的时候,如果是第一个插入的话就申请节点,插入函数返回值表示该值是否能插入,如果是第一个节点,就能插入,return true;定义一个遍历指针,刚开始让这个指针指向头结点,然后如果指针指向的结点的值小于要插入的值,则让该指针去右子树寻找,因为右子树是比该节点的值大的。如果指针指向的结点的值大于要插入的值,则让该指针去右子树寻找.如果该指针指向的结点的值等于要插入的·值,直接返回fasle;因为二叉树不能出现重复的数,等到找到要插入值的位置,让他的父节点指向他,但是按照上述的做法,他的父节点根本没有记录到,所以我们在循环里面遍历指针在去下一个位置的时候,需要将当前位置保存在父节点里面。除此之外,需要考虑要插入的结点应该链接到父节点的左边,还是右边,我们必须判断如果要插入的结点值比父节点的值大,就链接到父节点的右边,如果比父节点小的话就链接到父亲节点的左边,然后返回true,表示可以插入
c
bool insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return _root;
}
Node* parent = nullptr;
Node* cur =_root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key);
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
中序遍历
搜索二叉树的中序遍历就相当于从小到大排序,我们使用中序遍历来验证我们的插入.
因为我们的root是私有成员变量
所以我们采用一个共有的函数来调用私有的函数,这个私有的函数用来中序遍历
c
void _inorder()
{
return inorder(_root);
}
c
void inorder(Node* root)
{
if (root == nullptr)
return;
inorder(root->_left);
cout <<root->_key << " ";
inorder(root->_right);
}
二叉搜索树的查找
二叉树的查找和插入基本思路差不多,如果找到值一样的返回true;当遍历完没有一样的,就返回false;如果根节点是空的话就肯定没有要找的值返回false;
c
bool find(const K& key)
{
if (_root == nullptr)
{
return false;
}
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;
}
else if (cur->_key > key)
{
cur = cur->_left;
}
else
{
return true;
}
}
return false;
}
测试
c
void test()
{
bstree<int>st;
int a[] = { 8,3,1,10,6,4,7,14,13 };
for (auto e : a)
{
st.insert(e);
}
int ret=st.find(3);
int ret1 =st.find(100);
//st._inorder();
cout << ret << " ";
cout << ret1 << " ";
}
二叉搜索树的删除
情况1(叶子节点)
情况2(有一个孩子)
我们发现情况1可以归并到情况2中去.
情况3(有两个孩子)
c
bool earse(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
} //往上是在找值
else//找到了
{
if (cur->_left == nullptr)//处理情况2
{
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)//处理情况2
{
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
else//处理情况3,这里和图中不同的是去右子树找最左
{
Node* per = cur;
Node* nex = cur->_right;
while (nex->_left)
{
per = nex;
nex = nex->_left;
}
cur->_key = nex->_key;
per->_left = nex->_right;
delete nex;
}
return true;
}
}
return false;
}
情况1测试
情况2测试
情况3测试
这里还有一个问题,就是如果8没有右节点的话,也会崩溃.
同理左节点也是.
代码修改如下:
c
bool earse(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
if (cur->_left == nullptr)
{
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)
{ if (cur == _root)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
else
{
Node* per = cur;
Node* nex = cur->_right;
while (nex->_left)
{
per = nex;
nex = nex->_left;
}
cur->_key = nex->_key;
if (per->_left == nullptr)
{
per->_left = nex->_right;
}
else
{
per->_right = nex->_right;
}
delete nex;
}
return true;
}
}
return false;
}
3.源代码
tree.h
c
#pragma once
#include<iostream>
using namespace std;
template<class K>
struct bstreenode
{
bstreenode <K>* _left;
bstreenode <K>* _right;
K _key;
bstreenode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{
}
};
template<class K>
class bstree
{
typedef bstreenode<K> Node;
public:
bool insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return _root;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
cur = new Node(key);
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
void _inorder()
{
return inorder(_root);
}
bool find(const K& key)
{
if (_root == nullptr)
{
return false;
}
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;
}
else if (cur->_key > key)
{
cur = cur->_left;
}
else
{
return true;
}
}
return false;
}
bool earse(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
if (cur->_left == nullptr)
{
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)
{ if (cur == _root)
{
_root = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
else
{
Node* per = cur;
Node* nex = cur->_right;
while (nex->_left)
{
per = nex;
nex = nex->_left;
}
cur->_key = nex->_key;
if (per->_left == nullptr)
{
per->_left = nex->_right;
}
else
{
per->_right = nex->_right;
}
delete nex;
}
return true;
}
}
return false;
}
private:
Node* _root = nullptr;
void inorder(Node* root)
{
if (root == nullptr)
return;
inorder(root->_left);
cout <<root->_key << " ";
inorder(root->_right);
}
};
void test()
{
bstree<int>st;
int a[] = { 8,3,1,10,6,4,7,14,13 };
for (auto e : a)
{
st.insert(e);
}
st.earse(10);
st.earse(14);
st.earse(13);
st.earse(8);
st._inorder();
}
.cpp
c
#include"tree.h"
int main()
{
test();
}