《算法导论》— Chapter 12 二叉查找树

本文详细介绍了二叉查找树的基本概念、性质及其实现方法,包括查找、插入、删除等核心操作,并通过示例代码展示了如何构建和维护二叉查找树。

查找树是一种数据结构,它支持多种动态集合操作。包含Search、Minimum、Maximum、PreDecessor、Successor、Insert、Delete等。它既能够用作字典,也能够用作优先级队列;在二叉查找树(Binary Search Tree)上执行基本操作的时间与树的高度成正比,对于一颗含有n个结点的全然二叉树,基本操作的最坏情况执行时间为floor(logn)


本章讨论二叉查找树的基本性质以及上面提及的基本操作的实现。

GitHub 程序实现代码

1 二叉查找树

1.1 性质

例如以下图所看到的。一颗二叉查找树是依照二叉树结构来组织的。这种树一般用链表结构表示,每个结点是一个对象,包含关键字key、父亲结点parent、左儿子结点left以及右儿子结点right四个属性。
图12-1 二叉查找树
明显的,对于二叉查找树中关键字的存储方式总是满足这种性质:
x为二叉查找树中的一个结点。假设yx左子树中的一个结点,则y>key<=x>key,假设yx右子树中的一个结点,则y>key>=x>key

1.2 基本操作

1.2.1 遍历

依据二叉查找树的性质。能够用一个递归算法依照排列顺序依次输出全部关键字,这就是中序遍历,遍历顺序为根、左子树、右子树。相同的,有前序遍历,根的关键字在左右子树之前输出。后序遍历。根的关键字在其左右子树之后输出。

1.2.2 查找

对于二叉查找树,最常见的操作就是查找树中的某个关键字。

查找操作相同採用递归的形式实现,其复杂度等于树的高度。
操作步骤例如以下图所看到的:
图12-2 二叉查找树查询操作

1.2.3 求最大、最小关键字

对于用作优先级队列的结构。求最大最小关键字是不可缺少的操作。
要查找二叉查找树中的最小关键字,依据树的性质,仅仅要从根节点開始,沿着各个结点的left指针查找下去,直到遇到NULL为止。


同理,要查找二叉查找树中的最大关键字,依据树的性质。仅仅要从根节点開始,沿着各个结点的right指针查找下去,直到遇到NULL为止。
这两个操作的执行时间都是O(h)

1.2.4 求前驱、后继

我们知道。中序遍历二叉查找树得到的是一组有序序列,有时候须要求指定结点的前驱与后继。对于给定结点x的后继结点是具有大于或等于x>key中关键字的最小结点;同理,对于给定结点x的前驱结点是具有小于x>key中关键字的最大结点。依据二叉查找树的性质,不用对关键字做不论什么比較就能够得到给定结点的前驱和后继结点。

1.2.5 插入

插入和删除操作会引起整个二叉查找树表示的集合的动态变化。要反应出这种变化。就要改动数据结构,可是在改动的同一时候。还要保持整棵树的性质不变。


将新值插入到一颗二叉查找树中的步骤例如以下:

1.2.6 删除

相对于插入操作。删除更加复杂一些。下图具体展示了删除不同结点须要的步骤:
图12-4 二叉查找树删除操作
对高度为h的二叉查找树,动态集合操作Insert与Delete的执行时间都是O(n)

2 二叉查找树程序实现

以下给出的程序实现。包含了全部以上提及的基本操作:
(1)BinarySearchTree.h

#ifndef _BINARYSEARCHTREE_H_
#define _BINARYSEARCHTREE_H_

#include <iostream>

typedef struct BSTNode{
    BSTNode *left;
    BSTNode *right;
    BSTNode *parent;

    int key;

    BSTNode(int data) : left(NULL), right(NULL), parent(NULL), key(data){}
};

class BinarySearchTree{
public:
    BinarySearchTree();
    ~BinarySearchTree();

    //插入删除操作
    void Insert(int data);
    BSTNode *Delete(int data);
    BSTNode *root;
};

//查找操作
BSTNode *Search(BSTNode * node, int data);

//遍历操作
void InOrderWalk(BSTNode * node);
void PreOrderWalk(BSTNode * node);
void PostOrderWalk(BSTNode * node);

//查询最大最小值
BSTNode *Maximum(BSTNode * node);
BSTNode *Minimum(BSTNode * node);

//查找前驱与后继
BSTNode *PreDecessor(BSTNode *node);
BSTNode *Successor(BSTNode *node);

#endif

(2)BinarySearchTree.cpp

#include "BinarySearchTree.h"
#include <iostream>

BinarySearchTree::BinarySearchTree()
{
    root = NULL;
}

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

//向二分查找树中插入数据data
void BinarySearchTree::Insert(int data)
{
    BSTNode *node = new BSTNode(data);
    BSTNode *p = root, *q = NULL;
    while (p != NULL)
    {
        q = p;
        if (p->key > data)
            p = p->left;
        else
            p = p->right;
    }
    node->parent = q;
    if (q == NULL)
        root = node;
    else if (q->key > data)
        q->left = node;
    else
        q->right = node;
}

//从二分查找树中删除数据
BSTNode *BinarySearchTree::Delete(int data)
{
    BSTNode *node = Search(root, data);
    BSTNode *ret , *tmp;

    if (node == NULL)
        return node;

    //假设目标结点仅仅有一个子女则删除该结点,否则删除其后继结点
    if (node->left == NULL || node->right == NULL)
        ret = node;
    else
        ret = Successor(node);

    //假设被删结点有左右孩子,将其链接到被删结点的父节点
    if (ret->left != NULL)
        tmp = ret->left;
    else
        tmp = ret->right;

    if (tmp != NULL)
        tmp->parent = ret->parent;
    //假设被删结点的父节点为空,则说明要删的是根节点
    if (ret->parent == NULL)
        root = tmp;
    else if (ret == ret->parent->left)
        ret->parent->left = tmp;
    else
        ret->parent->right = tmp;

    if (ret != node)
        node->key = ret->key;

    return ret;
}

//查找以node结点为根的子树中值为data的结点
BSTNode *Search(BSTNode * node, int data)
{
    if (node == NULL || node->key == data)
        return node;
    if (data < node->key)
        return Search(node->left, data);
    else
        return Search(node->right, data);
}

//遍历操作
void InOrderWalk(BSTNode * node)
{
    if (node != NULL)
    {
        InOrderWalk(node->left);
        std::cout << node->key << "\t";
        InOrderWalk(node->right);
    }
}

void PreOrderWalk(BSTNode * node)
{
    if (node != NULL)
    {
        std::cout << node->key << "\t";
        InOrderWalk(node->left);
        InOrderWalk(node->right);
    }
}

void PostOrderWalk(BSTNode * node)
{
    InOrderWalk(node->left);
    InOrderWalk(node->right);
    std::cout << node->key << "\t";
}

//查询最大最小值
BSTNode *Maximum(BSTNode * node)
{
    while (node->left != NULL)
        node = node->left;
    return node;
}

BSTNode *Minimum(BSTNode * node)
{
    while (node->right != NULL)
        node = node->right;
    return node;
}

//查找前驱与后继
BSTNode *PreDecessor(BSTNode *node)
{
    if (node->left != NULL)
        return Maximum(node->left);

    BSTNode *p = node->parent;
    while (p != NULL && node == p->left)
    {
        node = p;
        p = node->parent;
    }

    return p;
}


BSTNode *Successor(BSTNode *node)
{
    if (node->right != NULL)
        return Minimum(node->right);
    BSTNode *p = node->parent;
    while (p != NULL && node == p->right)
    {
        node = p;
        p = node->parent;
    }

    return p;
}

(3)main.cpp

#include "BinarySearchTree.h"
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

const int MAX = 101;
const int N = 10;

int main()
{
    BinarySearchTree *bst = new BinarySearchTree();

    //设置随机化种子,避免每次产生相同的随机数   
    srand(time(0));

    //构造一个随机数组成的二分查找树
    for (int i = 0; i < N; i++)
        bst->Insert(rand() % MAX);

    //遍历查找树
    cout << "先序遍历二分查找树bst:" << endl;
    PreOrderWalk(bst->root);

    //遍历查找树
    cout << endl << "中序遍历二分查找树bst:" << endl;
    InOrderWalk(bst->root);

    //遍历查找树
    cout << endl << "后序遍历二分查找树bst:" << endl;
    PostOrderWalk(bst->root);

    int x = 45;
    BSTNode *node = Search(bst->root, x);
    if (node)
    {
        cout << endl << "二分查找树bst中存在结点x = " << x << endl;
        bst->Delete(x);

        cout << endl << "删除二分查找树中结点x = " << x << "成功!" << endl;

        //遍历查找树
        cout << endl << "先序遍历二分查找树bst:" << endl;
        PreOrderWalk(bst->root);

        //遍历查找树
        cout << endl << "中序遍历二分查找树bst:" << endl;
        InOrderWalk(bst->root);

        //遍历查找树
        cout << endl << "后序遍历二分查找树bst:" << endl;
        PostOrderWalk(bst->root);
        cout << endl << endl;
    }
    else{
        cout << endl << "二分查找树bst中不存在结点x = " << x << endl;
        cout << endl << endl;
    }

    system("pause");
    return 0;
}

測试结果(查找失败的情况):
測试结果
測试结果(查找成功并删除):
測试结果

3 随机构造的二叉查找树

在本章的最后介绍了一种随机构造二叉查找树的理论方法,这主要是针对普通二叉查找树基本操作执行时间O(h)考虑的。这种方式能够使得:
一棵在n个关键字上随机构造的二叉查找树的期望高度为O(logn)
这一部分感觉应用不多吧,木有细致看,^||^~~

转载于:https://www.cnblogs.com/wzzkaifa/p/7304942.html

标题SpringBoot智能在线预约挂号系统研究AI更换标题第1章引言介绍智能在线预约挂号系统的研究背景、意义、国内外研究现状及论文创新点。1.1研究背景与意义阐述智能在线预约挂号系统对提升医疗服务效率的重要性。1.2国内外研究现状分析国内外智能在线预约挂号系统的研究与应用情况。1.3研究方法及创新点概述本文采用的技术路线、研究方法及主要创新点。第2章相关理论总结智能在线预约挂号系统相关理论,包括系统架构、开发技术等。2.1系统架构设计理论介绍系统架构设计的基本原则常用方法。2.2SpringBoot开发框架理论阐述SpringBoot框架的特点、优势及其在系统开发中的应用。2.3数据库设计与管理理论介绍数据库设计原则、数据模型及数据库管理系统。2.4网络安全与数据保护理论讨论网络安全威胁、数据保护技术及其在系统中的应用。第3章SpringBoot智能在线预约挂号系统设计详细介绍系统的设计方案,包括功能模块划分、数据库设计等。3.1系统功能模块设计划分系统功能模块,如用户管理、挂号管理、医生排班等。3.2数据库设计与实现设计数据库表结构,确定字段类型、主键及外键关系。3.3用户界面设计设计用户友好的界面,提升用户体验。3.4系统安全设计阐述系统安全策略,包括用户认证、数据加密等。第4章系统实现与测试介绍系统的实现过程,包括编码、测试及优化等。4.1系统编码实现采用SpringBoot框架进行系统编码实现。4.2系统测试方法介绍系统测试的方法、步骤及测试用例设计。4.3系统性能测试与分析对系统进行性能测试,分析测试结果并提出优化建议。4.4系统优化与改进根据测试结果对系统进行优化改进,提升系统性能。第5章研究结果呈现系统实现后的效果,包括功能实现、性能提升等。5.1系统功能实现效果展示系统各功能模块的实现效果,如挂号成功界面等。5.2系统性能提升效果对比优化前后的系统性能
在金融行业中,对信用风险的判断是核心环节之一,其结果对机构的信贷政策风险控制策略有直接影响。本文将围绕如何借助机器学习方法,尤其是Sklearn工具包,建立用于判断信用状况的预测系统。文中将涵盖逻辑回归、支持向量机等常见方法,并通过实际操作流程进行说明。 一、机器学习基本概念 机器学习属于人工智能的子领域,其基本理念是通过数据自动学习规律,而非依赖人工设定规则。在信贷分析中,该技术可用于挖掘历史数据中的潜在规律,进而对未来的信用表现进行预测。 二、Sklearn工具包概述 Sklearn(Scikit-learn)是Python语言中广泛使用的机器学习模块,提供多种数据处理建模功能。它简化了数据清洗、特征提取、模型构建、验证与优化等流程,是数据科学项目中的常用工具。 三、逻辑回归模型 逻辑回归是一种常用于分类任务的线性模型,特别适用于二类问题。在信用评估中,该模型可用于判断借款人是否可能违约。其通过逻辑函数将输出映射为0到1之间的概率值,从而表示违约的可能性。 四、支持向量机模型 支持向量机是一种用于监督学习的算法,适用于数据维度高、样本量小的情况。在信用分析中,该方法能够通过寻找最佳分割面,区分违约与非违约客户。通过选用不同核函数,可应对复杂的非线性关系,提升预测精度。 五、数据预处理步骤 在建模前,需对原始数据进行清理与转换,包括处理缺失值、识别异常点、标准化数值、筛选有效特征等。对于信用评分,常见的输入变量包括收入水平、负债比例、信用历史记录、职业稳定性等。预处理有助于减少噪声干扰,增强模型的适应性。 六、模型构建与验证 借助Sklearn,可以将数据集划分为训练集测试集,并通过交叉验证调整参数以提升模型性能。常用评估指标包括准确率、召回率、F1值以及AUC-ROC曲线。在处理不平衡数据时,更应关注模型的召回率与特异性。 七、集成学习方法 为提升模型预测能力,可采用集成策略,如结合多个模型的预测结果。这有助于降低单一模型的偏差与方差,增强整体预测的稳定性与准确性。 综上,基于机器学习的信用评估系统可通过Sklearn中的多种算法,结合合理的数据处理与模型优化,实现对借款人信用状况的精准判断。在实际应用中,需持续调整模型以适应市场变化,保障预测结果的长期有效性。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值