突破编程_C++_查找算法(红黑树查找)

1 算法题 :使用红黑树的数据结构在无序数组中查找指定元素

1.1 题目含义

这个题目要求实现一个红黑树(Red-Black Tree),这是一种自平衡的二叉查找树,它通过颜色和一系列的调整规则来确保树的大致平衡,从而实现对数级别的查找、插入和删除操作。题目要求你在实现红黑树的基础上,使用它来在一个无序数组中查找指定的元素,并返回该元素在原始数组中的位置(索引)。

红黑树的性质

红黑树满足以下五个性质:

  • 每个节点要么是红色,要么是黑色。
  • 根节点是黑色。
  • 所有叶子节点(NIL 或空节点)是黑色。
  • 如果一个节点是红色的,则它的两个子节点都是黑色(从每个叶子到根的所有路径上不能有两个连续的红色节点)。
  • 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。

1.2 示例

示例 1:
输入:

  • nums = [4, 2, 7, 10, 1, 6, 8]
  • target = 7

输出:

  • 2

说明:

  • 首先,根据数组 [4, 2, 7, 10, 1, 6, 8] 构建一个 B 树。然后,在树中查找元素 7。找到后,返回元素 7 在原始数组中的位置,即索引 2。

示例 2:
输入:

  • nums = [1, 3, 5, 7]
  • target = 9

输出:

  • -1

说明:

  • 根据数组 [1, 3, 5, 7] 构建 B 树后,在树中查找元素 9。由于元素 9 不存在于树中,所以返回 -1,表示未找到目标值。

示例 3:
输入:

  • nums = []
  • target = 0

输出:

  • -1

说明:

  • nums 为空,0 不存在于 nums 中,返回 -1。

2 解题思路

这一题目涉及两个主要步骤:红黑树的构建和红黑树中的元素查找,以及如何在红黑树节点和原始数组元素之间建立并维护索引映射关系。

第一步:定义红黑树节点结构

首先,需要定义一个红黑树的节点结构。每个节点需要包含键(即元素值),颜色(红色或黑色),以及指向父节点、左孩子和右孩子的指针。这里可以使用结构体或类来表示这个节点。

第二步:实现红黑树的基本操作

在插入或删除节点时,可能需要执行一些基本操作来保持红黑树的性质。这些操作包括:

  • 旋转:左旋和右旋。旋转操作是为了在插入或删除节点后重新平衡树结构。
  • 颜色调整:改变节点的颜色。当插入或删除节点导致红黑树的性质被破坏时,可以通过改变节点的颜色来修复。

这些操作是构建红黑树的基础,必须正确实现。

第三步:实现红黑树的插入操作

插入操作是构建红黑树索引的关键步骤。需要将每个数组元素及其位置作为键值对插入到红黑树中。插入过程中,遵循二叉查找树的规则,并在插入后检查红黑树的性质是否被破坏。如果破坏了,则使用第二步中定义的基本操作来修复。

第四步:构建红黑树索引

遍历无序数组,对于数组中的每个元素,执行以下步骤:

  • 将元素及其位置作为键值对插入到红黑树中。
  • 检查红黑树的性质,如果需要,执行旋转和颜色调整。
  • 完成遍历后,就得到了一个包含数组元素及其位置信息的红黑树索引。

第五步:实现红黑树的查找操作

查找操作是从根节点开始,根据二叉查找树的规则向下遍历红黑树,直到找到要查找的元素或者遍历到叶子节点。如果找到了元素,返回该元素在红黑树中对应的节点所存储的位置信息。

第六步:处理查找结果

在查找操作中,需要处理几种情况:

  • 如果找到了元素,返回该元素在红黑树中对应的节点所存储的位置信息,即该元素在原始数组中的位置。
  • 如果元素在数组中不存在,返回一个特殊值(如 -1)来表示未找到。
  • 如果元素在数组中存在多个,根据题目要求,只返回元素第一次出现的位置。

第七步:调用查找操作并输出结果

最后,调用红黑树的查找操作,传入要查找的元素,并根据第六步中的规则处理查找结果。然后,将结果输出,完成整个算法题的要求。

3 算法实现代码

如下为算法实现代码:

#include <iostream>
#include <deque>
#include <vector>
using namespace std;enum Color { RED, BLACK };struct Node
{int data;int position;bool color;Node *left, *right, *parent;Node(int data, int position){this->data = data;this->position = position;left = right = parent = NULL;this->color = RED;}
};class RedBlackTree
{
private:Node *root;
protected:void rotateLeft(Node *&, Node *&);void rotateRight(Node *&, Node *&);void fixViolation(Node *&, Node *&);
public:RedBlackTree() { root = NULL; }void insert(const int &data, const int &position);void inorder();void levelOrder();int findPosition(int value);
};void inorderHelper(Node *root)
{if (root == NULL)return;inorderHelper(root->left);cout << root->data << "  ";inorderHelper(root->right);
}Node* BSTInsert(Node* root, Node *pt)
{if (root == NULL)return pt;if (pt->data < root->data){root->left = BSTInsert(root->left, pt);root->left->parent = root;}else if (pt->data > root->data){root->right = BSTInsert(root->right, pt);root->right->parent = root;}return root;
}void levelOrderHelper(Node *root)
{if (root == NULL)return;static deque<Node *> q;q.push_back(root);while (!q.empty()){Node *temp = q.front();cout << temp->data << "  ";q.pop_front();if (temp->left != NULL)q.push_back(temp->left);if (temp->right != NULL)q.push_back(temp->right);}
}void RedBlackTree::rotateLeft(Node *&root, Node *&pt)
{Node *pt_right = pt->right;pt->right = pt_right->left;if (pt->right != NULL)pt->right->parent = pt;pt_right->parent = pt->parent;if (pt->parent == NULL)root = pt_right;else if (pt == pt->parent->left)pt->parent->left = pt_right;elsept->parent->right = pt_right;pt_right->left = pt;pt->parent = pt_right;
}void RedBlackTree::rotateRight(Node *&root, Node *&pt)
{Node *pt_left = pt->left;pt->left = pt_left->right;if (pt->left != NULL)pt->left->parent = pt;pt_left->parent = pt->parent;if (pt->parent == NULL)root = pt_left;else if (pt == pt->parent->left)pt->parent->left = pt_left;elsept->parent->right = pt_left;pt_left->right = pt;pt->parent = pt_left;
}void RedBlackTree::fixViolation(Node *&root, Node *&pt)
{Node *parent_pt = NULL;Node *grand_parent_pt = NULL;while ((pt != root) && (pt->color != BLACK) && pt->parent &&(pt->parent->color == RED)){parent_pt = pt->parent;grand_parent_pt = pt->parent->parent;if (parent_pt == grand_parent_pt->left){Node *uncle_pt = grand_parent_pt->right;if (uncle_pt != NULL && uncle_pt->color == RED){grand_parent_pt->color = RED;parent_pt->color = BLACK;uncle_pt->color = BLACK;pt = grand_parent_pt;}else{if (pt == parent_pt->right){rotateLeft(root, parent_pt);pt = parent_pt;parent_pt = pt->parent;}rotateRight(root, grand_parent_pt);swap(parent_pt->color, grand_parent_pt->color);pt = parent_pt;}}else{Node *uncle_pt = grand_parent_pt->left;if ((uncle_pt != NULL) && (uncle_pt->color == RED)){grand_parent_pt->color = RED;parent_pt->color = BLACK;uncle_pt->color = BLACK;pt = grand_parent_pt;}else{if (pt == parent_pt->left){rotateRight(root, parent_pt);pt = parent_pt;parent_pt = pt->parent;}rotateLeft(root, grand_parent_pt);swap(parent_pt->color, grand_parent_pt->color);pt = parent_pt;}}}root->color = BLACK;
}void RedBlackTree::insert(const int &data, const int &position)
{Node *pt = new Node(data, position);root = BSTInsert(root, pt);fixViolation(root, pt);
}void RedBlackTree::inorder() { inorderHelper(root); }
void RedBlackTree::levelOrder() { levelOrderHelper(root); }int RedBlackTree::findPosition(int value) {Node* current = root;while (current != NULL) {if (value < current->data) {current = current->left;}else if (value > current->data) {current = current->right;}else { // value is equal to current node data, position found!return current->position;}}// value not found in the tree, return -1 or any invalid position.return -1;
}class Solution
{
public:int redBlackTreeSearch(std::vector<int>& nums, int target) {RedBlackTree tree;for (size_t i = 0; i < nums.size(); i++){tree.insert(nums[i], i);}int position = tree.findPosition(target);return position;}
};

这段代码实现了一个红黑树,并使用它在有序数组中查找指定数值的位置。

首先定义了一个节点类 Node,包含数据 data、数据原始位置 position、颜色 color、左右子节点 left 和 right 以及父节点parent。其中,颜色用枚举类型 Color 表示,包括 RED 和 BLACK 两种颜色。

接着定义了一个红黑树类 RedBlackTree,包含了插入节点、中序遍历、层序遍历等方法。其中,插入节点的方法 BSTInsert 是二叉搜索树的插入方法,而 fixViolation 方法用于修复插入节点后可能破坏红黑树性质的操作。

调用上面的算法,并得到输出:

int main()
{Solution s;std::vector<int> nums= { 15, 10, 20, 8, 12, 16, 25 }; int target = 16;int position = s.redBlackTreeSearch(nums, target);if (position != -1) { cout << "The position of " << target << " in the array is: " << position << endl;}else { cout << "Value not found in the tree." << endl;}return 0;
}

上面代码的输出为:

The position of 16 in the array is: 5

4 测试用例

以下是针对上面算法的测试用例,基本覆盖了各种情况:

(1)基础测试用例
输入:数组 [3, 5, -1, 0, 9, 12],目标值 9
输出:4
说明:目标值 9 存在于数组中,位于索引 4 的位置。

(2)目标值不存在于数组中
输入:数组 [3, 5, -1, 0, 9, 12],目标值 2
输出:-1
说明:目标值 2 不存在于数组中。

(3)目标值位于数组开头
输入:数组 [-1, 0, 3, 9, 5, 12],目标值 -1
输出:0
说明:目标值 -1 位于数组的开头,即索引 0 的位置。

(4)目标值位于数组末尾
输入:数组 [9, -1, 3, 0, 5, 12],目标值 12
输出:5
说明:目标值 12 位于数组的末尾,即索引 5 的位置。

(5)目标值位于数组中间
输入:数组 [0, -1, 3, 9, 5, 12],目标值 3
输出:2
说明:目标值 3 位于数组的中间位置,即索引 2 的位置。

(6)空数组
输入:数组 [],目标值 9
输出:-1
说明:空数组不包含任何元素,因此无法找到目标值。

(7)数组只有一个元素
输入:数组 [9],目标值 9
输出:0
说明:数组只有一个元素,且该元素就是目标值,位于索引 0 的位置。

(8)数组中存在多个相同的目标值
输入:数组 [1, 2, 3, 3, 4, 5],目标值 3
输出:2 或 3
说明:数组中存在多个目标值 3,返回任意一个目标值的索引都是正确的。这里可以返回 2 或 3。

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

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

相关文章

uni-app 实现仿微信界面【我的+首页聊天列表+长按菜单功能+添加菜单功能】+ 附源码

目录 【微信首页聊天列表】界面 【我的】界面 源代码&#xff1a; 文后附完整代码&#xff0c;支持一键导入 HBuilderX 示例体验 【微信首页聊天列表】界面 仿造【微信首页聊天列表 长按菜单功能 右上角添加按钮弹窗功能】&#xff0c;使用 uni-app 开发&#xff0c; 一…

深入浅出 -- 系统架构之微服务架构选型参考图

技术选型架构图 是一个用于展示项目中所采用的各种技术和组件之间关系的图表。 它通常包括以下几个部分&#xff1a; 1. 项目名称和描述&#xff1a;简要介绍项目的背景和目标。 2. 技术栈&#xff1a;列出项目中使用的主要技术和工具&#xff0c;如编程语言、框架、数据库…

[xboard]real6410-5.2 移植kernel网络驱动

文章目录 硬件电路 核心板,使用DM9000A [图片] 软件配置 问题1 / # / # ifconfig ifconfig: /proc/net/dev: No such file or directory ifconfig: socket: Function not implemented 参考https://blog.csdn.net/u011011827/article/details/115479707 问题2 / # ifconfig i…

Spring Boot程序中@JsonIgnoreProperties与@JsonIgnore的基本使用

问题由来&#xff1a; springboot项目中定义了很多类&#xff0c;我们在rest返回中直接返回或者在返回对象中使用这些类&#xff0c;spring已经使用jackson自动帮我们完成这些的to json。但是有时候自动转的json内容太多&#xff0c;或者格式不符合我们的期望&#xff0c;因此需…

JVM专题——类文件加载

本文部分内容节选自Java Guide和《深入理解Java虚拟机》, Java Guide地址: https://javaguide.cn/java/jvm/class-loading-process.html &#x1f680; 基础&#xff08;上&#xff09; → &#x1f680; 基础&#xff08;中&#xff09; → &#x1f680;基础&#xff08;下&a…

(免费分享)基于springboot,vue房屋租赁管理系统

功能说明&#xff1a; * 普通用户角色&#xff1a; 1. 寻找房源功能--提供了两种寻找房源的功能&#xff0c;一种是普通用户在平台上搜索、筛选主动寻找房源的功能&#xff0c;另一种是用户填写征集房源的条件&#xff0c;系统会持续将最新符合条件的房源推送给用户。 2. …

《Effective C++》《构造/析构/赋值运算——11、在operator=中处理“自我赋值”》

文章目录 1、Terms11:Handle assignment to self in operator类中自我赋值问题及如何解决自我赋值问题解决&#xff1a;异常处理问题解决使用“copy and swap”技术来处理自我赋值 2、面试相关2.1 什么是自我赋值&#xff1f;为什么它是个问题&#xff1f;2.2 在重载赋值操作符…

Vuex的模块化管理

1&#xff1a;定义一个单独的模块。由于mutation的第二个参数只能提交一个对象&#xff0c;所以这里的ThisLog是个json串。 2&#xff1a;在Vuex中的index.js中引入该模块 3&#xff1a;在别的组件中通过...mapState调用模块保存的State的值。 4&#xff1a;用...mapMutations修…

【番外篇2】统计学-方差分析

方差分析 方差分析&#xff08;ANOVA&#xff09;是一种用于比较三个或三个以上组之间平均值是否有显著差异的统计方法。通俗地说&#xff0c;就是用来确定不同组之间的平均值是否有显著差异。 让我们通过一个简单的例子来解释方差分析&#xff1a; 假设你是一位教育工作者&a…

界面控件Kendo UI for jQuery 2024 Q1亮点 - 新的ToggleButton组件

Telerik & Kendo UI 2024 Q1 版本于2024年初发布&#xff0c;在此版本中将AI集成到了UI组件中&#xff0c;在整个产品组合中引入AI Prompt组件以及10多个新的UI控件、支持Angular 17、多个数据可视化功能增强等。 P.S&#xff1a;Kendo UI for jQuery提供了在短时间内构建…

哲♂学家带你用顺序表实现通讯录

实现通讯录能使我们进一步加深对顺序表的理解&#xff0c;接下来就由本哲♂学家带你手把手实现通信录。 其中需要用到顺序表的知识可以点击下面链接了解&#xff1a;http://t.csdnimg.cn/9SjGd话不多说&#xff0c;我们♂开始吧。 一、通讯录头文件声明 由于我们前面已经写过…

四核8g服务器价格多少钱?

2024年腾讯云4核8G服务器租用优惠价格&#xff1a;轻量应用服务器4核8G12M带宽646元15个月&#xff0c;CVM云服务器S5实例优惠价格1437.24元买一年送3个月&#xff0c;腾讯云4核8G服务器活动页面 txybk.com/go/txy 活动链接打开如下图&#xff1a; 腾讯云4核8G服务器优惠价格 轻…

设计模式:代理模式

定义 代理模式(Proxy Pattern)是一种结构型设计模式,它为另一个对象提供一个代理或占位符,以控制对这个对象的访问。使用代理模式可以在不改变对象本身的前提下,增加额外的功能,如访问控制、延迟初始化、日志记录、安全检查等。 应用场景 代理模式常见的应用场景包括:…

gradle 7.0 + 配置

Maven 镜像地址的设置 原来在项目根目录的 build.gradle 中进行设置&#xff0c;但是现在里面只有plugins。 工程的build.gradle的dependencies修改为plugins&#xff0c;替代了引用原来的Gradle版本。 // Top-level build file where you can add configuration options com…

【数据结构】——二叉树的递归实现,看完不再害怕递归

创作不易&#xff0c;感谢三连加支持&#xff1f;&#xff01; 一 递归理解 递归无非就是相信它&#xff0c;只有你相信它&#xff0c;你才能写好递归&#xff01;为什么&#xff1f;请往下看 在进入二叉树的实现之前&#xff0c;我们得先理解一遍递归&#xff0c;可能很多…

Android JNI 调用第三方SO

最近一个项目使用了Go 编译了一个so库&#xff0c;但是这个so里面还需要使用第三方so库pdfium, 首先在Android工程把2个so库都放好 在jni中只能使用dlopen方式&#xff0c;其他的使用函数指针的方式来调用&#xff0c;和windows dll类似&#xff0c;不然虽然编译过了但是会崩溃…

基于H2O AutoML与集成学习策略的房屋售价预测模型研究与实现

项目简述&#xff1a; 本项目采用H2O AutoML工具&#xff0c;针对加州房屋销售价格预测问题进行了深入研究与建模。项目以Kaggle提供的加州房屋 交易数据集为基础&#xff0c;通过数据清洗、特征工程、模型训练与评估等步骤&#xff0c;构建了一种基于集成学习策略的房价预测模…

Flink运行机制相关概念介绍

Flink运行机制相关概念介绍 1. 流式计算和批处理2. 流式计算的状态与容错3. Flink简介及其在业务系统中的位置4. Flink模型5. Flink的架构6. Flink的重要概念7. Flink的状态、状态分区、状态缩放&#xff08;rescale&#xff09;和Key Group8. Flink数据交换9. 时间语义10. 水位…

GrayLog日志平台的基本使用-接入jumpserver

1、jumpserver3.8.0部署 Docker 环境准备 # 安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加源 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 替换Docker 安装源为清华大学镜像站 sed -i sh…

Spring Web MVC的入门学习(一)

目录 一、什么是 Spring Web MVC 1、MVC 定义 二、学习Spring MVC 1、项目准备 2、建立连接 2.1 RequestMapping 注解的学习 2.2 RequestMapping 使用 3、请求 3.1 传递单个参数 3.2 传递多个参数 3.3 传递对象 3.4 后端参数重命名&#xff08;后端参数映射&#xf…