旭说数据结构之二叉查找树

原创 2015年11月20日 17:18:33

上一篇详细介绍树的特殊结构——二叉树的相关知识和操作。
这一篇介绍二叉树的特殊结构——二叉查找树。
较之一般的二叉树,二叉查找树限定了结点的左子树的所有结点值均小于该结点,结点的右子树的所有结点值均大于该结点。下图给了一个示意:
这里写图片描述
所以在往二叉查找树中插入元素时,要注意,不能随便找到一个空位就插入,而是要通过与根结点的比较,判断插在根结点的左子树还有右子树,倘若应该插在右子树,在与右子树的根结点比较,判断应该插在右子树的哪个子树上,如此,这是个递归的过程。于是我们可以用递归来实现插入:

1.递归和非递归插入

    //递归插入数据
    void insertDataToBST1(BSTNode<DataType>**root,DataType data)
    {
        if (*root == NULL)
        {
            *root = new BSTNode<DataType>(data);
            return;
        }
        if (data<((*root)->_data))
        {
            insertDataToBST1(&((*root)->_lChild),data);
        }
        if (data>((*root)->_data))
        {
            insertDataToBST1(&((*root)->_rChild),data);
        }
    }

非递归插入数据的思路也不难,下面给出代码:

    //非递归插入数据
    void insertDataToBST2(BSTNode<DataType>**root,DataType data)
    {
        if (*root == NULL)
        {
            *root = new BSTNode<DataType>(data);
            return;
        }
        BSTNode<DataType>* p = *root;
        while(p){//从根结点开始,寻找到一个能放置data的空位置
            if (data > p->_data)//如果data比该结点大,而正好该结点的右孩子为NULL,
                                //则正好插入到这个结点的右孩子处
            {
                if (p->_rChild == NULL)
                {
                    p->_rChild = new BSTNode<DataType>(data);
                    break;
                }
                else//如果右孩子不是空的,则还得往下找
                {
                    p = p->_rChild;
                }
            }

            if (data < p->_data)
            {
                if (p->_lChild == NULL)
                {
                    p->_lChild = new BSTNode<DataType>(data);
                    break;
                }
                else
                {
                    p=p->_lChild;
                }
            }
        }
    }

2.遍历

由于二叉查找树的特殊性质,我们对一颗二叉查找树进行中序遍历,得到的中序序列是按照从小到大的顺序排列的。
二叉查找树也是一颗二叉树,故遍历方法与二叉树的相同:

//递归中序遍历
    void inOrderWithRecursion()
    {
        cout<<"中序遍历";
        inOrder1(_root);
    }
    void inOrder1(BSTNode<DataType>* root)
    {
        if (root == NULL)return;
        inOrder1(root->_lChild);
        cout<<root->_data;
        inOrder1(root->_rChild);
    }

    //非递归中序遍历
    void inOrder()
    {
        Stack<BSTNode<DataType>*>* nodeStack = new Stack<BSTNode<DataType>*>;
        BSTNode<DataType>* p = _root;
        while(p!=NULL)// 从根结点一路向左,入栈
        {
            nodeStack->push(p);
            p=p->_lChild; 
        }
        //取出栈中元素,打印,发现该元素有右子树,把右子树一路向左入栈
        while(!nodeStack->isEmpty())
        {
            p = nodeStack->pop();
            cout<<p->_data;
            if (p->_rChild)
            {
                p=p->_rChild;
                while(p)
                {
                    nodeStack->push(p);
                    p=p->_lChild;
                }
            }
        }
    }

3.删除操作

删除操作是较复杂的一个操作,得分不同的情况进行讨论,下图给出了示意:
这里写图片描述
此外如果我们删除的结点是根结点,情况也有些许不同:
这里写图片描述

下面给出代码:代码中的getParentNode是一个成员函数,用于返回给定结点的父结点;findData也是一个成员函数,根据给定值返回对应的结点;findMin用于返回给定子树的最小值结点

bool deleteData(DataType data)
    {
        //首先在整个树中寻找是否有这个结点
        //findData是一个成员函数
        BSTNode<DataType>* p = findData(data);
        //如果没有找到这个结点,就不用删除了,返回false
        if (p==NULL)return false;

        //如果找到了要删除的结点,要判断这个结点是不是根结点

        if (p!=_root)//如果删除的不是根结点,则p定有父结点
        {
            if (p->_lChild==NULL&&p->_rChild==NULL)//要删除结点的左右孩子都为空
            {
                //如果要删除节点被父结点的左指针指着,则把这个左指针设为NULL
                if (getParentNode(p)->_lChild = p)
                {
                    getParentNode(p)->_lChild = NULL;
                }else{//如果要删除节点被父结点的右指针指着,则把这个右指针设为NULL
                    getParentNode(p)->_rChild = NULL;
                }
                delete p;
            }else if (p->_lChild && p->_rChild)//要删除结点的左右孩子都不为空
            {
                BSTNode<DataType>*minNode = findMin(p->_rChild);
                if (minNode == p->_rChild)
                {
                    p->_data = minNode->_data;
                    p->_rChild=minNode->_rChild;
                    delete minNode;
                }else{
                    p->_data = minNode->_data;
                    getParentNode(minNode)->_lChild = NULL;
                    delete minNode;
                }
            }else{//要删除结点只有一个孩子
                if (p->_rChild)//有右孩子的话
                {
                    if (getParentNode(p)->_lChild = p)
                    {
                        getParentNode(p)->_lChild = p->_rChild;
                    }else{
                        getParentNode(p)->_rChild = p->_rChild;
                    }
                }
                if (p->_lChild)//有左孩子的话
                {
                    if (getParentNode(p)->_lChild = p)
                    {
                        getParentNode(p)->_lChild = p->_lChild;
                    }else{
                        getParentNode(p)->_rChild = p->_lChild;
                    }
                }
                delete p;
            }
        }else{//如果要删除的是根结点
            if (p->_lChild==NULL&&p->_rChild==NULL)//如果根结点的左右孩子都为空
            {
                if (_root)
                {
                    delete _root;
                    _root =NULL;
                }
            }else if (p->_lChild&&p->_rChild){//如果根结点左右孩子都有
                BSTNode<DataType>*minNode = findMin(p->_rChild);
                if (minNode == p->_rChild)
                {
                    p->_data = minNode->_data;
                    p->_rChild=minNode->_rChild;
                    delete minNode;
                }else{
                    p->_data = minNode->_data;
                    getParentNode(minNode)->_lChild = NULL;
                    delete minNode;
                }
            }else{
                if (p->_lChild)//如果有左子树
                {
                    _root = p->_lChild;
                    delete p;
                }
                if (p->_rChild)
                {
                    _root = p->_rChild;
                    delete p;
                }
            }

        }
        return true;
    }

4.寻找包含关键字的结点

    BSTNode<DataType>* findData(DataType data)
    {
        BSTNode<DataType>* p = _root;
        while(p)
        {
            if (data > p->_data)
            {
                p = p->_rChild;
            }else if (data<p->_data)
            {
                p = p->_lChild;
            }else {
                break;
            }
        }
        //p可能为NULL
        if (p)
        {
            cout<<"找到了"<<p->_data<<endl;
        }else{
            cout<<"没有找到"<<data;
        }
        return p;
    }

5.寻找给定子树的的最小值

    BSTNode<DataType>* findMin(BSTNode<DataType>* node)
    {
        BSTNode<DataType>* p = node;
        while(p)
        {
            if (p->_lChild == NULL)
            {
                break;
            }
            p = p->_lChild;
        }
        return p;
    }

6. 找一个结点的父结点


    BSTNode<DataType>* getParentNode(BSTNode<DataType>* child)
    {
        if (child == NULL||child == _root)return NULL;
        //利用层序遍历的思路,使用队列
        Queue<BSTNode<DataType>*>* queue = new Queue<BSTNode<DataType>*>;
        //先把根结点入队
        queue->addDataToQueue(_root);
        BSTNode<DataType>* p = NULL;
        //当队列不空时
        while(queue->count()){
            //取出队首元素,第一次取出的是根结点,打印根结点,再把根结点的左右孩子入队列,
            //下一次取出的队首元素就是root的左孩子,然后把它的左右孩子入队列
            //每次都是打印这个结点,然后把它的左右孩子入队,最终所有的结点都会入队列,
            p=queue->deleteDataFromQueue();
            if (p->_lChild)
            {
                if (p->_lChild == child)
                {
                    return p;

                }
                queue->addDataToQueue(p->_lChild);
            }
            if (p->_rChild)
            {
                if (p->_rChild == child)
                {
                    return p;

                }
                queue->addDataToQueue(p->_rChild);
            }
        }
    }
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

算法系列(八)数据结构之二叉查找树

在算法系列(七)数据结构之树的基本结构和二叉树的遍历 中介绍了基本的树结构,二叉树的实现和遍历。 这篇文章重点学习一下二叉查找树。 概述 二叉排序树(Binary Sort Tree)又称二叉查...

数据结构之二叉查找树

二叉查找树 :是支持动态查询的查询算法,即可以插入和删除 查询:遵循二叉树的规则,关键字的值大于左子树的值,小于右子树的值 插入:通过查询操作,如果存在,当然不用再插入咯,如果失败,则返回应该插入位置...

数据结构之二叉查找树

二叉查找树由节点构成,每个结构包含数值元素,左子树(指向左边相连的节点的指针),右子树(指向右边相连的节点的指针),父节点(指向父节点的指针) public class BinaryNode {...

算法学习之数据结构之二叉查找树

一,先介绍一些二叉查找树的概念和性质。   二叉树执行基本操作的时间与树的高度成正比。   设x为二叉查找树中的一个结点。如果y是x的左子树中的一个结点,则key[y]=key[x]。   注意...

数据结构之二叉查找树

数据结构之二叉树学习

数据结构之二叉查找树的C++实现

二叉树是结构最简单的树了,而二叉查找树又是特殊的二叉树,它能实现高效的查找,删除,插入等基本操作,STL里的map与set就是用了自平衡的二叉查找树的思想实现的 不过我这里先不实现自平衡功能,但这又...

Java数据结构之二叉查找树

package JavaProject; public class TestBinarySearchTree { public static void main(String[] args) { ...

数据结构(五)之二叉查找树

二叉查找树。假设所有的关键字是互异的。对于树的每个节点X,它的左子数中所有关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值。二叉查找树的平均深度是O(log N)。

数据结构之二叉查找树

package cn.thj.data_structures; /** * 二叉查找树 * * @author 谭恒杰 */ public class BinarySearc...

数据结构之二叉查找树

一,今天我们来介绍下二叉查找树,其定义是这样子的: (1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值; (2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值; ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)