二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值 3.它的左右子树也分别为二叉搜索树
int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};
a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。 b、最多查找高度次,走到到空,还没找到,这个值不存在。
bool nfind(const T& x)
{
return _nfind(root, x);
}
bool _nfind(node* root, const T& x)
{
if (root)
{
if (root->data > x)
{
return _nfind(root->left, x);
}
else if (root->data < x)
{
return _nfind(root->right, x);
}
else
{
return true;
}
}
else
{
return false;
}
}
a. 树为空,则直接新增节点,赋值给root指针 b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
bool Insert(const T& x)
{
return _Insert(root, x);
}
bool _Insert(node*& root, const T& x) //记得要加引用,规避了找父亲连接子节点的问题
{
if (root == nullptr)
{
root = new node(x);
return true;
}
else if (root->data < x)
{
return _Insert(root->right, x);
}
else if (root->data > x)
{
return _Insert(root->left, x);
}
else {
return false;
}
}
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情 况:
a. 要删除的结点无孩子结点 b. 要删除的结点只有左孩子结点 c. 要删除的结点只有右孩子结点 d. 要删除的结点有左、右孩子结点
看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程 如下:
情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点 中,再来处理该结点的删除问题--替换法删除//找左子树最大或右子树最小
namespace zone
{
template<class T>
struct bstnode
{
bstnode(const T& x)
:left(nullptr)
, right(nullptr)
, data(x)
{}
bstnode<T>* left;
bstnode<T>* right;
T data;
};
template<class T>
class bst
{
typedef bstnode<T> node;
public:
bool Insert(const T& x)
{
return _Insert(root, x);
}
bool _Insert(node*& root, const T& x) //记得要加引用,规避了找父亲连接子节点的问题
{
if (root == nullptr)
{
root = new node(x);
return true;
}
else if (root->data < x)
{
return _Insert(root->right, x);
}
else if (root->data > x)
{
return _Insert(root->left, x);
}
else {
return false;
}
}
bool nfind(const T& x)
{
return _nfind(root, x);
}
bool _nfind(node* root, const T& x)
{
if (root)
{
if (root->data > x)
{
return _nfind(root->left, x);
}
else if (root->data < x)
{
return _nfind(root->right, x);
}
else
{
return true;
}
}
else
{
return false;
}
}
bool erase(const T& x)
{
return _erase(root, x);
}
bool _erase(node*& root, const T& x)
{
if (root)
{
if (root->data > x)
{
_erase(root->left, x);
}
else if (root->data < x)
{
_erase(root->right, x);
}
else //开始删除
{
if (root->left == nullptr) //左为空
{
node* ptr = root;
root = root->right;
delete ptr;
}
else if (root->right == nullptr) //右为空
{
node* ptr = root;
root = root->left;
delete ptr;
}
else //左右都不为空,找右子树最小的
{
/*node* it = root->right;
while (it->left)
{
it = it->left;
}
std:swap(root->data, it->data);
return _erase(root->right,x);*/ //从原应当删除的位置的右子树开始删除x!!!!!!!!!!!
node* it = root->left; //左右都不为空,找左子树最大的
while (it->right)
{
it = it->right;
}
std:swap(root->data, it->data);
return _erase(root->left, x); //从原应当删除的位置的左子树开始删除x!!!!!!!!!!!
}
}
}
else
{
return false;
}
}
bst()
{}
bst(const bst<T>& it) //拷贝构造 s1(s2)
{
creat(root, it.root);
}
bst<T>& operator = (bst<T>& it) //拷贝构造 s1=s2
{
swap(root, it.root);
return *this;
}
~bst()
{
destroy(this->root);
}
void destroy(node* root)
{
if (root == nullptr);
return;
destroy(root->left);
destroy(root->right);
delete root;
}
void creat(node*& root1, node* root2)
{
if (root1 == nullptr && root2 == nullptr)
{
root1 = nullptr;
}
else if (root1 == nullptr && root2 != nullptr)
{
node* newnode = new node(root2->data);
root1 = newnode;
creat(root1->left, root2->left);
creat(root1->right, root2->right);
}
}
void inorder() //!!!!!二叉搜索树中序遍历的结果是升序打印
{
_inorder(root);
}
void _inorder(node* root)
{
if (root == nullptr)
return;
_inorder(root->left);
cout << root->data << " ";
_inorder(root->right);
}
private:
node* root = nullptr;
};
}
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
1.以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树 2.在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
1.比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英 文单词与其对应的中文就构成一种键值对; 2.再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出 现次数就是就构成一种键值对。
这里以字典为例:
bst.h:
namespace dictionary
{
template<class T,class K>
struct bstnode
{
bstnode(const T& x, const K& y)
:left(nullptr)
, right(nullptr)
, data(x)
, t(y)
{}
bstnode<T,K>* left;
bstnode<T,K>* right;
T data;
K t;
};
template<class T,class K>
class bst
{
typedef bstnode<T,K> node;
public:
bool Insert(const T& x, const K& y)
{
return _Insert(root,x,y);
}
bool _Insert(node*& root, const T& x, const K& y) //记得要加引用,规避了找父亲连接子节点的问题
{
if (root == nullptr)
{
root = new node(x,y);
return true;
}
else if (root->data < x)
{
return _Insert(root->right,x,y);
}
else if (root->data > x)
{
return _Insert(root->left,x,y);
}
else {
return false;
}
}
node* nfind(const T& x)
{
return _nfind(root, x);
}
node* _nfind(node* root, const T& x)
{
if (root)
{
if (root->data > x)
{
return _nfind(root->left, x);
}
else if (root->data < x)
{
return _nfind(root->right, x);
}
else
{
return root;
}
}
else
{
return nullptr;
}
}
bst()
{}
~bst()
{
destroy(this->root);
}
void destroy(node* root)
{
if (root == nullptr);
return;
destroy(root->left);
destroy(root->right);
delete root;
}
private:
node* root = nullptr;
};
}
test.c:
#include<iostream>
using namespace std;
#include"bst.h"
int main()
{
//int arr[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
//bst<int> t;
//for (auto s : arr)
//{
// t.Insert(s);
//}
t.erase(8);
//bst<int> q(t);
//q.inorder();
///*if (t.nfind(15))
//{
// cout << "1" << endl;
//}*/
dictionary::bst<string, string>dic;
dic.Insert("sort", "排序");
dic.Insert("tree", "树");
dic.Insert("left", "左");
dic.Insert("right", "右");
dic.Insert("root", "根");
string str;
while (cin >> str)
{
dictionary::bstnode<string, string>* set;
set=dic.nfind(str);
if (set)
cout << set->t << " ";
else
cout << "无此单词" << endl;
}
}
字典中插入了: ("sort", "排序"); ("tree", "树"); ("left", "左"); ("right", "右"); ("root", "根");