1. 程式人生 > >演算法導論第12章:二叉搜尋樹

演算法導論第12章:二叉搜尋樹

基本性質

左子樹 < 根 < 右子樹

基本操作 O(logn)

1.查詢最大、最小關鍵字元素

根據二叉樹的基本性質,向左子樹或右子樹遞迴即可

2.查詢前驅和後繼

查詢結點X的後繼Y分為兩種情況:

①右結點存在,即只需要找到右子樹中最小的元素就好了

②右結點不存在,此時就要向親代查詢,直到找到右上方的親代,此時Y是X的最底層祖先,且Y的左孩子是X的一個祖先。

3.插入

迭代演算法:類似於一根小棒在樹中移動,最終把待插入元素放置在一個空結點上

4.刪除

假設要刪除結點Z,那麼需要分3種情況討論:

①若沒有孩子,直接刪除即可,以空結點NULL代替之。

②若只有一個孩子,以孩子代替結點Z

③若有兩個孩子

a)若右孩子為其後繼:將右子樹代替結點Z即可

b)若右孩子不是其後繼:設Z的後繼為Y,Y的右孩子為X,則將Y原來的位置以X代替,Y將Z代替

利用二叉樹進行排序 Ω(n*logn)

不斷地插入節點,最後中序遍歷即可——元素之間的比較和快速排序相同,故它們的執行效率相似。若採用隨機化策略,則平均執行時間為θ(n*logn),樹高為θ(logn)

二叉搜尋樹類的實現(C++)

#include <iostream>
using namespace std;

#pragma once
//設想是:當樹為空時,root一定為nullptr 
struct node
{
    int element = 0;
    node* parent = nullptr;
    node* left = nullptr;
    node* right = nullptr;
};

class BinarySearchTree
{
public:
    BinarySearchTree() {}
    ~BinarySearchTree();
    int size();
    int maximum();
    int minimum();
    void print();
    void clear();
    void insert(const int&);
    void remove(const int&);
private:
    int cnt = 0;
    node* root = nullptr;

    node* minimum(node* x);
    void transplant(node* u, node* v);
    void clear(node*);
    void print(node*);
};

void BinarySearchTree::clear(node* x)
{
    if(x == nullptr) return;

    if(x->left != nullptr) clear(x->left);
    if(x->right != nullptr) clear(x->right);
    delete x;
    x = nullptr;
}

void BinarySearchTree::clear()
{
    cnt = 0;	
    clear(root);
}

BinarySearchTree::~BinarySearchTree()
{
    clear(root);
}

int BinarySearchTree::maximum()
{
    node* x = root;
    if(x == nullptr) return 0;
    while(x->right != nullptr)
        x = x->right;
    return x->element;
}

node* BinarySearchTree::minimum(node* x)
{
    if(x == nullptr) return 0;
    while(x->left != nullptr)
        x = x->left;
    return x;
}

int BinarySearchTree::minimum()
{
    return minimum(root)->element;
}

int BinarySearchTree::size()
{
    return cnt;
}

void BinarySearchTree::print(node* x)
{
    if(x == nullptr) return;
    if(x->left != nullptr) print(x->left);
    cout << x->element << ' ';
    if(x->right != nullptr) print(x->right);
}

void BinarySearchTree::print()
{
    print(root);
    cout<<'\n';
}

void BinarySearchTree::insert(const int& a)
{
    if(cnt == 0)
    {
        root = new node;
        root->element = a;
    }
    else
    {
        node* x = root;
        node* y = nullptr;
        while(x != nullptr)
        {
            y = x;
            if(a > x->element) x = x->right;
            else x = x->left;
        }

        node* t = new node;
        t->parent = y;
        t->element = a;
        if(a > y->element) y->right = t;
        else y->left = t;
    }
    ++cnt;
}

void BinarySearchTree::transplant(node* u, node* v)
{
    if(u->parent == nullptr) root = v;
    else if(u == u->parent->left) u->parent->left = v;
    else u->parent->right = v;

    if(v != nullptr) v->parent = u->parent;
}

void BinarySearchTree::remove(const int& a)
{
    node* x = root;
    while(x != nullptr && x->element != a)
    {
        if(a > x->element) x = x->right;
        else x = x->left;
    }
    if(x == nullptr) return;

    --cnt;
    if(x->left == nullptr)
        transplant(x, x->right);
    else if(x->right == nullptr)
        transplant(x, x->left);
    else
    {
        node* y = minimum(x->right);
        if(y->parent != x)
        {
            transplant(y, y->right);
            y->right = x->right;
            y->right->parent = y;
        }
        transplant(x, y);
        y->left = x->left;
        y->left->parent = y;
    }
}