zoukankan      html  css  js  c++  java
  • 二叉搜索树

    思路

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

    查找

    查找比较简单,基本都是一个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;
    }
    
  • 相关阅读:
    Ubuntu配置sublime text 3的c编译环境
    ORA-01078错误举例:SID的大写和小写错误
    linux下多进程的文件拷贝与进程相关的一些基础知识
    ASM(四) 利用Method 组件动态注入方法逻辑
    基于Redis的三种分布式爬虫策略
    Go语言并发编程总结
    POJ2406 Power Strings 【KMP】
    nyoj 会场安排问题
    Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.
    Java的String、StringBuffer和StringBuilder的区别
  • 原文地址:https://www.cnblogs.com/haoabcd2010/p/11087166.html
Copyright © 2011-2022 走看看