二叉搜索树:它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
二叉搜索树有个特点,最左的是最小的节点,最右的是最大的节点。
当我们把二叉搜索树进行中序遍历的时候,它是进行排序后的结果,所以我们也把二叉搜索树叫做排序二叉树。
接下来我们介绍二叉排序树的所有的算法:
1.1搜索二叉树的结构
首先我们来看它的结构,他的结构和二叉树类似,所以会有一个左孩子节点的指针,一个右孩子节点的指针,还有一个被叫做键值的东西,我们通常来采用这个构建搜索二叉树,然后还有一个叫做关键值,我们用它来保存数据。
template<typename K,typename V>
struct SearchBinaryTreeNode
{
typedef SearchBinaryTreeNode<K,V> Node;
SearchBinaryTreeNode(const K& key)
: _left(NULL)
, _right(NULL)
, _key(key)
{
}
V _value;
Node* _left;
Node* _right;
K _key;
};
1.2构建搜索二叉树
构建搜索二叉树,我们这里采用的方式是采用数组来进行构建的。
SearchBinaryTree(const K* arr, size_t size)
{
assert(arr);
for (size_t i = 0; i < size; i++)
{
InsertP(arr[i]);
}
}
把数组中的每一个元素作为节点,进行插入。
1.3搜索二叉树的插入
搜索二叉树关键的算法之一,在这里,我们的思路就是当你插入一个节点,必须是所指向的位置为空时才可以查入,所以我们来查找我们所需要插入的位置,如果为空树,那么可以直接进行插入。
其他的用根节点的键值和key进行比较,如果key大于根节点键值,就说明在右子树如果小,那么就说明在右子树,如果相等,就说明已经出现了,不需要再次进行插入。最后如果我们所找到的位置为空那么这个时候我们就可以进行插入,插入的时候要看与父亲节点的key进行比较,如果小插入右边,如果大,插入左边。
bool Insert(const K& key)
{
if (_root == NULL)
{
_root = new Node(key);
return true;
}
Node *cur = _root;
Node *parent = _root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (curcur->_key>key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
Node *tmp = new Node(key);
if (key > parent->_key)
{
parent->_right = tmp;
}
else
{
parent->_left = tmp;
}
return true;
}
上面完成的是非递归的插入,另外,我们实现递归的插入,思路是一样的。
递归的插入在最后只有找到为空的时候才能进行插入节点,否则就进行递归。
bool _InsertP(Node *&root, const K& key)
{
if (root == NULL)
{
root = new Node(key);
return true;
}
if (root->_key > key)
{
_InsertP(root->_left, key);
}
else if (root->_key < key)
{
_InsertP(root->_right, key);
}
else
{
return false;
}
return true;
}
1.4搜索二叉树的删除
搜索二叉树的删除算法算是最难的了。在这里我们需要考虑几种思路。
- 没有这个节点
- 删除根节点
- 删除左子树为空的节点
- 删除右子树为空的节点
- 删除左右子书都不为空的节点
首先我们要做的是找到这个节点,然后找到这个节点的算法就类似与查找节点。
接下来我们要做的是分情况进行讨论。
如果没有这个节点,我们就不删了,return。
接下来看它的孩子,当它孩子任意一个为空的时候,看他的孩子时要考虑删除根节点的情况。删除根节点,这个时候终点是改变root,另外的删除其他节点,找到这个节点,然后看这个节点和父亲节点的关系,进行调整就好了。
然后,进行讨论两个孩子都有的情况,首先我们就是利用交换的方式进行删除,思路就是找到删除节点的第一个右子树节点的最左节点或者左子树第一个节点的最右节点。简单的说,就是把根变作左子树最大的或者右子树最小的。
综合这个思路我们就可以完成删除。
bool Remove(const K& key)
{
Node *cur = _root;
Node *parent = NULL;
Node *del = NULL;
while (cur&&cur->_key!=key)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key>key)
{
parent = cur;
cur = cur->_left;
}
else
{
break;
}
}
if (cur == NULL)
{
return false;
}
if (cur->left == NULL)
{
del = cur;
if (parent == NULL)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
}
else if (cur->_right==NULL)
{
del = cur;
if (parent == NULL)
{
cur = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_right;
}
}
}
else
{
Node *swapnode = cur->_right;
while (swapnode->_left)
{
parent = swapnode;
swapnode = swapnode->_left;
}
del = swapnode;
cur->_key = swapnode->_key;
cur->_value = swapnode->_value;
if (parent->_left == swapnode)
parent->_left = swapnode->_right;
else
parent->_right = swapnode->_right;
}
delete del;
del = NULL;
return true;
}
接下来介绍递归的删除:
递归的删除的思路和上面的是一样的,重点是在于理解递归。
递归的时候进行的也先是查找,如果找不到返回,找到进行删除。
这个时候我们也是一样,看root节点的孩子进行分布操作,如果左为空,那么就给root右,右为空,就给左,在这里,其实这个root的含义相当于是parent的左指针或右指针。因为是递归,所以就是上一层函数左指针或者右指针。然后其他的和上面的思路是一样的。
bool _RemoveP(Node *&root, const K& key)
{
if (root == NULL)
{
return false;
}
if (root->_key < key)
{
_RemoveP(root->_right,key);
}
else if (root->_key > key)
{
_RemoveP(root->_left,key);
}
else
{
Node* del = root;
if (root->_left == NULL)
{
root = root->_right;
}
else if (root->_right == NULL)
{
root = root->_left;
}
else
{
Node* parent = root;
Node *swapnode = root->_right;
while (swapnode->_left)
{
parent = swapnode;
swapnode = swapnode->_left;
}
root->_key = swapnode->_key;
root->_value = swapnode->_value;
if (parent->_right == swapnode)
parent->_right = swapnode->_right;
else
parent->_left = swapnode->_right;
del = swapnode;
}
delete del;
return true;
}
return false;
}
1.5搜索二叉树的查找
搜索二叉树的查找,这个算法其实上面我们在删除已经进行过了,下面进行简单的介绍一下,你要搜索的,那么就是和根的key比较,如果大于根的key,那么就找右树,如果小于根的key,那么就找左树。相等,就代表找到了。
bool Find(const K &key)
{
if (_root == NULL)
return false;
Node *cur = _root;
while (cur)
{
if (key > cur->_key)
{
cur = cur->_left;
}
else if (key < cur->_key)
{
cur = cur->_right;
}
else
{
return true;
}
}
return false;
}
下来是递归查找,思路上同,就不多说了。
bool _FindP(Node * root,const K& key)
{
if (root == NULL)
{
return false;
}
if (key < root->_key)
{
return _FindP(root->_left, key);
}
else if (key>root->_key)
{
return _FindP(root->_right, key);
}
else
{
return true;
}
return false;
}
1.5搜索二叉树的MAX和MIN
另外的算法就是找最小和最大
这两个算法就是查找算法的变形,一个是右子树的最右节点,一个是左子树的最左节点。
const K& Minvalue()
{
assert(_root);
Node* cur = _root;
while (cur->_left)
{
cur = cur->_left;
}
return cur->_value;
}
const K& Maxvalue()
{
assert(_root);
Node *cur = _root;
while (cur->_right)
{
cur = cur->_right;
}
return cur->_value;
}
其他搜索二叉树的算法和二叉树的类似,可以查看我的二叉树的博客来查看。
代码(全):
#pragma once
#include<iostream>
#include<cstdlib>
#include<cassert>
using namespace std;
template<typename K,typename V>
struct SearchBinaryTreeNode
{
typedef SearchBinaryTreeNode<K,V> Node;
SearchBinaryTreeNode(const K& key)
: _left(NULL)
, _right(NULL)
, _key(key)
{
}
V _value;
Node* _left;
Node* _right;
K _key;
};
template<typename K,typename V>
class SearchBinaryTree
{
protected:
typedef SearchBinaryTreeNode<K,V> Node;
public:
SearchBinaryTree(const K* arr, size_t size)
{
assert(arr);
for (size_t i = 0; i < size; i++)
{
InsertP(arr[i]);
}
}
~SearchBinaryTree()
{
_root=_DestorySBT(_root);
}
bool InsertP(const K& key)
{
return _InsertP(_root, key);
}
bool Insert(const K& key)
{
if (_root == NULL)
{
_root = new Node(key);
return true;
}
Node *cur = _root;
Node *parent = _root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (curcur->_key>key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
Node *tmp = new Node(key);
if (key > parent->_key)
{
parent->_right = tmp;
}
else
{
parent->_left = tmp;
}
return true;
}
bool RemoveP(const K& key)
{
return _RemoveP(_root, key);
}
bool Remove(const K& key)
{
Node *cur = _root;
Node *parent = NULL;
Node *del = NULL;
while (cur&&cur->_key!=key)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key>key)
{
parent = cur;
cur = cur->_left;
}
else
{
break;
}
}
if (cur == NULL)
{
return false;
}
if (cur->left == NULL)
{
del = cur;
if (parent == NULL)
{
_root = cur->_right;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
}
else if (cur->_right==NULL)
{
del = cur;
if (parent == NULL)
{
cur = cur->_left;
}
else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_right;
}
}
}
else
{
Node *swapnode = cur->_right;
while (swapnode->_left)
{
parent = swapnode;
swapnode = swapnode->_left;
}
del = swapnode;
cur->_key = swapnode->_key;
cur->_value = swapnode->_value;
if (parent->_left == swapnode)
parent->_left = swapnode->_right;
else
parent->_right = swapnode->_right;
}
delete del;
del = NULL;
return true;
}
void Inorderprint()
{
_Inorderprint(_root);
cout << endl;
}
bool Empty()
{
return _root == NULL;
}
bool Find(const K &key)
{
if (_root == NULL)
return false;
Node *cur = _root;
while (cur)
{
if (key > cur->_key)
{
cur = cur->_left;
}
else if (key < cur->_key)
{
cur = cur->_right;
}
else
{
return true;
}
}
return false;
}
bool FindP(const K &key)
{
return _FindP(_root, key);
}
const K& Top()
{
return _root->_key;
}
const K& Minvalue()
{
assert(_root);
Node* cur = _root;
while (cur->_left)
{
cur = cur->_left;
}
return cur->_value;
}
const K& Maxvalue()
{
assert(_root);
Node *cur = _root;
while (cur->_right)
{
cur = cur->_right;
}
return cur->_value;
}
protected:
Node* _DestorySBT(Node *root)
{
if (root != NULL)
{
root->_left = _DestorySBT(root->_left);
root->_right = _DestorySBT(root->_right);
delete root;
root = NULL;
}
return root;
}
void _Inorderprint(Node *root)
{
if (root == NULL)
return;
_Inorderprint(root->_left);
cout << root->_key << " ";
_Inorderprint(root->_right);
}
bool _InsertP(Node *&root, const K& key)
{
if (root == NULL)
{
root = new Node(key);
return true;
}
if (root->_key > key)
{
_InsertP(root->_left, key);
}
else if (root->_key < key)
{
_InsertP(root->_right, key);
}
else
{
return false;
}
return true;
}
bool _RemoveP(Node *&root, const K& key)
{
if (root == NULL)
{
return false;
}
if (root->_key < key)
{
_RemoveP(root->_right,key);
}
else if (root->_key > key)
{
_RemoveP(root->_left,key);
}
else
{
Node* del = root;
if (root->_left == NULL)
{
root = root->_right;
}
else if (root->_right == NULL)
{
root = root->_left;
}
else
{
Node* parent = root;
Node *swapnode = root->_right;
while (swapnode->_left)
{
parent = swapnode;
swapnode = swapnode->_left;
}
root->_key = swapnode->_key;
root->_value = swapnode->_value;
if (parent->_right == swapnode)
parent->_right = swapnode->_right;
else
parent->_left = swapnode->_right;
del = swapnode;
}
delete del;
return true;
}
return false;
}
bool _FindP(Node * root,const K& key)
{
if (root == NULL)
{
return false;
}
if (key < root->_key)
{
return _FindP(root->_left, key);
}
else if (key>root->_key)
{
return _FindP(root->_right, key);
}
else
{
return true;
}
return false;
}
protected:
Node * _root;
};
另外代码已上传github,链接:https://github.com/wsy081414/data-structure/blob/master/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9B%B8%E5%85%B3/%E6%90%9C%E7%B4%A2%E4%BA%8C%E5%8F%89%E6%A0%91.h