【数据结构】二叉查找树

1.概念:

二叉查找树也叫二叉搜索树,是一棵空树或者是具有一下性质的一颗二叉树

a.每个节点都有一个作为搜索依据的关键码(key),而且所有的关键码的取值都互不相同。

b.每个左子树(如果存在)所有节点的关键码都小于根节点的关键码。

c.每个右子树(如果存在)所有节点的关键码都大于根节点的关键码。

d.每个左子树和右子树也均为二叉搜索树。

需要说明的是,关键码事实上是节点所保存元素中的某个域的值,它能够唯一的表示这个结点,因此,如果对一颗二叉搜索树进行中序遍历,就可以按照从小到大的顺序将各个结点的关键排列起来,因此二叉搜索树也被称为二叉排序树。

2.二叉搜索树相关的算法:

a.搜索算法:

在二叉搜索树上进行搜索,过程是从一个根节点开始,沿着某一个分支逐层向下进行比较判别的过程,这个过程可以是一个递归的过程,也可以是一个迭代的过程。因为通常使用递归的方法来定义二叉树类,因此搜索算法通常也使用递归的思想来编写。主要过程如下:

假设想要在二叉搜索树中搜索关键码为x的元素,搜索过程从根节点开始,如果根结点为nullptr(空指针),则直接返回搜索失败,否则用给定的值x与根结点的关键码相比较,如果给定的值等于根结点的关键码中的值,则返回搜索成功的信息,并提交搜索到的结点地址。如果给定值小于根结点的关键码,则继续递归搜索根结点的左子树,窦泽,进行递归搜索根结点的右子树。

b.插入算法:

向二叉搜索树中插入一个元素,必须先检查这个元素在已有的树中是否已经存在。所以 在进行插入之前,可以先使用搜索算法在树中检查准备要插入的元素是否存在。如果返回搜索成功的信息,说明在这棵二叉搜索树中已有这个元素,就不再进行插入操作。否则,说明在树中没有要插入的这个元素。再把新元素添加到搜索操作停止的地方。在将要插入的元素与搜索操作返回的地址的关键码相比较。如果小于,则插入为左子树,否则成为右子树。

在插入过程中需要注意,每次的结点的插入,都要从根结点出发先搜索插入的位置,然后把新结点作为叶结点插入,这样不需要移动结点,只需要修改某个已有树中结点的空指针即可。

c.二叉搜索树的删除

在二叉搜索树中删除一个结点时,必须将因删除结点而断开的二叉链表重新连接起来,同时又要确保二叉搜索树的性质不丢失。此外,为了保证在删除结点后树的搜索性能不至于降低,还需要防止重新连接后输的高度不能增加。因此,删除算法需要分为几种情况进行讨论。

(1).如果想要删除叶结点,只需将父结点指向它的指针进行清零操作即可,在释放掉这个结点即可。

(2).如果被删除的结点右子树为空,则可以用它的左子女结点代替它的位置,再释放掉这个结点;若被删除结点左子树为空,则可以用它的右子女结点代替它的位置,再释放掉这个结点即可。

(3)如果被删除结点的左右子树都不为空,则可以在它的右子树下寻找中序下的第一个结点(关键码最小),用它的值填补到被删除的结点中,再来处理这个结点的删除问题。

同样的,这也是一个递归处理的过程。之后进行递归删除即可。

相关实现程序如下

二叉搜索树的头文件:

/
//  BST.h
//  BinarySearchTree
//
//  Created by 大幕 on 2017/3/2.
//  Copyright © 2017年 Damu. All rights reserved.
//

//  构建一颗二叉查找树并进行使用
//  特点,每一个元素有一个键值,左子树比根节点小,右子树比根节点大,且左右子树都是二叉查找树


#ifndef BST_h
#define BST_h

#include <iostream>

enum Boolean { FALSE, TRUE };      //定义自己的布尔类型

//使用C++的模板类来设计二叉查找树

template <class Type>
class Element
{
public:
    Type key;
    //可以很容易的添加更多的数据
};

template<class Type> class BST;     //声明类

template <class Type>
class BstNode      //二叉查找树的结点类
{
    friend class BST<Type>;     //定义为友元类,方便操作BstNode的私有成员
public:
    Element<Type> data;
    BstNode * LeftChild;
    BstNode * RightChild;
    void display(int i);
};

template <class Type>
class BST
{
public:
    BST(BstNode<Type> *init = 0)
    {
        root = init;
    }
    Boolean Insert(const Element<Type>& x);     //插入结点操作
    Boolean Remove(BstNode<Type> * ptr, const Element<Type>& x);     //删除以ptr为根结点,关键码为x的结点
    Boolean Remove(const Element<Type>& x);     //配合上一个函数实现删除操作
    BstNode<Type>* Search(const Element<Type>& x);     //使用递归的方法进行查找
    BstNode<Type>* Search(BstNode<Type> *, const Element<Type> &);     //重载函数进行查找
    BstNode<Type>* IterSearch(const Element<Type>&);   //使用迭代进行查找
    void display()
    {
        std::cout << '\n';
        if (root)
            root->display(1);
        else
            std::cout << "这是一颗空树\n";
    }
private:
    BstNode<Type> *root;

};

template <class Type>
void BstNode<Type>::display(int i)
{
    //用来显示当前节点的数据以及它所有的左子树和右子树的数据,利用递归的方法
    std::cout << "Position: " << i << ": data.key = " << data.key << '\n'; //先显示位置,再显示数据
    if (LeftChild)
        LeftChild->display(2 * i);      //递归左子树
    if (RightChild)
        RightChild->display(2 * i + 1);   //递归右子树
}

template <class Type>
Boolean BST<Type>::Insert(const Element<Type> &x)
{
    BstNode<Type> *p = root;
    BstNode<Type> *q = 0;       //q指向p的父节点
    //insert之前需要先进行查找,找到合适的位置进行插入
    while (p)
    {
        q = p;      //在每次改变之前使用q将p进行保留下来
        if (x.key == p->data.key)
            return FALSE;       //发生重复,插入失败
        if (x.key < p->data.key)
            p = p->LeftChild;
        else
            p = p->RightChild;
    }
    //循环结束后,找到了位置q
    p = new BstNode<Type>;
    p->LeftChild = nullptr;
    p->RightChild = nullptr;
    p->data = x;
    if (!root)
        root = p;
    else if (x.key < q->data.key)
        q->LeftChild = p;
    else
        q->RightChild = p;
    return TRUE;        //表示插入成功
}

//删除以ptr为根结点,关键码为x的结点
template<class Type>
Boolean BST<Type>::Remove(BstNode<Type> * ptr, const Element<Type>& x)
{
    BstNode<Type> *temp = nullptr;
    ptr = root;
    if (ptr != nullptr)
    {
        if (x.key < ptr->data.key)
            Remove(ptr->LeftChild, x);       //在左子树中执行删除
        else if (x.key > ptr->data.key)
            Remove(ptr->RightChild, x);      //在右子树中执行删除
        else if (ptr->LeftChild != nullptr && ptr->RightChild != nullptr)
        {
            //ptr指到了关键码为x的结点,而且这个结点有两个子女
            temp = ptr->RightChild;     //找到右子树搜寻中序下的第一个结点
            while (temp->LeftChild != nullptr)
                temp = temp->LeftChild;
            ptr->data.key = temp->data.key;     //使用temp中数据代替此时ptr结点中的数据
            Remove(ptr->RightChild, ptr->data);  //递归删除右子树中的temp结点
        }
        else
        {
            //ptr也指到了关键码为x的结点,但是它只有1个或0个子女
            temp = ptr;
            if (ptr->LeftChild == nullptr)
                ptr = ptr->RightChild;
            else
                ptr = ptr->LeftChild;
            delete temp;
            return TRUE;

        }

    }
    return FALSE;
}

//删除函数
template <class Type>
Boolean BST<Type>::Remove(const Element<Type> &x)
{
    return Remove(root, x);
}


//搜索函数
template <class Type>
BstNode<Type> *BST<Type>::Search(const Element<Type> &x)
{
    return Search(root, x);
}

template<class Type>
BstNode<Type> * BST<Type>::Search(BstNode<Type> *b, const Element<Type>& x)
{
    //从节点b开始找数值为x的结点
    if (!b)
        return 0;
    if (x.key == b->data.key)
        return b;
    if (x.key < b->data.key)
        return Search(b->LeftChild, x);
    return Search(b->RightChild, x);
}

//迭代的查找方法
template<class Type>
BstNode<Type>* BST<Type>::IterSearch(const Element<Type> &x)
{
    for (BstNode<Type> *t = root; t;)
    {
        if (x.key == t->data.key)
            return t;
        if (x.key < t->data.key)
            t = t->LeftChild;
        else
            t = t->RightChild;
    }
    return 0;
}

#endif /* BST_h */

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/qq_34784753/article/details/59551757
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞