二叉搜索树
Binary Search Tree
静态查找, 动态查找
无序链表:灵活性好
有序数组:效率高
直接把元素放在树上,树的动态性强。
这种方式查找,即灵活又效率高。
二叉搜索树,又称有序二叉树,排序二叉树
顾名思义用来排序,何以排序,键值比大小
键 : key 排序用的是key,权值
值 :value 有意义的数据
性质:
1.非空左子树的键值均小于根结点;
2.非空右子树的键值小均于根结点;
3.左,右子树都是二叉树。
构造结点
老规矩,树形数据结构先来构造结点-》 注意多出了key 与 value
template <class K>
struct BinarySearchTreeNode
{
K _k;
V _v;
BinarySearchTreeNode<K>* _left;
BinarySearchTreeNode<K>* _right;
BinarySearchTreeNode(const K& k, const V& v)
: _k(k)
: _v(v)
, _left(NULL)
, _right(NULL)
{}
};
基本操作:
查找操作:key的作用是来排序,所以用它来查找,循环比较结点的key,小进入左子树,大进入右子树
相等时返回key 或 value
Node* Find(const T& x, Node* root)
{
if (root == NULL)
return NULL;
if ( x == root->_t)
return root;
if ( x < root->_t)
return Find(root->_left); //尾递归 可以用循环来实现
else ( x > root->_t)
return Find(root->_right);
else
error(flase);
}
找最值元素 : 根据他的概念不难知道
最大元素一定在最右边
最小元素一定在最左边
Node* FindMin(Node* root)
{
while(root)
{
if (root->left)
root = root->left;
}
return NULL;
}
结点的插入: 1.首先找到他所在的位置,类似查找函数
2判断有没有相同的key值,如果有更新
3.没有,就直接插入
bool Insert(const K& k)
{
Node* root = _root;
Node* par = root;
if (_root == NULL)
{
_root = new Node(k);
//_root = root;
return true;
}
while (root)
{
if (k < root->_k)
{
par = root;
root = root->_left;
}
else if (k > root->_k)
{
par = root;
root = root->_right;
}
else
return false;
}
if (k < par->_k)
par->_left = new Node(k);
else
par->_right = new Node(k);
return true;
}
结点的删除 -》删除操作是很重要的操作,要不能影响其他的节点,具体为三种情况。
1.叶子结点,直接删除,置空
2.只有一个孩子结点,删除自己,父亲指向自己孩子
3.有俩个孩子结点,在左子树里找一个最大的数 或在右子树里找一个最小的树替换 转换为1 2种情况。
why: 因为右子树的最小值一定不会有俩个儿子,这样交换之后可以删除。
何为右子树的最小值,上面有讲最值问题,最左边的节点一定最小。交换之后,因为他是从右子树交换上来所以一定比左树的值都大,又是比右树都小的,所以不影响。
bool Removed(const K& k)
{
Node* root = _root;
Node* par = _root;
if (!root)
return false;
while (root)
{
if (k < root->_k)
{
par = root;
root = root->_left;
}
else if (k > root->_k)
{
par = root;
root = root->_right;
}
else if (k == root->_k)
break;
}
if (!root)
return false;
//1,当他为叶子结点时,直接删
if (root->_left == NULL && root->_right == NULL)
{
if (par->_left == root)
par->_left = NULL;
else if (par->_right == root)
par->_right = NULL;
/*else
error(false);*/
delete root;
return true;
}
//2.当他左树不为空时,找出左树中最大节点为交换值,删除
if (root->_left != NULL)
{
par = root;
Node* cur = root->_left;
while (cur->_right)
{
par = cur;
cur = cur->_right;
}
_Swap(root, cur);
if (par->_left == cur)
par->_left = cur->_left;
else if (par->_right == cur)
par->_right = cur->_left;
delete cur;
}
//3,只有右子树
else if (root->_right != NULL)
{
if (root == par->_left)
par->_left = root->_right;
else if (par->_right == root)
par->_right = root->_right;
delete root;
}
}
效率分析
我们不难看出当某一端高度过高时,运行时间会变慢,为了让高度相近,就为平衡树。
当插入顺序最好时,为平衡树,此时效率最高为lgn;
所以 如何BST树构造为平衡数才是重点。