【数据结构与算法】二叉搜索树和平衡二叉树

二叉搜索树

左子树的结点都比当前结点小,右子树的结点都比当前结点大。

构造二叉搜索树:

let arr = [3, 4, 7, 5, 2]function Node(value) {this.value = valuethis.left = nullthis.right = null
}/*** 添加结点* @param root 当前结点* @param num 新的结点的值*/
function addNode(root, num) {if (root == null) returnif (root.value == num) returnif (root.value < num) {if (root.right == null) root.right = new Node(num)else addNode(root.right, num)} else {if (root.left == null) root.left = new Node(num)else addNode(root.left, num)}
}function binarySearchTree(arr) {if (arr == null || arr.length == 0) return nulllet root = new Node(arr[0])for (let i = 1; i < arr.length; i++) {addNode(root, arr[i])}return root
}
let root = binarySearchTree(arr)
console.dir(root)

image.png

二叉搜索树的应用:

let arr = [3, 4, 7, 5, 2]function Node(value) {this.value = valuethis.left = nullthis.right = null
}/*** 添加结点* @param root 当前结点* @param num 新的结点的值*/
function addNode(root, num) {if (root == null) returnif (root.value == num) returnif (root.value < num) {if (root.right == null) root.right = new Node(num)else addNode(root.right, num)} else {if (root.left == null) root.left = new Node(num)else addNode(root.left, num)}
}function binarySearchTree(arr) {if (arr == null || arr.length == 0) return nulllet root = new Node(arr[0])for (let i = 1; i < arr.length; i++) {addNode(root, arr[i])}return root
}function searchByTree (root,target) {if (root == null) return falseif (root.value == target) return trueif (root.value > target) return searchByTree(root.left, target)else return searchByTree(root.right, target)
}let root = binarySearchTree(arr)
console.log(searchByTree(root, 4))

平衡二叉树

  • 根节点的左子树和右子树的高度处不能超过1
  • 每棵子树都符合上述规则

image.png

function Node(value) {this.value = valuethis.left = nullthis.right = null
}let a = new Node('a')
let b = new Node('b')
let c = new Node('c')
let d = new Node('d')
let e = new Node('e')
let f = new Node('f')
let g = new Node('g')
let h = new Node('h')
let j = new Node('j')
a.left = b
a.right = c
b.left = d
b.right = e
c.left = f
c.right = g
d.right = h
e.right = jfunction getDeep(root) {if (root == null) return 0let leftDeep = getDeep(root.left)let rightDeep = getDeep(root.right)return Math.max(leftDeep, rightDeep) + 1
}function isBalance(root) {if (root == null) return truelet leftDeep = getDeep(root.left)let rightDeep = getDeep(root.right)if (Math.abs(leftDeep - rightDeep) > 1) {return false} else {return isBalance(root.left) && isBalance(root.right)}
}console.log(getDeep(a))
console.log(isBalance(a))

单旋

某一节点不平衡,如果左边浅,右边深,进行左单旋。

image.png

  • 旋转节点:不平衡的节点为旋转节点(2)
  • 新根:旋转之后称为根节点的节点(5)
  • 变化分支:父级节点发生变化的那个分支
  • 不变分支:父级节点不变的那个分支

左单旋时:

  • 旋转节点:当前不平衡的节点 2
  • 新根:右子树的根节点 5
  • 变化分支:旋转节点的右子树的左子树 3
  • 不变分支:旋转节点的右子树的右子树 6

image.png

右单旋时:

  • 旋转节点:当前不平衡的节点 6
  • 新根:左子树的根节点 3
  • 变化分支:旋转节点的左子树的右子树 5
  • 不变分支:旋转节点的左子树的左子树 2

步骤:

  • 进行左单旋
    1. 找到新根
    1. 找到变化分支
    1. 当前旋转节点的右孩子为变化分支
    1. 新根的左孩子为旋转节点
    1. 返回新的根节点
  • 进行右单旋
    1. 找到新根
    1. 找到变化分支
    1. 当前旋转节点的左孩子为变化分支
    1. 新根的右孩子为旋转节点
    1. 返回新的根节点
function Node(value) {this.value = valuethis.left = nullthis.right = null
}let node2 = new Node('2')
let node5 = new Node('5')
let node3 = new Node('3')
let node6 = new Node('6')
node2.right= node5
node5.left = node3
node5.right = node6function getDeep(root) {if (root == null) return 0let leftDeep = getDeep(root.left)let rightDeep = getDeep(root.right)return Math.max(leftDeep, rightDeep) + 1
}function isBalance(root) {if (root == null) return truelet leftDeep = getDeep(root.left)let rightDeep = getDeep(root.right)if (Math.abs(leftDeep - rightDeep) > 1) {return false} else {return isBalance(root.left) && isBalance(root.right)}
}function leftRotate (root){// 找到新根let newRoot= root.right// 找到变化分支let changeBranch  = root.right.left// 当前旋转接点的右节点变为变化分支root.right = changeBranch// 新根的左节点变为旋转分支newRoot.left = root// 返回新的根节点return newRoot
}
function rightRotate (root){let newRoot = root.leftlet changeBranch = root.left.rightroot.left = changeBranchnewRoot.right = rootreturn newRoot
}/*** 平衡二叉树* @param root 根节点* @returns {*|boolean} 平衡后的根节点*/
function change(root) {if (isBalance(root)) return rootif (root.left != null) root.left = change(root.left)if (root.right != null) root.right = change(root.right)let leftDeep = getDeep(root.left)let rightDeep = getDeep(root.right)if (Math.abs(leftDeep - rightDeep < 2)) {return true} else if (leftDeep > rightDeep) {// 左边深 右旋return rightRotate(root)}  else {// 右边深 左旋return  leftRotate(root)}
}console.log(isBalance(node2))
let newRoot = change(node2)
console.log(isBalance(newRoot))

双旋

有些情况只有一次单选是实现不了的,比如下面的情况:

变化分支(6,7)不可以是唯一的最深分支。

image.png

如果变化分支(6,7)是唯一的最深分支,那么需要先进行依次左旋,再进行右旋。也就是需要双旋。

image.png

二叉树的双旋(左右双旋,右左双旋)

当要对某个节点进行左单旋时,如果变化分支是唯一的最深分支,那么我们要对新根进行右单旋,然后再进行左单旋,这样的旋转叫做右左双旋

当要对某个节点进行右单旋时,如果变化分支是惟一的最深分支,那么我们要对新根进行左单旋,然后再进行右单旋,这样的旋转叫做左右双旋

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

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

相关文章

SpringBoot 登录认证(二)Cookie与Sesstion

SpringBoot 登录认证&#xff08;一&#xff09;-CSDN博客 SpringBoot 登录认证&#xff08;二&#xff09;-CSDN博客 SpringBoot登录校验&#xff08;三&#xff09;-CSDN博客 HTTP是无状态协议 HTTP协议是无状态协议。什么又是无状态的协议&#xff1f; 所谓无状态&…

有Digicert免费证书吗

说到Digiert证书&#xff0c;DigiCert 是美国CA认证可信&#xff0c;提供了很过十年的SSL证书和SSL管理工具。与其他CA不同&#xff0c;DigiCert 完全专注于SSL的创新&#xff0c;提供完整系列的SSL证书、工具和管理平台。它是名副其实的行业单位。 “DigiCert”是这个行业中根…

【JS】打乱数组顺序,用作领域:随机播放音乐

思路 循环数组随机获取数组下标取值&#xff1a; 取当前随机下标数组取当前循环的下标数组 相互替换步骤3的数组 /*** 随机数组顺序* param {Array} arr 数组* returns Array*/ const shufArr arr > {for (let i arr.length - 1; i > 0; i--) {const j Math.floor(M…

Postman和Python Request测试多行Form-data

1、请求参数有多个&#xff0c;F12查看请求体如下&#xff1a; 查看源代码&#xff1a; ------WebKitFormBoundaryHknGXm9VkhRUXZYC Content-Disposition: form-data; name"custId"IICON004 ------WebKitFormBoundaryHknGXm9VkhRUXZYC Content-Disposition: form-da…

企业邮箱给谷歌Gmail报错550-5.7.25解决方案

企业邮箱给谷歌Gmail报错550-5.7.25解决方案 问题表现 今天接到同事报告企业邮箱发送报错的问题&#xff0c;具体问题表现如下&#xff1a; 我司内部邮箱 xxXXX.com 邮箱给国内的163和新浪和企业内部发送邮件可以成功给Hotmail发送邮件&#xff0c;成功。给Gmail发送邮件&am…

IoT数采平台1:开篇

IoT数采平台1&#xff1a;开篇IoT数采平台2&#xff1a;文档IoT数采平台3&#xff1a;功能IoT数采平台4&#xff1a;测试 【功能概述】 开箱即用; 向下接入不同设备(PLC / 采集网关 / OPC / TCP设备 / UDP设备 / HTTP接入),向上通过MQTT发布消息; 数采底层基于NET CORE,既支持P…

Unity与CocosCreator对比学习一

一、屏幕分辨率 1.在creator中设置分辨率 1&#xff09;打开对应场景&#xff1b; 2&#xff09;选中【层级管理器】中的Canvas节点&#xff1b; 3&#xff09;修改【属性检察器】中Canvas组建的属性即可&#xff1b; 2.在Unity中设置屏幕分辨率 1&#xff09;切换到【Game视…

Python学习笔记-Flask接收post请求数据并存储数据库

1.引包 from flask import Flask, request, jsonify from flask_sqlalchemy import SQLAlchemy 2.配置连接,替换为自己的MySQL 数据库的实际用户名、密码和数据库名 app Flask(__name__) #创建应用实列 app.config[SQLALCHEMY_DATABASE_URI] mysqlpymysql://ro…

麒麟Linux安装教程(超详细)

公司要进行信息国产化&#xff0c;要用国产操作系统。公司下载了麒麟Linux&#xff0c;先安装试一下。 和大多数的Linux发行版差不多&#xff0c;支持直接试用而不安装&#xff0c;肯定是要安装的&#xff0c;所有直接选择了第二项“安装银河麒麟操作系统”。 安装主界面logo …

上网行为管理系统推荐,上网行为审计软件推荐

上网行为管理是指帮助互联网用户控制和管理对互联网的使用。它涵盖了多个方面&#xff0c;包括网页访问过滤、上网隐私保护、网络应用控制、带宽流量管理、信息收发审计、用户行为分析等。 上网行为管理产品系列适用于需要实施内容审计与行为监控、行为管理的网络环境&#xf…

弱电工程有哪些系统?一站式解决方案

随着科技的不断进步&#xff0c;现代建筑不仅仅是砖石和水泥的堆砌&#xff0c;它们已经转化为拥有高度智能化的复杂结构。在这些建筑的核心&#xff0c;弱电工程扮演着至关重要的角色。今天&#xff0c;我们将深入探讨弱电工程的各个组成部分以提供的解决方案。 弱电工程涵盖…

OpenHarmony实战:轻量级系统之子系统移植概述

OpenHarmony系统功能按照“系统 > 子系统 > 部件”逐级展开&#xff0c;支持根据实际需求裁剪某些非必要的部件&#xff0c;本文以部分子系统、部件为例进行介绍。若想使用OpenHarmony系统的能力&#xff0c;需要对相应子系统进行适配。 OpenHarmony芯片适配常见子系统列…