自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java編程內(nèi)功-數(shù)據(jù)結(jié)構(gòu)與算法「平衡二叉樹(shù)」

開(kāi)發(fā) 后端 算法
本篇繼續(xù)給大家介紹關(guān)于Java編程的相關(guān)知識(shí),今天主要介紹數(shù)據(jù)結(jié)構(gòu)與算法之平衡二叉樹(shù),希望對(duì)你有所幫助!

[[390860]]

二叉排序樹(shù)可能的問(wèn)題

給定一個(gè)數(shù)列{1,2,3,4,5,6},要求創(chuàng)建一個(gè)二叉排序樹(shù)(BST),分析問(wèn)題所在

問(wèn)題分析:

  1. 左子樹(shù)全部為空,從形式上看,更像一個(gè)單鏈表;
  2. 插入速度沒(méi)有影響;
  3. 查詢速度明顯降低(因?yàn)樾枰淮伪容^),不能發(fā)揮BST的優(yōu)勢(shì)。因?yàn)槊看芜€要比較左子樹(shù),其查詢速度,比單鏈表還慢。
  4. 解決方案-平衡二叉樹(shù)(ALV)

基本介紹

  1. 平衡二叉樹(shù)也叫平衡二叉搜索樹(shù)(Self-balancing binary search tree),又稱為AVL樹(shù),可以保證查詢效率較高。
  2. 具有以下特點(diǎn):它是一顆空樹(shù)或它的左右兩個(gè)子樹(shù)的高度差的絕對(duì)值不超過(guò)1,并且左右兩個(gè)子樹(shù)都是一顆平衡二叉樹(shù)。平衡二叉樹(shù)的常用實(shí)現(xiàn)方法有 紅黑樹(shù)、AVL、替罪羊樹(shù)、Treap、伸展樹(shù)等;
  3. 舉例說(shuō)明,下圖前兩個(gè)都是平衡二叉樹(shù),第一個(gè)左右子樹(shù)的高度差絕對(duì)值是1,第二個(gè)左右子樹(shù)高度差的絕對(duì)值是0,而第三個(gè)的左右子樹(shù)高度差的絕對(duì)值是2,這樣第三個(gè)就不是平衡二叉樹(shù);

平衡二叉樹(shù)之左旋轉(zhuǎn)

步驟

  1. 創(chuàng)建一個(gè)新的節(jié)點(diǎn)newNode,值等于當(dāng)前根節(jié)點(diǎn)的值。
  2. 把新節(jié)點(diǎn)的左子樹(shù)設(shè)置成當(dāng)前節(jié)點(diǎn)的左子樹(shù)。
  3. 把新節(jié)點(diǎn)的右子樹(shù)設(shè)置成當(dāng)前節(jié)點(diǎn)的右子樹(shù)的左子樹(shù)。
  4. 把當(dāng)前節(jié)點(diǎn)的值換為當(dāng)前右子節(jié)點(diǎn)的值。
  5. 把當(dāng)前節(jié)點(diǎn)的右子樹(shù)設(shè)置成右子樹(shù)的右子樹(shù)。
  6. 把當(dāng)前節(jié)點(diǎn)的左子樹(shù)設(shè)置為新的節(jié)點(diǎn)。

平衡二叉樹(shù)之右旋轉(zhuǎn)

步驟:

  1. 創(chuàng)建一個(gè)新的節(jié)點(diǎn),值等于當(dāng)前根的節(jié)點(diǎn)的值。
  2. 把新節(jié)點(diǎn)的右子樹(shù)設(shè)置成當(dāng)前節(jié)點(diǎn)的右子樹(shù)。
  3. 把新節(jié)點(diǎn)的左子樹(shù)設(shè)置成當(dāng)前節(jié)點(diǎn)的左子樹(shù)的右子樹(shù)。
  4. 把當(dāng)前節(jié)點(diǎn)的值換位左子節(jié)點(diǎn)的值。
  5. 把當(dāng)前節(jié)點(diǎn)的左子樹(shù)設(shè)置成左子樹(shù)的左子樹(shù)。
  6. 把當(dāng)前節(jié)點(diǎn)的右子樹(shù)設(shè)置為新的節(jié)點(diǎn)。

平衡二叉樹(shù)之雙旋轉(zhuǎn)

在某些情況下,單旋轉(zhuǎn)不能完成完成平衡二叉樹(shù)的轉(zhuǎn)換,需要進(jìn)行兩次旋轉(zhuǎn)。

  1. 如果它的右子樹(shù)的左子樹(shù)的高度大于它的右子樹(shù)的右子樹(shù)的高度,需要先對(duì)右子樹(shù)進(jìn)行右旋轉(zhuǎn),再對(duì)當(dāng)前節(jié)點(diǎn)進(jìn)行左旋轉(zhuǎn)。
  2. 如果它的左子樹(shù)的右子樹(shù)高度大于它的左子樹(shù)的左子樹(shù)高度,
  3. 需要對(duì)左子樹(shù)先進(jìn)行左旋轉(zhuǎn),再對(duì)當(dāng)前節(jié)點(diǎn)進(jìn)行右旋轉(zhuǎn)。

代碼案例

  1. package com.xie.avl; 
  2.  
  3. public class AVLTreeDemo { 
  4.     public static void main(String[] args) { 
  5.         int[] arr = {4, 3, 6, 5, 7, 8}; 
  6.         AVLTree avlTree = new AVLTree(); 
  7.         for (int i = 0; i < arr.length; i++) { 
  8.             avlTree.add(new Node(arr[i])); 
  9.         } 
  10.         System.out.println("中序遍歷"); 
  11.         avlTree.infixOrder(); 
  12.         System.out.println("在沒(méi)有平衡處理前~~"); 
  13.         System.out.println("樹(shù)的高度=" + avlTree.getRoot().height()); 
  14.         System.out.println("樹(shù)的左子樹(shù)的高度=" + avlTree.getRoot().leftHeight()); 
  15.         System.out.println("樹(shù)的右子樹(shù)的高度=" + avlTree.getRoot().rightHeight()); 
  16.     } 
  17.  
  18. class AVLTree { 
  19.     private Node root; 
  20.  
  21.     public Node getRoot() { 
  22.         return root; 
  23.     } 
  24.  
  25.     public void setRoot(Node root) { 
  26.         this.root = root; 
  27.     } 
  28.  
  29.     //查找要?jiǎng)h除的節(jié)點(diǎn)的父節(jié)點(diǎn) 
  30.     public Node searchParent(Node node) { 
  31.         if (root != null) { 
  32.             return root.searchParent(node); 
  33.         } else { 
  34.             return null
  35.         } 
  36.     } 
  37.  
  38.     //查找要?jiǎng)h除的節(jié)點(diǎn) 
  39.     public Node search(int value) { 
  40.         if (root == null) { 
  41.             return null
  42.         } else { 
  43.             return root.search(value); 
  44.         } 
  45.     } 
  46.  
  47.     /** 
  48.      * 找到以node 根的二叉排序樹(shù)的最小值,并刪除以node 為根節(jié)點(diǎn)的二叉排序樹(shù)的最小節(jié)點(diǎn) 
  49.      * 
  50.      * @param node 傳入節(jié)點(diǎn)(當(dāng)做二叉排序樹(shù)的根節(jié)點(diǎn)) 
  51.      * @return 返回以node為根節(jié)點(diǎn)的二叉排序樹(shù)的最小節(jié)點(diǎn)值 
  52.      */ 
  53.     public int delRightTreeMin(Node node) { 
  54.         Node target = node; 
  55.         //循環(huán)查找左節(jié)點(diǎn) 
  56.         while (target.left != null) { 
  57.             target = target.left
  58.         } 
  59.         //刪除最小節(jié)點(diǎn) 
  60.         delNode(target.value); 
  61.         return target.value; 
  62.     } 
  63.  
  64.     /** 
  65.      * 找到以node 根的二叉排序樹(shù)的最大值,并刪除以node 為根節(jié)點(diǎn)的二叉排序樹(shù)的最大節(jié)點(diǎn) 
  66.      * 
  67.      * @param node 傳入節(jié)點(diǎn)(當(dāng)做二叉排序樹(shù)的根節(jié)點(diǎn)) 
  68.      * @return 返回以node為根節(jié)點(diǎn)的二叉排序樹(shù)的最大節(jié)點(diǎn)值 
  69.      */ 
  70.     public int delLeftTreeMax(Node node) { 
  71.         Node target = node; 
  72.         while (target.right != null) { 
  73.             target = target.right
  74.         } 
  75.  
  76.         //刪除最大節(jié)點(diǎn) 
  77.         delNode(target.value); 
  78.         return target.value; 
  79.     } 
  80.  
  81.     //刪除節(jié)點(diǎn) 
  82.     public void delNode(int value) { 
  83.         if (root == null) { 
  84.             return
  85.         } else { 
  86.             Node targetNode = search(value); 
  87.             if (targetNode == null) { 
  88.                 return
  89.             } 
  90.             if (targetNode == root) { 
  91.                 root = null
  92.                 return
  93.             } 
  94.             Node parentNode = searchParent(targetNode); 
  95.  
  96.             if (targetNode.left == null && targetNode.right == null) { 
  97.                 //如果要?jiǎng)h除的節(jié)點(diǎn)是葉子節(jié)點(diǎn) 
  98.                 if (parentNode.left != null && parentNode.left.value == targetNode.value) { 
  99.                     parentNode.left = null
  100.                 } 
  101.                 if (parentNode.right != null && parentNode.right.value == targetNode.value) { 
  102.                     parentNode.right = null
  103.                 } 
  104.             } else if (targetNode.left != null && targetNode.right != null) { 
  105.                 //如果要?jiǎng)h除的節(jié)點(diǎn)是有兩個(gè)子樹(shù)的節(jié)點(diǎn) 
  106.                 int minValue = delRightTreeMin(targetNode.right); 
  107.                 targetNode.value = minValue; 
  108.                 //上下代碼刪除效果一樣 
  109.                 //int maxValue = delLeftTreeMax(targetNode.left); 
  110.                 //targetNode.value = maxValue; 
  111.             } else { 
  112.                 //要?jiǎng)h除的節(jié)點(diǎn)是只有左子節(jié)點(diǎn) 
  113.                 if (targetNode.left != null) { 
  114.                     if (parentNode != null) { 
  115.                         if (parentNode.left == targetNode) { 
  116.                             parentNode.left = targetNode.left
  117.                         } else { 
  118.                             parentNode.right = targetNode.left
  119.                         } 
  120.                     } else { 
  121.                         //如果父節(jié)點(diǎn)是空,讓root換位 
  122.                         root = targetNode.left
  123.                     } 
  124.                 } else {//要?jiǎng)h除的節(jié)點(diǎn)是只有右子節(jié)點(diǎn) 
  125.                     if (parentNode != null) { 
  126.                         if (parentNode.left == targetNode) { 
  127.                             parentNode.left = targetNode.right
  128.                         } else { 
  129.                             parentNode.right = targetNode.right
  130.                         } 
  131.                     } else { 
  132.                         //如果父節(jié)點(diǎn)是空,讓root換位 
  133.                         root = targetNode.right
  134.                     } 
  135.  
  136.                 } 
  137.             } 
  138.         } 
  139.     } 
  140.  
  141.     //添加節(jié)點(diǎn) 
  142.     public void add(Node node) { 
  143.         if (root == null) { 
  144.             root = node; 
  145.         } else { 
  146.             root.add(node); 
  147.         } 
  148.     } 
  149.  
  150.     //中序遍歷 
  151.     public void infixOrder() { 
  152.         if (root != null) { 
  153.             root.infixOrder(); 
  154.         } else { 
  155.             System.out.println("二叉排序?yàn)榭?,不能遍歷"); 
  156.         } 
  157.     } 
  158.  
  159. class Node { 
  160.     int value; 
  161.     Node left
  162.     Node right
  163.  
  164.     public Node(int value) { 
  165.         this.value = value; 
  166.     } 
  167.  
  168.     /** 
  169.      * 返回左子樹(shù)的高度 
  170.      * 
  171.      * @return 
  172.      */ 
  173.     public int leftHeight() { 
  174.         if (left == null) { 
  175.             return 0; 
  176.         } 
  177.         return left.height(); 
  178.     } 
  179.  
  180.     /** 
  181.      * 返回右子樹(shù)的高度 
  182.      * 
  183.      * @return 
  184.      */ 
  185.     public int rightHeight() { 
  186.         if (this.right == null) { 
  187.             return 0; 
  188.         } 
  189.         return right.height(); 
  190.     } 
  191.  
  192.     /** 
  193.      * 返回以該節(jié)點(diǎn)為根節(jié)點(diǎn)的樹(shù)的高度 
  194.      * 
  195.      * @return 
  196.      */ 
  197.     public int height() { 
  198.         return Math.max(this.left == null ? 0 : this.left.height(), this.right == null ? 0 : this.right.height()) + 1; 
  199.     } 
  200.  
  201.     /** 
  202.      * 左旋轉(zhuǎn) 
  203.      */ 
  204.     public void leftRotate() { 
  205.         //創(chuàng)建新的節(jié)點(diǎn),以當(dāng)前根節(jié)點(diǎn)的值 
  206.         Node newNode = new Node(value); 
  207.         //把新的節(jié)點(diǎn)的左子樹(shù)設(shè)置為當(dāng)前節(jié)點(diǎn)的左子樹(shù) 
  208.         newNode.left = left
  209.         //把新的右子樹(shù)設(shè)置為當(dāng)前節(jié)點(diǎn)的右子樹(shù)的左子樹(shù) 
  210.         newNode.right = right.left
  211.         //把當(dāng)前節(jié)點(diǎn)的值替換成右子節(jié)點(diǎn)的值 
  212.         value = right.value; 
  213.         //把當(dāng)前節(jié)點(diǎn)的右子樹(shù)設(shè)置成當(dāng)前節(jié)點(diǎn)的右子節(jié)點(diǎn)的右子樹(shù) 
  214.         right = right.right
  215.         //把當(dāng)前的節(jié)點(diǎn)的左子節(jié)點(diǎn)(左子樹(shù)),設(shè)置成新的節(jié)點(diǎn) 
  216.         left = newNode; 
  217.     } 
  218.  
  219.     /** 
  220.      * 右旋轉(zhuǎn) 
  221.      */ 
  222.     public void rightRotate() { 
  223.         //創(chuàng)建新的節(jié)點(diǎn),以當(dāng)前根節(jié)點(diǎn)的值 
  224.         Node newNode = new Node(value); 
  225.         //把新的節(jié)點(diǎn)的右子樹(shù)設(shè)置成當(dāng)前節(jié)點(diǎn)的右子樹(shù) 
  226.         newNode.right = right
  227.         //把新的節(jié)點(diǎn)的左子樹(shù)設(shè)置為當(dāng)前節(jié)點(diǎn)左子樹(shù)的右子樹(shù) 
  228.         newNode.left = left.right
  229.         //把當(dāng)前節(jié)點(diǎn)的值換為左子節(jié)點(diǎn)的值 
  230.         value = left.value; 
  231.         //把當(dāng)前節(jié)點(diǎn)左子樹(shù)設(shè)置成左子樹(shù)的左子樹(shù) 
  232.         left = left.left
  233.         //把當(dāng)前節(jié)點(diǎn)的右子樹(shù)設(shè)置新節(jié)點(diǎn) 
  234.         right = newNode; 
  235.     } 
  236.  
  237.     /** 
  238.      * 查找要?jiǎng)h除節(jié)點(diǎn)的父節(jié)點(diǎn) 
  239.      * 
  240.      * @param node 要?jiǎng)h除的節(jié)點(diǎn) 
  241.      * @return 要?jiǎng)h除節(jié)點(diǎn)的父節(jié)點(diǎn) 
  242.      */ 
  243.     public Node searchParent(Node node) { 
  244.         //如果當(dāng)前節(jié)點(diǎn)就是要?jiǎng)h除節(jié)點(diǎn)的父節(jié)點(diǎn)就返回 
  245.         if ((this.left != null && this.left.value == node.value) || 
  246.                 (this.right != null && this.right.value == node.value)) { 
  247.             return this; 
  248.         } else { 
  249.             if (this.left != null && node.value < this.value) { 
  250.                 //如果查找的節(jié)點(diǎn)的值小于當(dāng)前節(jié)點(diǎn)的值,向左子樹(shù)遞歸查找 
  251.                 return this.left.searchParent(node); 
  252.             } else if (this.right != null && value >= this.value) { 
  253.                 //如果查找的節(jié)點(diǎn)的值小于當(dāng)前節(jié)點(diǎn)的值,向左子樹(shù)遞歸查找 
  254.                 return this.right.searchParent(node); 
  255.             } else { 
  256.                 return null
  257.             } 
  258.         } 
  259.     } 
  260.  
  261.     /** 
  262.      * 查找要?jiǎng)h除的節(jié)點(diǎn) 
  263.      * 
  264.      * @param value 要?jiǎng)h除的節(jié)點(diǎn)的值 
  265.      * @return 刪除的節(jié)點(diǎn) 
  266.      */ 
  267.     public Node search(int value) { 
  268.         if (value == this.value) { 
  269.             return this; 
  270.         } else if (value < this.value) { 
  271.             if (this.left != null) { 
  272.                 return this.left.search(value); 
  273.             } else { 
  274.                 return null
  275.             } 
  276.         } else { 
  277.             if (this.right != null) { 
  278.                 return this.right.search(value); 
  279.             } else { 
  280.                 return null
  281.             } 
  282.         } 
  283.     } 
  284.  
  285.     //遞歸的形式添加節(jié)點(diǎn),滿足二叉排序樹(shù)的要求 
  286.     public void add(Node node) { 
  287.         if (node == null) { 
  288.             return
  289.         } 
  290.         if (node.value < this.value) { 
  291.             if (this.left == null) { 
  292.                 this.left = node; 
  293.             } else { 
  294.                 //遞歸向左子樹(shù)添加 
  295.                 this.left.add(node); 
  296.             } 
  297.         } else { 
  298.             if (this.right == null) { 
  299.                 this.right = node; 
  300.             } else { 
  301.                 //遞歸向右子節(jié)點(diǎn)添加 
  302.                 this.right.add(node); 
  303.             } 
  304.         } 
  305.  
  306.         //當(dāng)添加完一個(gè)節(jié)點(diǎn)后,如果(右子樹(shù)高度-左子樹(shù)高度)> 1 ,進(jìn)行左旋轉(zhuǎn) 
  307.         if (rightHeight() - leftHeight() > 1) { 
  308.             //如果它的右子樹(shù)的左子樹(shù)的高度大于它的右子樹(shù)的右子樹(shù)的高度,需要先對(duì)右子樹(shù)進(jìn)行右旋轉(zhuǎn),再對(duì)當(dāng)前節(jié)點(diǎn)進(jìn)行左旋轉(zhuǎn) 
  309.             if(right != null && right.leftHeight()>right.rightHeight()){ 
  310.                 right.rightRotate(); 
  311.                 leftRotate(); 
  312.             }else
  313.                 //直接進(jìn)行左旋轉(zhuǎn)即可 
  314.                 leftRotate(); 
  315.             } 
  316.             return
  317.         } 
  318.  
  319.         //當(dāng)添加完一個(gè)節(jié)點(diǎn)后,如果(左子樹(shù)高度-右子樹(shù)高度)> 1 ,進(jìn)行右旋轉(zhuǎn) 
  320.         if (leftHeight() - rightHeight() > 1) { 
  321.             //如果它的左子樹(shù)的右子樹(shù)高度大于它的左子樹(shù)的左子樹(shù)高度,需要對(duì)左子樹(shù)先進(jìn)行左旋轉(zhuǎn),再對(duì)當(dāng)前節(jié)點(diǎn)進(jìn)行右旋轉(zhuǎn) 
  322.             if(left != null && left.rightHeight() > left.leftHeight()){ 
  323.                 left.leftRotate(); 
  324.                 rightRotate(); 
  325.             }else
  326.                 //直接進(jìn)行右旋轉(zhuǎn)即可 
  327.                 rightRotate(); 
  328.             } 
  329.  
  330.         } 
  331.     } 
  332.  
  333.     //中序遍歷 
  334.     public void infixOrder() { 
  335.         if (this.left != null) { 
  336.             this.left.infixOrder(); 
  337.         } 
  338.         System.out.println(this); 
  339.         if (this.right != null) { 
  340.             this.right.infixOrder(); 
  341.         } 
  342.     } 
  343.  
  344.     @Override 
  345.     public String toString() { 
  346.         return "Node{" + 
  347.                 "value=" + value + 
  348.                 '}'
  349.     } 

 【編輯推薦】

 

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2021-03-19 10:25:12

Java數(shù)據(jù)結(jié)構(gòu)算法

2021-03-22 09:00:22

Java數(shù)據(jù)結(jié)構(gòu)算法

2021-03-29 10:13:47

Java編程數(shù)據(jù)結(jié)構(gòu)算法

2020-11-02 09:15:47

算法與數(shù)據(jù)結(jié)構(gòu)

2021-09-29 10:19:00

算法平衡二叉樹(shù)

2021-03-18 08:44:20

Java數(shù)據(jù)結(jié)構(gòu)算法

2020-09-23 18:25:40

算法二叉樹(shù)多叉樹(shù)

2021-04-19 07:47:42

數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)Tree

2021-04-20 08:37:14

數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)樹(shù)

2021-04-07 09:26:37

Java數(shù)據(jù)結(jié)構(gòu)算法

2021-04-28 20:12:27

數(shù)據(jù)結(jié)構(gòu)創(chuàng)建

2013-01-30 10:34:02

數(shù)據(jù)結(jié)構(gòu)

2021-05-12 09:07:09

Java數(shù)據(jù)結(jié)構(gòu)算法

2021-03-24 10:41:04

Java數(shù)據(jù)結(jié)構(gòu)算法

2021-04-23 09:12:09

Java數(shù)據(jù)結(jié)構(gòu)算法

2023-04-06 07:39:48

2021-04-13 09:37:41

Java數(shù)據(jù)結(jié)構(gòu)算法

2021-03-09 06:30:32

JAVA數(shù)據(jù)結(jié)構(gòu)算法

2021-01-07 08:12:47

數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)樹(shù)

2021-03-26 08:40:28

Java數(shù)據(jù)結(jié)構(gòu)算法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)