【数据结构】|第14章:搜索树

本文详细介绍了二叉搜索树的定义、抽象数据类型,包括基本二叉搜索树(binarySearchTree)的操作如ascend、find、insert和erase,以及带有相同关键字和索引的二叉搜索树。还讨论了其在直方图问题中的应用。
摘要由CSDN通过智能技术生成

14.1定义

  • 搜索树
    在这里插入图片描述

  • 二叉搜索树
    在这里插入图片描述

在这里插入图片描述

  • 有重复值得二叉搜索树
    在这里插入图片描述

  • 索引二叉搜索树
    在这里插入图片描述
    LeftSize和名次
    在这里插入图片描述

14.2抽象数据类型

  • 二叉搜索树
抽象数据类型 bsTree
{
实例
	二叉树,每个节点为关键字+数值的数对;所有节点的关键字各不相同;任何节点左子树的关
键字小于该节点的关键字;任何节点右子树的关键字大于该节点的关键字

操作
	find(k): 返回关键字为k的数对
	insert(p): 将数对p插入到搜索树中
	erase(k): 删除关键字为k的数对
	ascend(): 按照关键字的升序排列输出所有数对
}

抽象类bdTree

template<class K,class E>
class bsTree:public dictionary<K,E>{
    public:
        virtual void ascend()=0;//按关键字升序输出
}
  • 索引二叉搜索树
抽象数据类型 indexedBSTree
{
实例
	与bsTree相同,只是每个节点多一个LeftSize域

操作
	find(k): 返回关键字为k的数对
	get(index): 返回第index个数对
	insert(p): 将数对p插入到搜索树中
	erase(k): 删除关键字为k的数对
	delete(index): 删除第index个数对
	ascend(): 按照关键字的升序排列输出所有数对
}

抽象类indexedBSTree

template<class K,class E>
class indexedBSTree:public bsTree<K,E>{
    public:
        virtual pair<const K,E>*get(int) const=0;//根据给定的索引,返回其数对的指针
        virtual void delete(int)=0;//根据给定的索引,删除其数对
}

14.3二叉搜索树的实现

binarySearchTree

template <class K, class E>
class binarySearchTree : public linkedBinaryTree<K, E>
{
public:
    // 返回关键字theKey匹配的数对的指针,若不存在匹配的数对,则返回NULL
    pair<const K, E> *find(const K &theKey) const;
    // 插入一个数对thePair,如果存在关键字相同的数对,则覆盖
    void insert(const pair<const K, E> &thePair);
    // 删除关键字theKey匹配的数对
    void erase(const K &theKey);
    // 按照关键字的升序排列输出所有数对
    void ascend()
    {
        inOrderOutput();
    }
};

操作ascend

在这里插入图片描述

void ascend(){inOrderOutput();}

搜索find

  • 若根为空,则查找失败
  • 若不为空
    • theKey小于根的关键字,只查找左子树
    • 反之,查找右子树
  • 与根的关键字相同,查找成功
  • 时间复杂度: O ( h ) O(h) O(h)
template <class K, class E>
pair<const K, E> *find(const K &theKey) const
{
    // 返回关键字theKey匹配的数对的指针,若不存在匹配的数对,则返回NULL
    // 指针p 从根开始搜索,寻找关键字等于theKey的元素(数对)
    binaryTreeNode<pair<const K, E>> *p = root;
    while (p != nullptr) // 检查p->element直到叶子节点
        if (theKey < p->element.first)
            p = p->leftChild;
        else if (theKey > p->element.first)
            p = p->rightChild;
        else // 找到匹配的元素
            return &p->element;
    // 无匹配的元素
    return nullptr;
}

插入insert

  • 搜索是否存在被插入元素
    • 有,替换该元素的值
    • 没有,将新元素作为搜索中断节点的孩子插入二叉搜索树
  • 时间复杂度: O ( h ) O(h) O(h)
template <class K, class E>
void binarySearchTree<K, E>::insert(const pair<const K, E> &thePair)
{
    // 插入一个数对thePair,如果存在关键字相同的数对,则覆盖
    binaryTreeNode<pair<const K, E>> *p = root, // 搜索指针
        *pp = nullptr;                          // p的父节点指针
    // 寻找插入点
    while (p != nullptr)
    {
        pp = p;
        if (thePair.first < p->element.first)
            p = p->leftChild;
        else if (thePair.first > p->element.first)
            p = p->rightChild;
        else
        {
            p->element.second = thePair.second; // 覆盖旧值
            return;
        }
    }
    // 为thePair 建立一个新节点,并将该节点连接至 pp
    binaryTreeNode<pair<const K, E>> *newNode =
        new binaryTreeNode<pair<const K, E>>(thePair);
    if (root != nullptr)
    { // 树非空
        if (thePair.first < pp->element.first)
            pp->leftChild = newNode;
        else
            pp->rightChild = newNode;
    }
    else // 插入到空树中
        root = newNode;
}

删除erase

  • 时间复杂度: O ( h ) O(h) O(h)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 情况三:删除有两个子树的节点
    • 两种选择:
      • 使用目标节点的左子树的最大元素代替
      • 使用目标节点的右子树的最小元素代替
    • 右子树的最小关键字节点(左子树的最大关键字节点)要么没有子树,要么只有一棵子树
template <class K, class E>
void binarySearchTree<K, E>::erase(const K &theKey)
{
    binaryTreeNode<pair<const K, E>> *p = root, *pp = nullptr;
    while (p != nullptr && p->element.first != theKey)
    {
        pp = p;
        if (theKey < p->element.first)
            p = p->leftChild;
        else
            p = p->rightChild;
    }
    if (p == nullptr)
        return; // 没有关键字为theKey的元素
    // p有两个孩子
    if (p->leftChild && p->rightChild)
    {
        // 在p的左子树中寻找最大元素
        binaryTreeNode<pair<const K, E>> *s = p->leftChild, *ps = p;
        while (s->rightChild != nullptr)
        { // s移动到最大的元素
            ps = s;
            s = s->rightChild;
        }
        // 使用s的值构造一个新节点,并让其指向p的孩子(K是常量,无法修改)
        binaryTreeNode<pair<const K, E>> *q =
            new binaryTreeNode<pair<const K, E>>(s->element, p - > leftChild, p->rightChild);
        // 让p的父节点指向q
        if (pp == nullptr)
            root = q;
        else if (p == pp->leftChild)
            pp->leftChild = q;
        else
            pp->rightChild = q;
        // 修改p指向s,pp指向s的父节点,后续继续删除
        if (ps == p)
            pp = q;
        else
            pp = ps;
        delete p;
        p = s;
    }
    // p最多有一个孩子
    // 在c中保存孩子指针
    binaryTreeNode<pair<const K, E>> *c;
    if (p->leftChild != nullptr)
        c = p->leftChild;
    else
        c = p->rightChild; // 如果p为叶子节点,c为null
    // 删除p
    if (p == root)
        root = c;
    else
    { // p是pp的左孩子还是pp的右孩子?
        if (p == pp->leftChild)
            pp->leftChild = c;
        else
            pp->rightChild = c;
    }
    treesize--;
    delete p;
}

二叉搜索树的高度

在这里插入图片描述

14.4带有相同关键字元素的二叉搜索树

只需将if (thePair.first < p->element.first)
改为if (thePair.first <= p->element.first)

14.5索引二叉搜索树

  • 一个节点的数值域是三元的:leftSize,key,value
  • 偶对:关键字域key、值域value

在这里插入图片描述

在这里插入图片描述

14.6应用——直方图问题

在这里插入图片描述
在这里插入图片描述

使用二叉搜索树

void add1(int &count) { count++; }
int main(int argc, char *argv[])
{          // 使用搜索树的直方图
    int n; // 元素个数
    cout << "Enter number of elements" << endl;
    cin >> n;
    // 添加了新的insert方法的二叉搜索树
    binarySearchTreeWithVisit<int, int> theTree;
    for (int i = 1; i <= n; i++)
    {
        pair<int, int> thePair;
        cout << "Enter element " << i << endl;
        cin >> thePair.first; // 输入元素
        thePair.second = 1;   // 频度初始化为1
        // 插入数对,如果键值已存在,频度值加1
        theTree.insert(thePair, add1);
    }
    cout << "Distinct elements and frequencies are"
         << endl;
    theTree.ascend(); // 输出
    return 0;
}

方法insert

template <class K, class E>
void binarySearchTreeWithVisit<K, E>::insert(const pair<const K, E> &thePair,
                                             void (*visit)(E &u))
{
    // 插入一个数对thePair,如果存在关键字相同的数对,则覆盖
    binaryTreeNode<pair<const K, E>> *p = root, // 搜索指针
        *pp = nullptr;                          // p的父节点指针
    // 寻找插入点
    while (p != nullptr)
    {
        pp = p;
        if (thePair.first < p->element.first)
            p = p->leftChild;
        else if (thePair.first > p->element.first)
            p = p->rightChild;
        else
        {
           // p->element.second = thePair.second; // 覆盖旧值
            visit(p->element.second);
            return;
        }
    }
    // 为thePair 建立一个新节点,并将该节点连接至 pp
    binaryTreeNode<pair<const K, E>> *newNode =
        new binaryTreeNode<pair<const K, E>>(thePair);
    if (root != nullptr)
    { // 树非空
        if (thePair.first < pp->element.first)
            pp->leftChild = newNode;
        else
            pp->rightChild = newNode;
    }
    else // 插入到空树中
        root = newNode;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值