二叉搜索树

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(){
        // TODO: ~BST()
    }

    int size(){
        return count;
    }

    bool isEmpty(){
        return count == 0;
    }
};

int main() {

    return 0;
}

1_二分查找

  • 没什么好说的,mid那里处理下越界的可能即可
//查找target是否是arr数组中,找到返回其索引
//找不到返回-1
template<typename T>
int binarySearch(T arr[],int n,T target){
    // 在arr[l,r]中查找target
    int l = 0,r = n-1;
    int mid;
    while( l <= r ){
       // mid = ( l + r )/2;
        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为节点的搜索树种插入节点(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_搜索树查找

//检查key是否在搜索树种
bool contain(Key key){
        return contain(root,key);
    }
//找到key保存的value值,如果存在返回其指针
//不存在返回nullptr;
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);
    }

//以node为根节点的前序遍历
    void preOrder(Node* node){
        if(node == nullptr) return ;

        cout << node->key << endl;
        preOrder(node->left);
        preOrder(node->right);

    }
    //以node为根节点的中序遍历
    void inOrder(Node* node){
        if(node == nullptr) return;

        inOrder(node->left);
        cout << node->key << endl;
        inOrder(node->right);

    }
    //以node为根节点的后序遍历
    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);
//层序遍历
//#inlcude <queue>
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为根节点的搜索树中,返回最小键值的节点
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为根节点的搜索树中的最小节点
//返回删除节点后新的二叉搜索树的根
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;
//从二叉搜索树中删除任意键值为key的节点
void remove(Key key){
    root = remove(root,key);
}
//删除掉以node为根的二叉搜索树中键值为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可以处理更多数据集的一种数据结构
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值