二叉搜索树

思路

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

查找

查找比较简单,基本都是一个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("\n");
    inOrder(root);
    printf("\n");
    postOrder(root);
    printf("\n");

    printf("%d->%d->%d\n", search_predecessor(5)->key, 5, search_successor(5)->key);
    printf("%d->%d->%d\n", search_predecessor(7)->key, 7, search_successor(7)->key);
    printf("%d->%d->%d\n", search_predecessor(3)->key, 3, search_successor(3)->key);

    printf("%d, %d\n", search_minimum(root)->key, search_maximum(root)->key);

    delete_node(5);
    inOrder(root);
    printf("\n");

    return 0;
}
posted @ 2019-06-25 22:41  happy_codes  阅读(143)  评论(0编辑  收藏