数据结构:构建完全二叉查找树

news2025/1/22 21:05:40

文章目录

    • 1、步骤 1: 对给定数组排序
    • 2、步骤 2: 递归构建完全二叉查找树
    • 3、注意
    • 4、在有序数组中寻找根结点位置
    • 5、代码实现
    • 6、其他方法?
      • 基本思路
      • 插入操作
      • 删除操作
      • 特别考虑

  对于一个给定序列的二叉查找树,有很多种,但是完全二叉查找树只有一种,因为树形是确定的,我们按照中根序列遍历的顺序也是按照数值大小顺序的,因此 按照树结点的中根遍历顺序 将 序列按照数值大小顺序 填入这颗树形确定的完全二叉树中,可以得到一颗唯一确定的完全二叉树。并且对于根结点,其左子树的所有结点都小于根结点,右子树的所有结点都大于等于根结点。
  构建一颗 完全二叉查找树(Complete Binary Search Tree,CBST)的算法关键在于如何保证二叉树的完全性质,同时维护二叉查找树(BST)的特性:对于任意节点,其左子树的所有节点的值小于该节点的值,其右子树的所有节点的值大于等于该节点的值。

以下是构建完全二叉查找树的一种有效算法:

1、步骤 1: 对给定数组排序

由于二叉查找树的中序遍历结果是一个有序数组,**首先要对输入的无序数组进行排序。**根结点的位置是可以唯一确定的。

2、步骤 2: 递归构建完全二叉查找树

  1. 选择中间元素作为树的根:从排序好的数组中选择中间的元素作为二叉查找树的根节点。如果有两个中间元素,选择它们中的任意一个。
  2. 递归构建左子树和右子树:将根节点左侧的元素递归地构建成左子树,将根节点右侧的元素递归地构建成右子树。

3、注意

  • 完全二叉树的定义是除了最后一层外,每一层都是完全填满的,而最后一层从左向右填充。上述算法构建的是一棵高度平衡的二叉查找树,但不一定满足完全二叉树的严格定义。构建满足完全二叉树定义的二叉查找树需要更复杂的逻辑来确保所有层(除了可能的最后一层)都完全填满。
  • 确保完全性的一个方法是通过计算给定元素数量所能构建的完全二叉树的最大高度,然后在构建过程中控制树的形态,使其满足完全二叉树的性质。

4、在有序数组中寻找根结点位置

在这里插入图片描述

完全二叉树的性质:

  • 性质的数学公式换算:
    • 树的结点个数n 取对数 可以得到树高: Treeheight=log2(n)
    • 通过树高 可以得到 除最后一层之外的右子树结点个数:rightTree1=pow(2,Treeheight-1)-1
    • 通过树高 以及 树的结点个数 可以得到树的最后一层结点个数:lastLevelNodes=n-(pow(2,Treeheight)-1)
    • 最后可以得到 右子树结点个数:rightTree=rightTree1+((lastLevelNodes-pow(2,Treeheight-1))>0?(lastLevelNodes-pow(2,Treeheight-1)) :0)
  • 直接求满了的层的总结点个数:
    • 利用快速幂思想,即取出总结点数n的二进制位数的最高位。
    • 然后计算即可得到右子树的个数

5、代码实现

  • 数学性质
#include<bits/stdc++.h>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 构建完全二叉查找树
TreeNode* createTree(int start, int end, vector<int>& sortedValues) {
    if (start > end) return nullptr;

    // 计算完全二叉树的最后一层前的所有节点数和最后一层的节点数
    int totalNodes = end - start + 1;
    int fullLevels = log2(totalNodes + 1);
    int lastLevelNodes = totalNodes - (pow(2, fullLevels) - 1);
    int leftSubtreeNodes = pow(2, fullLevels - 1) - 1 + min((int)pow(2, fullLevels - 1), lastLevelNodes);

    // 根据左子树的节点数确定根节点
    int rootIndex = start + leftSubtreeNodes;
    TreeNode* root = new TreeNode(sortedValues[rootIndex]);
    root->left = createTree(start, rootIndex - 1, sortedValues);
    root->right = createTree(rootIndex + 1, end, sortedValues);

    return root;
}

// 层次遍历
void traversal(TreeNode* root) {
    if (!root) return;
    queue<TreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        TreeNode* current = q.front(); q.pop();
        cout << current->val << " ";
        if (current->left) q.push(current->left);
        if (current->right) q.push(current->right);
    }
}

int main() {
    int n;
    cin >> n;
    vector<int> values(n);
    for (int& value : values) {
        cin >> value;
    }
    sort(values.begin(), values.end());

    TreeNode* root = createTree(0, n - 1, values);
    traversal(root);
    return 0;
}
  • 直接计算
#include<bits/stdc++.h>
using namespace std;
struct TreeNode{
    TreeNode * left=nullptr;
    TreeNode * right=nullptr;
    int val;
    TreeNode (int v=0):val(v) {}
};
TreeNode * createTree(int left,int right,vector<int> & baby){//O(nlogn)
    if(left>right) return nullptr;
    if(left==right) return new TreeNode(baby[left]);
    TreeNode * root=nullptr;
    int flag=right-left+2;
    int b=1;
    while(flag!=1){//O(logn) 每次建树logn,n个结点共nlogn
        b*=2;
        flag>>=1;
    }
    int rightTree_size=b/2-1;
    if(rightTree_size+2-b-b/2>0){
       rightTree_size+=rightTree_size+2-b-b/2;
    }
    root=new TreeNode(baby[right-rightTree_size]);
    root->left=createTree(left,right-rightTree_size-1,baby);
    root->right=createTree(right-rightTree_size+1,right,baby);
    return root;
}
int main(void){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin>>n;
    vector<int> baby;
    for(int i=0;i<n;++i){
        int j;cin>>j;
        baby.emplace_back(j);
    }
    sort(baby.begin(),baby.end());//O(nlogn)
    createTree(0,n-1,baby);
    return 0;
}

6、其他方法?

动态构建完全二叉查找树(CBST)比静态构建更为复杂,因为需要在插入和删除操作发生时持续保持树的完全二叉树性质。一种方法是在每次插入或删除后重建树,但这显然效率不高。另一种思路是通过维护额外的信息和采用特定的插入/删除策略来尽可能保持树的完全性。下面是一个较为高效的动态构建完全二叉查找树的策略:

基本思路

动态维护一个完全二叉查找树,主要挑战在于插入和删除操作。对于插入操作,需要找到树中最后一个节点并在适当的位置插入新节点以保持完全二叉树的性质。对于删除操作,则需要找到可以替换被删除节点的节点(通常是树中的最后一个节点)并调整树以保持其完全性质。

插入操作

  1. 计算完全二叉树的深度:基于树当前的节点数量,可以计算出树的深度。
  2. 定位插入点:根据完全二叉树的性质,新节点应当被插入为最后一个节点。可以通过深度和节点数定位到这个位置。
  3. 执行插入:在定位到的位置插入新节点。如果需要,调整树的结构以保持二叉查找树的性质。

删除操作

  1. 定位并删除目标节点:找到需要删除的节点,将其删除。如果这个节点不是最后一个节点,则需要找到最后一个节点。
  2. 用最后一个节点替换删除的节点(如果被删除的节点不是最后一个节点):将最后一个节点移动到被删除节点的位置。
  3. 调整树:可能需要对树进行调整,以保持二叉查找树的性质。

特别考虑

  • 这种方法要求你能快速定位到树的最后一个节点,这可能需要维护额外的信息,如每层的节点数。
  • 插入和删除操作可能导致需要重新平衡树,以保持二叉查找树的性质。
  • 动态维护完全二叉树的复杂度主要在于定位最后一个节点和维护二叉查找树的性质。

动态地维护一个完全二叉查找树在实践中较为罕见,因为它要求在每次操作后都严格保持完全二叉树的性质,这可能导致较高的复杂性和成本。通常,人们会使用其他类型的自平衡二叉搜索树(如AVL树、红黑树)来获得较好的平均性能,尽管这些树不保证完全性质。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1579708.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot 整合 mybatis(配置版)

代码及配置整合 创建实体类,与数据库对应 创建 mapper、service 和 controller @AutowiredUserService userService;@ResponseBody@GetMapping("/user")public com.vazquez.bootstudy.model.User getById(@RequestParam("id") Long id) {return userServ…

AI大模型基石:文字与数字的起源与演变

AI大模型基石&#xff1a;文字与数字的起源与演变 1、文字 1.1、起源 我们的祖先在还没有发明文字和语言之前就已经开始使用“咿咿呀呀”的声音来传播信息了&#xff0c;比如在野外活动遇到危险&#xff0c;然后发出“咿咿呀呀”的声音来提醒同伴小心&#xff0c;同伴在接收到…

物联网数据服务平台

随着物联网技术的迅猛发展&#xff0c;海量数据的产生和应用成为推动工业数字化转型的核心动力。在这个数据为王的时代&#xff0c;如何高效地收集、处理、分析并应用这些数据&#xff0c;成为了企业关注的焦点。物联网数据服务平台应运而生&#xff0c;为企业提供了全面、高效…

20240403-算法复习打卡day43||● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

1049. 最后一块石头的重量 II class Solution { public:int lastStoneWeightII(vector<int>& stones) {vector<int> dp(15001, 0);int sum 0;for (int i 0; i < stones.size(); i) sum stones[i];int target sum / 2;for (int i 0; i < stones.siz…

群晖NAS使用Docker部署Potopea在线图片编辑工具并实现公网访问

文章目录 1. 部署Photopea2. 运行Photopea3. 群晖安装Cpolar4. 配置公网地址5. 公网访问测试6. 固定公网地址 本文主要介绍如何在群晖NAS使用Docker部署Potopea在线图片编辑工具&#xff0c;并结合cpolar内网穿透实现公网环境可以远程访问本地部署的Potopea. Photopea是一款强大…

鸿蒙OS实战开发:【多设备自适应服务卡片】

介绍 服务卡片的布局和使用&#xff0c;其中卡片内容显示使用了一次开发&#xff0c;多端部署的能力实现多设备自适应。 用到了卡片扩展模块接口&#xff0c;[ohos.app.form.FormExtensionAbility] 。 卡片信息和状态等相关类型和枚举接口&#xff0c;[ohos.app.form.formInf…

设计模式 -- 发布订阅模式

发布订阅模式&#xff1a; 订阅者把自己想订阅的事件注册到调度中心&#xff0c;当发布者发布该事件到调度中心&#xff0c;也就是该事件触发时&#xff0c;由调度者统一调度订阅者注册到调度中心的处理代码。 在javaScript 中我们一般使用事件模型来代替传统的发布订阅模式。 …

最长上升子序列(线性dp)-java

主要是解决最长上升子序列问题&#xff0c;推出状态转移方程。 文章目录 前言 一、最长上升子序列问题 二、算法思路 1.最长上升子序列思路 三、代码如下 1.代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入数据 3.代码运行结果 总结 前言 主要是解决最长上升子序列问…

三相交流电子负载的基础认识

三相交流电子负载主要用于电源、电机、逆变器等产品的测试和老化&#xff0c;它能够精确地模拟各种负载的工作状态&#xff0c;如阻性、感性、容性等&#xff0c;以满足不同产品的测试需求。三相交流电子负载具有响应速度快、精度高、稳定性好等特点&#xff0c;是现代电力电子…

6款超好用AI写作神器,写作效率秒拔高! #经验分享#人工智能#知识分享

在当今信息爆炸的时代&#xff0c;写作成为了人们表达思想、分享知识和传递情感的重要方式之一。对于很多人来说&#xff0c;写作并非易事。我们会陷入困境&#xff0c;无法找到灵感&#xff0c;我们会苦恼于语言表达的准确性&#xff0c;还有时候我们可能遭遇到了创作瓶颈&…

功耗低、触控灵敏度高、抗干扰能力强等众多优势,输出方式多样的单键电容式触控芯片TS223B介绍

•应用领域• 适用于小家电、电子玩具、智能物联网等各种触控产品方案。 •功能介绍• 单键电容式触控芯片TS223B具有功耗低、触控灵敏度高、抗干扰能力强等众多优势&#xff0c;输出方式包括直接输出、电平翻转输出&#xff0c;并且输出的初始状态可以配置&#xff0c;能灵活满…

UVA12538 Version Controlled IDE 题解 crope

Version Controlled IDE 传送门 题面翻译 维护一种数据结构&#xff0c;资磁三种操作。 1.在p位置插入一个字符串s 2.从p位置开始删除长度为c的字符串 3.输出第v个历史版本中从p位置开始的长度为c的字符串 1 ≤ n ≤ 50000 1 \leq n \leq 50000 1≤n≤50000&#xff0c;所…

Spring声明式事务(Spring学习笔记十三)

不推荐使用编程式事务 在Spring-dao.xml中配置声明式事务 <!--配置声明式事务 --><!--获得transactionManager然后把他丢给他的构造器 constructor-arg --><bean id"transactionManager" class"org.springframework.jdbc.datasource.Data…

网站压力测试和Locust

一、压力测试介绍 网站压力测试是一种评估网站性能、可靠性和稳定性的方法。它通过模拟大量用户同时访问网站,来测试网站的响应时间、吞吐量、资源利用率等指标,从而发现网站的潜在问题和瓶颈。下面我将从几个方面详细介绍网站压力测试: 1、压力测试的目的 评估网站在高并发…

Midjourney该怎么用?从零基础到落地实践

前言 从注册登录到基本的操作界面&#xff0c;提示词组成后缀介绍&#xff0c;到主流的生成图片的方式&#xff0c;以及最重要的提示词咒语分享&#xff0c;还有一些我的使用心得&#xff0c;希望对大家有帮助&#xff01; 喜欢的话欢迎关注我&#xff0c;欢迎点赞收藏评论&am…

如何运用工业智能网关将数据上传到设备数字化平台

在数字化浪潮的推动下&#xff0c;工业领域正迎来前所未有的变革。工业智能网关作为连接物理世界与数字世界的桥梁&#xff0c;其在数据采集、传输和处理方面发挥着不可或缺的作用。而HiWoo Cloud平台&#xff0c;正是利用工业智能网关&#xff0c;实现设备数据数字化管理的强大…

RTThread studio 驱动开发

rtthread 驱动开发的两种情况 rtthread studio 自动生成 由 RT Thread Studio 自动生成&#xff0c;无需修改任何文件或者简单定义几个宏即可直接使用的驱动&#xff0c;如 GPIO&#xff0c;UART&#xff0c;I2C&#xff0c;SPI&#xff0c;SDIO 和 ETH 等。 使用 RT-Thread S…

Flowise AI工作流本地部署实战教程

&#x1f9d9;‍♂️ 诸位好&#xff0c;吾乃斜杠君&#xff0c;编程界之翘楚&#xff0c;代码之大师。算法如流水&#xff0c;逻辑如棋局。 &#x1f4dc; 吾之笔记&#xff0c;内含诸般技术之秘诀。吾欲以此笔记&#xff0c;传授编程之道&#xff0c;助汝解技术难题。 &#…

axure谷歌插件(直接下载)

axure谷歌插件 在网上找一个谷歌的axure&#xff0c;不是登陆就是收费&#xff0c;离谱。找了好久才找到这个&#xff0c;我下载保存到网盘了&#xff0c;直接下载就ok&#xff0c;永久无提取码。 下载插件文件&#xff0c;打开开发者模式&#xff0c;直接拖进来就ok。 网盘…

网络安全行业现在还能入吗?

这几年随着我国《国家网络空间安全战略》《网络安全法》《网络安全等级保护2.0》等一系列政策/法规/标准的持续落地&#xff0c;网络安全行业地位、薪资随之水涨船高。 未来3-5年&#xff0c;是安全行业的黄金发展期&#xff0c;提前踏入行业&#xff0c;能享受行业发展红利。…