数据结构与算法06:二叉查找树

来源:互联网 发布:淘宝军刀 编辑:程序博客网 时间:2024/05/16 17:08

一、二叉查找树
1、定义一棵二叉查找树
二叉查找树是一棵二叉树:
i)它的根节点大于左孩子节点,但小于右孩子节点
ii)左子树和右子树也是一棵二叉查找树。
这里写图片描述

2、二叉查找树的插入、查找、删除操作。
二叉查找树最核心的三个操作,下面以删除为例进行解释。
从二叉查找树中删除一个结点:
如果节点是NULL,则返回错误信息;
如果是叶节点,则直接删除就可以;如果不是叶节点,则需要进行拼接操作。
这里写图片描述

情况1:被删节点左右子树均为空,即删除的是叶子节点,如45.
情况2:被删节点左子树为空,右子树不为空,如30.
情况3:被删节点右子树为空,左子树不为空,如80.
情况4:被删节点左右子树均不为空,如50.
对于情况1:只需把该节点设置为NULL,再释放内存即可
对于情况2:右孩子晋升至该节点的位置,释放内存
对于情况3:左孩子晋升至该节点的位置,释放内存
对于情况4:
把它简化为情况2或情况3。选择简化为情况3,即左子树不为空,右子树为空。
首先,在被删节点50的左子树中,一直往右走,找到最右的元素48 ,交换节点50与节点48。
注意的这里的交换实际只需要把48赋值到被删节点就可以,因为最右的节点最后是删除了的,是不是50不重要。
这时,删除节点50的情况就变成了真正的情况3,即节点50只剩下一个左孩子45了。

template <class elemType>void bSearchTreeType<elemType>::deleteFromTree(nodeType<elemType>* &p){    nodeType<elemType> *current;     nodeType<elemType> *trailCurrent;    nodeType<elemType> *temp;     if (p == NULL)        cout << "Error: The node to be deleted is NULL."<< endl;    else if (p->lLink == NULL && p->rLink == NULL)     //case 1:叶子节点,将p置NULL,释放p的内存    {        temp = p;        p = NULL;        delete temp;    }//case 2:没有左子树,将p设置为它的右子节点,释放p的内存    {        temp = p;        p = temp->rLink;        delete temp;    }    else if (p->rLink == NULL)    //case 3:没有右子树,将p设置为它的左子节点,释放p的内存    {        temp = p;        p = temp->lLink;        delete temp;    }    //case 4:既有左子树,又有右子树,按照假设没有右子树来处理    {        current = p->lLink;  //游标初始化为左子树的根节点        trailCurrent = NULL;  //游标的父节点目前为NULL        //游标在左子树中一直向右走        while (current->rLink != NULL)        {            trailCurrent = current;            current = current->rLink;        }        //最右元素的值赋值给被删元素        p->info = current->info;        //如果左子树中没有右子树,此时游标没有动        if (trailCurrent == NULL)             p->lLink = current->lLink;        else           //左子树中有右子树,此时current是最右的那个节点        //把current的左子树拼接到它的父节点的右子树            trailCurrent->rLink = current->lLink;        delete current;    }}

二、二叉查找树的实现
让二叉查找树继承二叉树抽象类,实现查找、插入和删除方法。

#include "stdafx.h"#include "binaryTree.h"#include <iostream>using namespace std;#pragma region 二叉查找树定义template <class elemType>class bSearchTreeType: public binaryTreeType<elemType>{public:    bool search(const elemType& searchItem) const;    void insert(const elemType& insertItem);    void deleteNode(const elemType& deleteItem);private:    void deleteFromTree(nodeType<elemType>* &p);    };#pragma endregion 二叉查找树定义template <class elemType>bool bSearchTreeType<elemType>::search(const elemType& searchItem) const{    nodeType<elemType> *current;    bool found = false;    if (root == NULL)        cout << "Cannot search an empty tree." << endl;    else    {        current = root;        while (current != NULL && !found)        {            if (current->info == searchItem)                found = true;            else if (current->info > searchItem)                current = current->lLink;            else                current = current->rLink;        }    }    return found;}template <class elemType>void bSearchTreeType<elemType>::insert(const elemType& insertItem){    nodeType<elemType> *current; //遍历树的游标    nodeType<elemType> *trailCurrent; //游标的父节点    nodeType<elemType> *newNode; //需要插入的节点    newNode = new nodeType<elemType>;    newNode->info = insertItem;    newNode->lLink = NULL;    newNode->rLink = NULL;    if (root == NULL)//空树        root = newNode;    else    {        current = root;        while (current != NULL)        {            trailCurrent = current;            if (current->info == insertItem)            {                cout << "已经存在键为insertItem的节点,不能插入"                << endl;                return;            }            else if (current->info > insertItem)                current = current->lLink;            else                current = current->rLink;        }        if (trailCurrent->info > insertItem)            trailCurrent->lLink = newNode;        else            trailCurrent->rLink = newNode;    }}template <class elemType>deleteNode(const elemType& deleteItem){    nodeType<elemType> *current; //遍历树的游标    nodeType<elemType> *trailCurrent; //游标的父节点    bool found = false;    if (root == NULL)        cout << "Cannot delete from an empty tree."        << endl;    else    {        current = root;        trailCurrent = root;        while (current != NULL && !found)        {            if (current->info == deleteItem)                found = true;            else            {                trailCurrent = current;                if (current->info > deleteItem)                    current = current->lLink;                else                    current = current->rLink;            }        }        if (current == NULL)            cout << "The item to be deleted is not in the tree."            << endl;        else if (found)        {            if (current == root)                deleteFromTree(root);            else if (trailCurrent->info > deleteItem)                deleteFromTree(trailCurrent->lLink);            else                deleteFromTree(trailCurrent->rLink);        }        else            cout << "The item to be deleted is not in the tree."            << endl;    }} template <class elemType>void bSearchTreeType<elemType>::deleteFromTree(nodeType<elemType>* &p){    nodeType<elemType> *current;     nodeType<elemType> *trailCurrent;    nodeType<elemType> *temp;     if (p == NULL)        cout << "Error: The node to be deleted is NULL."        << endl;    else if (p->lLink == NULL && p->rLink == NULL)     //case 1:叶子节点,将p置NULL,释放p的内存    {        temp = p;        p = NULL;        delete temp;    }    else if (p->lLink == NULL)     //case 2:没有左子树,将p设置为它的右子节点,释放p的内存    {        temp = p;        p = temp->rLink;        delete temp;    }    else if (p->rLink == NULL)     //case 3:没有右子树,将p设置为它的左子节点,释放p的内存    {        temp = p;        p = temp->lLink;        delete temp;    }    //case 4:既有左子树,又有右子树,按照假设没有右子树来处理    {        current = p->lLink;  //当前节点,初始化为左子树的根节点        trailCurrent = NULL;  //当前节点的父节点        //将当前节点指向左子树中最右的节点,它为左子树中的最大结点        while (current->rLink != NULL)        {            trailCurrent = current;            current = current->rLink;        }        //调整p的数据域        p->info = current->info;        //调整p的指针领域                if (trailCurrent == NULL)         //左子树中没有右子树,此时current没有移动            p->lLink = current->lLink;        else//左子树中有右子树,此时current是最右的那个节点            //把current的左子树拼接到它的父节点的右子树            trailCurrent->rLink = current->lLink;          delete current;    }}
0 0