Analyse d'un exemple d'arborescence AVL de structure de données Java
L'introduction des arbres AVL
La recherche d'arbres binaires a une efficacité de recherche extrêmement élevée, mais la recherche d'arbres binaires provoquera les situations extrêmes suivantes :
L'efficacité de recherche de ces arbres binaires est encore inférieure à celle des listes chaînées. L'arbre binaire équilibré (arbre AVL) qui apparaît sur la base de l'arbre binaire de recherche résout ce problème. Lorsque la valeur absolue de la différence de hauteur entre les sous-arbres gauche et droit d'un nœud dans un arbre binaire équilibré (arbre AVL) est supérieure à 1, leur différence de hauteur sera réduite grâce à une opération de rotation.
Concept de base
L'arbre AVL est essentiellement un arbre de recherche binaire. Ses caractéristiques sont :
lui-même est avant tout un
arbre de recherche binaire
.二叉搜索树
。每个结点的左右子树的
高度之差的绝对值(平衡因子)最多为1
。也就是说,AVL树,本质上是带了平衡功能
的二叉查找树(二叉排序树,二叉搜索树)。当插入一个节点或者删除一个节点时,导致某一个节点的左右子树高度差的绝对值大于1,这时需要通过
左旋
和右旋
的操作使二叉树再次达到平衡状态。
平衡因子(balanceFactor)
一个结点的左子树与右子树的
高度之差
。AVL树中的任意结点的BF只可能是
-1,0和1。
基础设计
下面是AVL树需要的简单方法和属性:
public class AVLTree <E extends Comparable<E>>{ class Node{ E value; Node left; Node right; int height; public Node(){} public Node(E value){ this.value = value; height = 1; left = null; right = null; } public void display(){ System.out.print(this.value + " "); } } Node root; int size; public int size(){ return size; } public int getHeight(Node node) { if(node == null) return 0; return node.height; } //获取平衡因子(左右子树的高度差,大小为1或者0是平衡的,大小大于1不平衡) public int getBalanceFactor(){ return getBalanceFactor(root); } public int getBalanceFactor(Node node){ if(node == null) return 0; return getHeight(node.left) - getHeight(node.right); } //判断一个树是否是一个平衡二叉树 public boolean isBalance(Node node){ if(node == null) return true; int balanceFactor = Math.abs(getBalanceFactor(node.left) - getBalanceFactor(node.right)); if(balanceFactor > 1) return false; return isBalance(node.left) && isBalance(node.right); } public boolean isBalance(){ return isBalance(root); } //中序遍历树 private void inPrevOrder(Node root){ if(root == null) return; inPrevOrder(root.left); root.display(); inPrevOrder(root.right); } public void inPrevOrder(){ System.out.print("中序遍历:"); inPrevOrder(root); }}
RR(左旋)
往一个树右子树的右子树上插入一个节点,导致二叉树变得不在平衡,如下图,往平衡二叉树中插入5,导致这个树变得不再平衡,此时需要左旋操作,如下:
代码如下:
//左旋,并且返回新的根节点 public Node leftRotate(Node node){ System.out.println("leftRotate"); Node cur = node.right; node.right = cur.left; cur.left = node; //跟新node和cur的高度 node.height = Math.max(getHeight(node.left),getHeight(node.right)) + 1; cur.height = Math.max(getHeight(cur.left),getHeight(cur.right)) + 1; return cur; }
LL(右旋)
往一个AVL树左子树的左子树上插入一个节点,导致二叉树变得不在平衡,如下图,往平衡二叉树中插入2,导致这个树变得不再平衡,此时需要左旋操作,如下:
代码如下:
//右旋,并且返回新的根节点 public Node rightRotate(Node node){ System.out.println("rightRotate"); Node cur = node.left; node.left = cur.right; cur.right = node; //跟新node和cur的高度 node.height = Math.max(getHeight(node.left),getHeight(node.right)) + 1; cur.height = Math.max(getHeight(cur.left),getHeight(cur.right)) + 1; return cur; }
LR(先左旋再右旋)
往AVL树左子树的右子树
上插入一个节点,导致该树不再平衡,需要先对左子树进行左旋
,再对整棵树右旋
,如下图所示,插入节点为5.
RL(先右旋再左旋)
往AVL树右子树的左子树
上插入一个节点,导致该树不再平衡,需要先对右子树进行右旋
,再对整棵树左旋
La valeur absolue (facteur d'équilibre) de la
différence de hauteur entre les sous-arbres gauche et droit de chaque nœud est d'au plus 1
. En d'autres termes, l'arbre AVL est essentiellement un arbre de recherche binaire (arbre de tri binaire, arbre de recherche binaire) avec fonction d'équilibre
.
rotation à gauche
et rotation à droite sont nécessaires. L'opération de rotation permet à l'arbre binaire de retrouver un état d'équilibre. <h3></li></ol></h3><strong>Facteur d'équilibre (balanceFactor)</strong>🎜<ul class=" list-paddingleft-2">🎜🎜Le sous-arbre gauche et le sous-arbre droit d'un nœud< code>Hauteur différence
. 🎜🎜🎜Le BF de n'importe quel nœud de l'arborescence AVL ne peut être que -1, 0 et 1.
🎜🎜Conception de base🎜🎜Voici les méthodes et attributs simples requis par l'arborescence AVL : 🎜//添加元素 public void add(E e){ root = add(root,e); } public Node add(Node node, E value) { if (node == null) { size++; return new Node(value); } if (value.compareTo(node.value) > 0) { node.right = add(node.right, value); } else if (value.compareTo(node.value) < 0) { node.left = add(node.left, value); } //跟新节点高度 node.height = Math.max(getHeight(node.left), getHeight(node.right)) + 1; //获取当前节点的平衡因子 int balanceFactor = getBalanceFactor(node); //该子树不平衡且新插入节点(导致不平衡的节点)在左子树的左子树上,此时需要进行右旋 if (balanceFactor > 1 && getBalanceFactor(node.left) >= 0) { return rightRotate(node); } //该子树不平衡且新插入节点(导致不平衡的节点)在右子树子树的右子树上,此时需要进行左旋 else if (balanceFactor < -1 && getBalanceFactor(node.right) <= 0) { return leftRotate(node); } //该子树不平衡且新插入节点(导致不平衡的节点)在左子树的右子树上,此时需要先对左子树左旋,在整个树右旋 else if (balanceFactor > 1 && getBalanceFactor(node.left) < 0) { node.left = leftRotate(node.left); return rightRotate(node); } //balanceFactor < -1 && getBalanceFactor(node.left) > 0 //该子树不平衡且新插入节点(导致不平衡的节点)在右子树的左子树上,此时需要先对右子树右旋,再整个树左旋 else if(balanceFactor < -1 && getBalanceFactor(node.right) > 0) { node.right = rightRotate(node.right); return leftRotate(node); } return node; }

//删除节点 public E remove(E value){ root = remove(root,value); if(root == null){ return null; } return root.value; } public Node remove(Node node, E value){ Node retNode = null; if(node == null) return retNode; if(value.compareTo(node.value) > 0){ node.right = remove(node.right,value); retNode = node; } else if(value.compareTo(node.value) < 0){ node.left = remove(node.left,value); retNode = node; } //value.compareTo(node.value) = 0 else{ //左右节点都为空,或者左节点为空 if(node.left == null){ size--; retNode = node.right; } //右节点为空 else if(node.right == null){ size--; retNode = node.left; } //左右节点都不为空 else{ Node successor = new Node(); //寻找右子树最小的节点 Node cur = node.right; while(cur.left != null){ cur = cur.left; } successor.value = cur.value; successor.right = remove(node.right,value); successor.left = node.left; node.left = node.right = null; retNode = successor; } if(retNode == null) return null; //维护二叉树平衡 //跟新height retNode.height = Math.max(getHeight(retNode.left),getHeight(retNode.right)); } int balanceFactor = getBalanceFactor(retNode); //该子树不平衡且新插入节点(导致不平衡的节点)在左子树的左子树上,此时需要进行右旋 if (balanceFactor > 1 && getBalanceFactor(retNode.left) >= 0) { return rightRotate(retNode); } //该子树不平衡且新插入节点(导致不平衡的节点)在右子树子树的右子树上,此时需要进行左旋 else if (balanceFactor < -1 && getBalanceFactor(retNode.right) <= 0) { return leftRotate(retNode); } //该子树不平衡且新插入节点(导致不平衡的节点)在左子树的右子树上,此时需要先对左子树左旋,在整个树右旋 else if (balanceFactor > 1 && getBalanceFactor(retNode.left) < 0) { retNode.left = leftRotate(retNode.left); return rightRotate(retNode); } //该子树不平衡且新插入节点(导致不平衡的节点)在右子树的左子树上,此时需要先对右子树右旋,再整个树左旋 else if(balanceFactor < -1 && getBalanceFactor(retNode.right) > 0) { retNode.right = rightRotate(retNode.right); return leftRotate(retNode); } return retNode; }

gauche
de l'arborescence AVL, ce qui entraîne un déséquilibre de l'arbre. Vous devez d'abord effectuer une rotation à gauche sur le sous-arbre gauche
, puis faire pivoter l'arbre entier à droite<.>, comme indiqué dans la figure ci-dessous, insérez le nœud 5.🎜<img src="https://img.php.cn/upload/article/000/465/%20014/168277722832272.jpg" alt="Données Java structure exemple d'analyse de l'arbre AVL">🎜🎜RL (d'abord à droite puis à gauche)🎜🎜Allez au sous-arbre gauche de l'arbre AVL <code>sous-arbre droit
L'insertion d'un nœud provoque le déséquilibre de l'arbre. Vous avez besoin pour faire d'abord pivoter le sous-arbre droit vers la droite
, puis faire pivoter l'arbre entier vers la gauche
Comme le montre la figure ci-dessous, le nœud inséré est 2.🎜🎜🎜. 🎜Ajouter un nœud🎜rrreee🎜Supprimer un nœud🎜rrreeeCe qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Guide de la racine carrée en Java. Nous discutons ici du fonctionnement de Square Root en Java avec un exemple et son implémentation de code respectivement.

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Guide du générateur de nombres aléatoires en Java. Nous discutons ici des fonctions en Java avec des exemples et de deux générateurs différents avec d'autres exemples.

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

Guide de TimeStamp to Date en Java. Ici, nous discutons également de l'introduction et de la façon de convertir l'horodatage en date en Java avec des exemples.
