0_二分搜索树的定义
- 它是一颗二叉树
- 每个节点的键值大于左孩子
- 每个节点的键值小于右孩子
- 以左右孩子为根的子树仍为二分搜索树
- 不一定是完全二叉树
#include <iostream>
using namespace std;
template <typename Key, typename Value>
class BST{
private:
//树节点的定义,以键值对的形式来保存数据
struct Node{
Key key;
Value value;
Node *left;
Node *right;
Node(Key key, Value value){
this->key = key;
this->value = value;
this->left = this->right = NULL;
}
Node(Node* node){
this->key = node->key
this->value = node->value;
this -> left = node->left;
this->right = node->right;
}
};
Node *root;
int count;
public:
BST(){
root = NULL;
count = 0;
}
~BST(){
}
int size(){
return count;
}
bool isEmpty(){
return count == 0;
}
};
int main() {
return 0;
}
1_二分查找
template<typename T>
int binarySearch(T arr[],int n,T target){
int l = 0,r = n-1;
int mid;
while( l <= r ){
mid = l + (r-l)/2;
if(arr[mid] == target)
return mid;
if(arr[mid]>target)
r = mid-1;
else l = mid+1;
}
return -1;
}
2_向搜索树种插入数据
void insert(Key key,Value value){
root = insert(root,key,value);
}
Node* insert(Node* node,Key key,Value value){
if(node == nullptr){
count ++;
return new Node(key,value);
}
if(key == node->key)
node->value = value;
else if(key < node->key)
node->left = insert(node->left,key,value);
else node->right = insert(node->right,key,value);
return node;
}
3_搜索树查找
bool contain(Key key){
return contain(root,key);
}
Value* search(Key key){
search(root,key);
}
bool contain(Node* node,Key key){
if(node == nullptr) return false;
if(node->key == key)
return true;
else if(node->key > key)
return contain(node->left,key);
else return contain(node->right,key);
}
Value* search(Node* node,Key key){
if(node == nullptr) return nullptr;
if(node->key == key )
return &(node->value);
if(node->key < key)
return search(node->right,key);
else return search(node->left,key);
}
4_二叉搜索树的遍历
- 前序遍历: 先访问当前节点,然后依次递归访问左右子树
- 中序遍历: 先递归访问左子树,再访问自身,然后递归访问右子树
- 后续遍历: 先递归访问左右子树,再访问自身节点
void preOrder(){
preOrder(root);
}
void inOrder(){
inOrder(root);
}
void postOrder(){
postOrder(root);
}
void preOrder(Node* node){
if(node == nullptr) return ;
cout << node->key << endl;
preOrder(node->left);
preOrder(node->right);
}
void inOrder(Node* node){
if(node == nullptr) return;
inOrder(node->left);
cout << node->key << endl;
inOrder(node->right);
}
void postOrder(Node* node){
if(node == nullptr ) return;
postOrder(node->left);
postOrder(node->right);
cout << node->key << endl;
}
5_析构一个二叉搜索树
~BST(){
destroy(root);
}
void destroy(Node* node){
if(node == nullptr) return;
destroy(node->left);
destroy(node->right);
delete node;
count--;
}
6_广度优先遍历
- 前中序遍历都是采用的深度优先遍历
- 广度优先采用队列的形式来进行:先让当前节点入队,当当前节点出队的时候将其左右子节点依次入队(如果存的话),直到队列为空,程序完成
- 四种遍历的时间复杂度都为O(N);
using std::queue;
void levelOrder(){
queue<Node*> q;
q.push(root);
while(!q.empty()){
Node* node = q.front();
q.pop();
cout << node->key << endl;
if(node->left != nullptr){
q.push(node->left);
}
if(node->right != nullptr){
q.push(node->right);
}
}
}
7.1_寻找二叉搜索树的最小/最大值
- 不难发现最左边的节点是最小值节点
- 最右边的节点是最大值节点
Key minimum(){
assert(count != 0);
Node* minNode = minimum(root);
return minNode->key;
}
Key maximum(){
assert(count != 0);
Node* maxNode = maximum(root);
return maxNode->key;
}
Node* minimum(Node* node){
if(node->left == nullptr)
return node;
return minimum(node->left);
}
Node* maximum(Node* node){
if(node->right == nullptr)
return node;
return maximum(node->right);
}
7.2_删除二叉搜索树的最大/最大值
void removeMin(){
if(root)
root = removeMin(root);
}
void removeMax(){
if(root)
root = removeMax(root);
}
Node* removeMin(Node* node){
if(node->left == nullptr){
Node* rightNode = node->right;
delete node;
count--;
return rightNode;
}
node->left = removeMin(node->left);
}
Node* removeMax(Node* node){
if(node->right == nullptr){
Node* leftNode = node->left;
delete node;
count--;
return leftNode;
}
node->right = removeMax(node->right);
}
8_二叉搜索树种删除任意位置的节点
- 1962年,Hibbard提出的-Hubbard Deletion
- 删除任意节点的时间复杂度为O(N)
- 要删除节点d,可以先找到s = min(d->right)中的节点
- s是d的后继节点,d被删除后s代替d原来的位置,删除s原来的位置 s->right = delMin(d->right);s-left = d->left;
void remove(Key key){
root = remove(root,key);
}
Node* remove(Node* node,Key key){
if(node == nullptr)
return nullptr;
if(key < node->key){
node->left = remove(node->left,key);
return node;
}
else if(key > node->key){
node->right = remove(node->right,key);
return node;
}
else {
if(node->left == nullptr){
Node* rightNode = node->right;
delete node;
count--;
return rightNode;
}
else if(node->right == nullptr){
Node* leftNode = node->left;
delete node;
count--;
return leftNode;
}
else{
Node* successor = new Node(minimum(node->right));
count++;
successor->right = removeMin(node->right);
successor->left = node->left;
delete node;
count--;
return successor;
}
}
}
9_二叉搜索树的一些常见推广
- 当数据有较多重复的话,可以给每个Node节点一个count变量统计多少个重复元素
- 二叉搜索树会出现退化,极端情况下会退化成一个单链表,效率上会大大折扣;–可以采用平衡二叉树来避免
- 平衡二叉树和堆的结合:Treap;
- trie可以处理更多数据集的一种数据结构