• 二叉搜索树


    思路

    二叉排序树,二叉搜索树好像都行,原理应该都懂,比较基础,但要写出来还是有相当大的难度的。

    查找

    查找比较简单,基本都是一个while就解决。但查前驱与后继较难,可能需要上溯父节点。

    • 任意键值
    • 查最值
    • 查某键值的前驱或后继
    • 先序,中序,后序遍历

    修改

    修改键-值对,这个非常简单,查找出来即可。

    增加

    插入节点,比较简单。找到空节点插入即可

    删除

    比较复杂,分3种大情况,其中第3种又分两种情况

    1. 删除的节点没有左右孩子节点
    2. 删除的节点只有一个孩子节点
    3. 删除的节点有两个孩子节点
      1. 该节点的后继是右孩子
      2. 该节点的后继不是右孩子
    # include <cstdio>
    # include <iostream>
    using namespace std;
    /**************************/
    struct BSTreeNode {
        int key;
        BSTreeNode * p;     // 父节点
        BSTreeNode * left;  // 左孩子
        BSTreeNode * right; // 右孩子
    } * root;
    
    
    /// 初始化
    void init() {
        root = NULL;
    }
    
    
    /// 新建节点
    BSTreeNode * create_node(int key) {
        BSTreeNode * p = new BSTreeNode;
        p->key = key;
        p->p = NULL;
        p->left = NULL;
        p->right = NULL;
        return p;
    }
    
    
    /// 根据键查询
    BSTreeNode * search_node(int key) {
        BSTreeNode * x = root;
        while(x!=NULL && key != x->key) {
            if (key < x->key) x = x->left;
            else x = x->right;
        }
        return x;
    }
    
    
    /// 查找某子树最小节点
    BSTreeNode * search_minimum(BSTreeNode * p) {
        if (p == NULL) return NULL;
        while (p->left != NULL) p = p->left;
        return p;
    }
    
    
    /// 查找某子树最大节点
    BSTreeNode * search_maximum(BSTreeNode * p) {
        if (p == NULL) return NULL;
        while (p->right != NULL) p = p->right;
        return p;
    }
    
    
    /// 查询节点前驱节点(节点)
    BSTreeNode * search_predecessor(BSTreeNode * p) {
        if (p->left != NULL) {
            return search_maximum(p->left);  // 拥有左子树,后继一定是左子树的最大节点
        } else {
            BSTreeNode * y = p->p;
            while(y!=NULL && y->left==p) {  // 找到高层节点中以p所在的树为右子树的树的根节点,即是前驱节点
                p = y;
                y = y->p;
            }
            return y;
        }
    }
    
    
    /// 查询节点前驱节点(键值)
    BSTreeNode * search_predecessor(int key) {
        BSTreeNode * p = search_node(key);
        if (p!=NULL) {
            return search_predecessor(p);
        }
        return NULL;
    }
    
    
    /// 查找节点后继节点(节点)
    BSTreeNode * search_successor(BSTreeNode * p) {
        if (p->right != NULL) {
            return search_minimum(p->right);  // 拥有右子树,后继一定是右子树的最小节点
        } else {
            BSTreeNode * y = p->p;
            while(y!=NULL && y->right==p) {  // 找到高层节点中以p所在的树为左子树的树的根节点,即是后继节点
                p = y;
                y = y->p;
            }
            return y;
        }
    }
    
    
    /// 查找节点后继(键值)
    BSTreeNode * search_successor(int key) {
        BSTreeNode * p = search_node(key);
        if (p!=NULL) {
            return search_successor(p);
        }
        return NULL;
    }
    
    
    /// 插入节点(节点)
    void insert_node(BSTreeNode * s) {
        BSTreeNode * x = root;
        BSTreeNode * y = NULL;
        while (x!=NULL) {
            y = x;
            if (s->key < x->key) x = x->left;
            else x = x->right;
        }
        s->p=y;
        if (y==NULL)
            root = s;
        else if (s->key < y->key)
            y->left = s;
        else
            y->right = s;
    }
    
    
    /// 插入节点(键值)
    bool insert_node(int key) {
        BSTreeNode * f = search_node(key);
        if (f!=NULL) return false; // 有重复的键
    
        BSTreeNode * node = create_node(key);
        insert_node(node);
        return true;
    }
    
    
    /// 替换节点树(v替换u)
    void transplant_node(BSTreeNode * u, BSTreeNode * v) {
        if (u->p==NULL) {
            root = v;
        } else if (u->p->left == u) {
            u->p->left = v;
        } else {
            u->p->right = v;
        }
        if (v!=NULL) {
            v->p = u->p;
        }
    }
    
    
    /// 删除节点(节点)
    void delete_node(BSTreeNode * x) {
        if (x->left == NULL) {
            transplant_node(x, x->right);
        } else if (x->right == NULL) {
            transplant_node(x, x->left);
        } else {  // 左右孩子都存在的情况
            BSTreeNode * y = search_minimum(x->right);  // 找后继节点
            if (y != x->right) {  // 如果后继不是右孩子,需要变形。具体是将后继节点提为右子树的根节点
                transplant_node(y, y->right);  // 后继节点的左孩子一定不存在,右孩子取代后继节点
                y->right = x->right;
                y->right->p = y;
            }
            // 如果后继就是右孩子
            transplant_node(x, y);
            y->left = x->left;  // 替换后还需要修改与左子树的父子关系
            x->left->p = y;
        }
        delete x;
    }
    
    
    /// 删除节点(键值)
    bool delete_node(int key) {
        BSTreeNode * node = search_node(key);
        if (node == NULL) return false;  //键值不存在
        delete_node(node);
        return true;
    }
    
    
    /// 先序遍历
    void preOrder(BSTreeNode * p) {
        if (p == NULL) return;
        printf("%d-", p->key);
        preOrder(p->left);
        preOrder(p->right);
    }
    
    
    /// 中序遍历
    void inOrder(BSTreeNode * p) {
        if (p == NULL) return;
        inOrder(p->left);
        printf("%d-", p->key);
        inOrder(p->right);
    }
    
    
    /// 后序遍历
    void postOrder(BSTreeNode * p) {
        if (p == NULL) return;
        postOrder(p->left);
        postOrder(p->right);
        printf("%d-", p->key);
    }
    
    
    int main() {
    
        init();
    
        insert_node(5);
        insert_node(7);
        insert_node(1);
        insert_node(19);
        insert_node(3);
    
    
        preOrder(root);
        printf("
    ");
        inOrder(root);
        printf("
    ");
        postOrder(root);
        printf("
    ");
    
        printf("%d->%d->%d
    ", search_predecessor(5)->key, 5, search_successor(5)->key);
        printf("%d->%d->%d
    ", search_predecessor(7)->key, 7, search_successor(7)->key);
        printf("%d->%d->%d
    ", search_predecessor(3)->key, 3, search_successor(3)->key);
    
        printf("%d, %d
    ", search_minimum(root)->key, search_maximum(root)->key);
    
        delete_node(5);
        inOrder(root);
        printf("
    ");
    
        return 0;
    }
    
  • 相关阅读:
    图的存储代码实现
    最小生成树算法
    图的遍历
    图的存储结构
    ftp服务器的配置
    利用c++利用odbc连接mysql数据库
    测试odbc连接sqlsever数据库是否成功的代码
    gk888t打印机安装
    Win10下windows mobile设备中心连接不上的方法无法启动
    js千分位加逗号和四舍五入保留两位小数
  • 原文地址:https://www.cnblogs.com/haoabcd2010/p/11087166.html
Copyright © 2020-2023  润新知