二叉搜索树(Binary Search Tree)

一. 定义, 性质

二叉查找树(Binary Search Tree),也称二叉搜索树、有序二叉树(ordered binary tree),排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树

  1. 若任意节点的左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
  2. 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点(no duplicate nodes)
  5. 中序遍历为递增序列

搜索、插入、删除的复杂度等于树高,期望O(logN),最坏O(N)(数列有序,树退化成线性表)。

二. 查询操作

    Node* search(int key) {
        Node* n = root;
        while(n!=NULL && key!=n->data)
        {
            if (key<n->data) n = n->left;
            else n = n->right;
        }
        return n;
    }
    // 找到以x为根的(子)树的最小结点
    Node* minimum(Node* x)
    {
        if (x == 0) return 0;
        while (x->left!=NULL)
            x = x->left;
        return x;
    }
    // find the minimum node in the whole tree
    Node* minimum() {return minimum(root);}

    // 找到以x为根的(子)树的最大结点
    Node* maximum(Node* x)
    {
        if (x == 0) return 0;
        while (x->right!=NULL)
            x = x->right;
        return x;
    }
    // find the maximum node in the whole tree
    Node* maximum() {return maximum(root);}

三. 插入操作

插入的步骤如下:

1) 若树是空树, 则申请一个新节点, 赋给root

2) 若在树中找到key, 说明树中已经有该字段, 不能再插入, 否则

3) 若key小于当前结点的值, 则检查左孩子. 否则

4) 若key大于当前结点的值, 则检查右孩子.

递归算法:

Node* BinarySearchTree::insert(int key, Node*& n)
{
    if (n == 0)
    {
        n = new Node(key);
        return n;
    }
    else if (key < n->data)
        return insert(key, n->left);
    else if (key > n->data)
        return insert(key, n->right);
    else return n;
}

非递归算法:

Node* BinarySearchTree::insert_iterative(int key)
{
    if (root == 0)
    {
        root = new Node(key);
        return root;
    }
    Node* n = root;
    // parent总是指向当前结点的父节点
    Node* parent = 0;
    while (n != 0)
    {
        parent = n;
        if (key < n->data)
            n = n->left;
        else if (key > n->data)
            n = n->right;
        else;
    }
    if (key < parent->data)
    {    
        parent->left = new Node(key);
        return parent->left;
    }
    else
    {    
        parent->right = new Node(key);
        return parent->right;
    }
}

四. 删除操作

由于删除操作要保证不破坏二叉搜索树树的性质, 因此要分两种情况考虑

1. 至多有一棵非空子树:

      如果左子树非空, 那么用左子树替换当前结点. 否则用右子树替换当前结点.

2. 有两棵非空子树:

      要转化为第一种情况------用该节点的直接后继来代替该节点, 并在该节点的右子树中删除其直接后继. 由于中序遍历的直接后继必然没有左子树, 因此能够转化为第一种情况

递归:

void BinarySearchTree::remove(int key, Node*& n)
{
    if (n == 0)
        return;
    if (key < n->data)
        remove(key, n->left);
    else if (key > n->data)
        remove(key, n->right);
    else if (n->left != 0 && n->right != 0) //having two children
    {
        // 由于节点没有parent属性, 用重新安排指针的方法来移除结点很困难.
        // 因此把直接后继结点的值赋给待删除结点
        // 并且在右子树中删除该直接后继结点
        n->data = minimum(n->right)->data; 
        remove(n->data, n->right);
    }
    else
    {
        Node* tmp = n;
        n = (n->left != 0) ? n->left : n->right;
        delete tmp;
    }
}

非递归:

void BinarySearchTree::remove_iterative(int key)
{
    // STEP 1 : 找到待删除结点和它的父节点
#pragma region STEP 1
    Node *replacer, *successor, *successor_parent, *toRemove, *parent_toRemove;
    toRemove = root; parent_toRemove = 0;
    while (toRemove != NULL && key != toRemove->data)
    {
        parent_toRemove = toRemove;
        if (key < toRemove->data)
            toRemove = toRemove->left;
        else
            toRemove = toRemove->right;
    }
    if (toRemove == 0) return;
#pragma endregion STEP 1

#pragma region STEP 2 : 如果是第二种情况
    if (toRemove->left && toRemove->right)
    {
        successor = toRemove->right;
        successor_parent = toRemove;
        while (successor->left)
        {
            successor_parent = successor;
            successor = successor->left;
        }
        // 把直接后继的值赋给待删除结点
        toRemove->data = successor->data;
        // 待删除结点改为直接后继
        toRemove = successor;
        parent_toRemove = successor_parent;
    }
#pragma endregion
    if (toRemove->left) 
        replacer = toRemove->left;
    else 
        replacer = toRemove->right;
    if (toRemove == root)
        root = replacer;
    else if (toRemove == parent_toRemove->left) 
        parent_toRemove->left = replacer;
    else 
        parent_toRemove->right = replacer;

    delete toRemove;
}
posted @ 2015-01-13 14:32  Roy_Mustango  阅读(298)  评论(0编辑  收藏  举报