• 算法-二分查找与树的增删改查


    查找算法

    二分查找

    非递归版的

    // 二分查找法,在有序数组arr中,查找target
    // 如果找到target,返回相应的索引index
    // 如果没有找到target,返回-1
    template<typename T>
    int binarySearch(T arr[], int n, T target){
    
        // 在arr[l...r]之中查找target
        int l = 0, r = n-1;
        while( l <= r ){
    
            //int mid = (l + r)/2;
            // 防止极端情况下的整形溢出,使用下面的逻辑求出mid
            int mid = l + (r-l)/2;
    
            if( arr[mid] == target )
                return mid;
    
            if( arr[mid] > target )
                r = mid - 1;
            else
                l = mid + 1;
        }
    
        return -1;
    }
    

    递归版的

    // 用递归的方式写二分查找法
    template<typename T>
    int __binarySearch2(T arr[], int l, int r, T target){
    
        if( l > r )
            return -1;
    
        //int mid = (l+r)/2;
        // 防止极端情况下的整形溢出,使用下面的逻辑求出mid
        int mid = l + (r-l)/2;
    
        if( arr[mid] == target )
            return mid;
        else if( arr[mid] > target )
            return __binarySearch2(arr, l, mid-1, target);
        else
            return __binarySearch2(arr, mid+1, r, target);
    }
    
    template<typename T>
    int binarySearch2(T arr[], int n, T target){
    
        return __binarySearch2( arr , 0 , n-1, target);
    }
    

    floor实现
    二分查找法, 在有序数组arr中, 查找target,如果找到target, 返回第一个target相应的索引index,如果没有找到target, 返回比target小的最大值相应的索引, 如果这个最大值有多个, 返回最大索引,如果这个target比整个数组的最小元素值还要小, 则不存在这个target的floor值, 返回-1

    template<typename T>
    int floor(T arr[], int n, T target){
    
        assert( n >= 0 );
    
        // 寻找比target小的最大索引
        int l = -1, r = n-1;
        while( l < r ){
            // 使用向上取整避免死循环
            int mid = l + (r-l+1)/2;
            if( arr[mid] >= target )
                r = mid - 1;
            else
                l = mid;
        }
    
        assert( l == r );
    
        // 如果该索引+1就是target本身, 该索引+1即为返回值
        if( l + 1 < n && arr[l+1] == target )
            return l + 1;
    
        // 否则, 该索引即为返回值
        return l;
    }
    

    ceil实现
    二分查找法, 在有序数组arr中, 查找target,如果找到target, 返回最后一个target相应的索引index,如果没有找到target, 返回比target大的最小值相应的索引, 如果这个最小值有多个, 返回最小的索引,如果这个target比整个数组的最大元素值还要大, 则不存在这个target的ceil值, 返回整个数组元素个数n

    template<typename T>
    int ceil(T arr[], int n, T target){
    
        assert( n >= 0 );
    
        // 寻找比target大的最小索引值
        int l = 0, r = n;
        while( l < r ){
            // 使用普通的向下取整即可避免死循环
            int mid = l + (r-l)/2;
            if( arr[mid] <= target )
                l = mid + 1;
            else // arr[mid] > target
                r = mid;
        }
    
        assert( l == r );
    
        // 如果该索引-1就是target本身, 该索引+1即为返回值
        if( r - 1 >= 0 && arr[r-1] == target )
            return r-1;
    
        // 否则, 该索引即为返回值
        return r;
    }
    

    二分查找树插入与查找与遍历算法

    递归写法

    #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 *root; // 根节点
        int count;  // 树中的节点个数
    
    public:
        // 构造函数, 默认构造一棵空二分搜索树
        BST(){
            root = NULL;
            count = 0;
        }
         ~BST(){
            destroy( root );
        }
    
        // 返回二分搜索树的节点个数
        int size(){
            return count;
        }
    
        // 返回二分搜索树是否为空
        bool isEmpty(){
            return count == 0;
        }
    
        // 向二分搜索树中插入一个新的(key, value)数据对
        void insert(Key key, Value value){
            root = insert(root, key, value);
        }
    
        // 查看二分搜索树中是否存在键key
        bool contain(Key key){
            return contain(root, key);
        }
    
        // 在二分搜索树中搜索键key所对应的值。如果这个值不存在, 则返回NULL
        Value* search(Key key){
            return search( root , key );
        }
        // 二分搜索树的前序遍历
        void preOrder(){
            preOrder(root);
        }
    
        // 二分搜索树的中序遍历
        void inOrder(){
            inOrder(root);
        }
    
        // 二分搜索树的后序遍历
        void postOrder(){
            postOrder(root);
        }
        // 二分搜索树的层序遍历
        void levelOrder() {
    
            if (root == NULL) return;
    
            queue<Node *> q;
            q.push(root);
            while (!q.empty()) {
    
                Node *node = q.front();
                q.pop();
    
                cout << node->key << endl;
    
                if (node->left)
                    q.push(node->left);
                if (node->right)
                    q.push(node->right);
            }
        }
        // 从二分搜索树中删除最小值所在节点
        void removeMin(){
            if( root )
                root = removeMin( root );
        }
    
        // 从二分搜索树中删除最大值所在节点
        void removeMax(){
            if( root )
                root = removeMax( root );
        }
        // 从二分搜索树中删除键值为key的节点
        void remove(Key key){
            root = remove(root, key);
        }
    private:
        // 向以node为根的二分搜索树中, 插入节点(key, value), 使用递归算法
        // 返回插入新节点后的二分搜索树的根
        Node* insert(Node *node, Key key, Value value){
    
            if( node == NULL ){
                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    // key > node->key
                node->right = insert( node->right, key, value);
    
            return node;
        }
    
        // 查看以node为根的二分搜索树中是否包含键值为key的节点, 使用递归算法
        bool contain(Node* node, Key key){
    
            if( node == NULL )
                return false;
    
            if( key == node->key )
                return true;
            else if( key < node->key )
                return contain( node->left , key );
            else // key > node->key
                return contain( node->right , key );
        }
    
        // 在以node为根的二分搜索树中查找key所对应的value, 递归算法
        // 若value不存在, 则返回NULL
        Value* search(Node* node, Key key){
    
            if( node == NULL )
                return NULL;
    
            if( key == node->key )
                return &(node->value);
            else if( key < node->key )
                return search( node->left , key );
            else // key > node->key
                return search( node->right, key );
        }
        // 对以node为根的二叉搜索树进行前序遍历, 递归算法
        void preOrder(Node* node){
    
            if( node != NULL ){
                cout<<node->key<<endl;
                preOrder(node->left);
                preOrder(node->right);
            }
        }
    
        // 对以node为根的二叉搜索树进行中序遍历, 递归算法
        void inOrder(Node* node){
    
            if( node != NULL ){
                inOrder(node->left);
                cout<<node->key<<endl;
                inOrder(node->right);
            }
        }
    
        // 对以node为根的二叉搜索树进行后序遍历, 递归算法
        void postOrder(Node* node){
    
            if( node != NULL ){
                postOrder(node->left);
                postOrder(node->right);
                cout<<node->key<<endl;
            }
        }
    
        // 释放以node为根的二分搜索树的所有节点
        // 采用后续遍历的递归算法
        void destroy(Node* node){
    
            if( node != NULL ){
                destroy( node->left );
                destroy( node->right );
    
                delete node;
                count --;
            }
        }
        // 删除掉以node为根的二分搜索树中的最小节点
        // 返回删除节点后新的二分搜索树的根
        Node* removeMin(Node* node){
    
            if( node->left == NULL ){
    
                Node* rightNode = node->right;
                delete node;
                count --;
                return rightNode;
            }
    
            node->left = removeMin(node->left);
            return node;
        }
    
        // 删除掉以node为根的二分搜索树中的最大节点
        // 返回删除节点后新的二分搜索树的根
        Node* removeMax(Node* node){
    
            if( node->right == NULL ){
    
                Node* leftNode = node->left;
                delete node;
                count --;
                return leftNode;
            }
    
            node->right = removeMax(node->right);
            return node;
        }
        // 删除掉以node为根的二分搜索树中键值为key的节点, 递归算法
        // 返回删除节点后新的二分搜索树的根
        Node* remove(Node* node, Key key){
    
            if( node == NULL )
                return NULL;
    
            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{   // key == node->key
    
                // 待删除节点左子树为空的情况
                if( node->left == NULL ){
                    Node *rightNode = node->right;
                    delete node;
                    count --;
                    return rightNode;
                }
    
                // 待删除节点右子树为空的情况
                if( node->right == NULL ){
                    Node *leftNode = node->left;
                    delete node;
                    count--;
                    return leftNode;
                }
    
                // 待删除节点左右子树均不为空的情况
    
                // 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点
                // 用这个节点顶替待删除节点的位置
                Node *successor = new Node(minimum(node->right));
                count ++;
    
                successor->right = removeMin(node->right);
                successor->left = node->left;
    
                delete node;
                count --;
    
                return successor;
            }
        }
    };
    
    int main() {
    
        return 0;
    }
    
  • 相关阅读:
    【LOJ#6277】数列分块1
    【LOJ6284】数列分块8
    【洛谷P3275】糖果
    【洛谷P3810】陌上花开
    【洛谷P1052】过河 离散化+dp
    【洛谷P2042】维护数列
    【模板】文艺平衡树
    【洛谷P4145】花神游历各国
    【洛谷P4878】布局
    hdu 5748(LIS)
  • 原文地址:https://www.cnblogs.com/ygjzs/p/12761521.html
Copyright © 2020-2023  润新知