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

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

開發(fā) 后端 算法
本篇繼續(xù)給大家介紹關(guān)于Java編程數(shù)據(jù)結(jié)構(gòu)與算法,今天主要介紹線索化二叉樹的相關(guān)知識。

[[388829]]

先看一個問題

將數(shù)列{1,3,6,8,10,14}構(gòu)建成一顆二叉樹.n+1=7,如下圖所示


問題分析:

  1. 當(dāng)我們對上面的二叉樹進(jìn)行中序遍歷時,數(shù)列為{8,3,10,1,14,6}
  2. 但是6,8,10,14這幾個節(jié)點的左右指針,并沒有完全的利用上。
  3. 如果我們希望充分的利用各個節(jié)點的左右指針,讓各個節(jié)點指向自己的前后節(jié)點怎么辦?
  4. 解決方案-線索二叉樹

線索二叉樹基本介紹

  1. n 個節(jié)點的二叉鏈表中含有n+1【公式 2n-(n-1)=n+1】個空指針域。利用二叉鏈表中的空指針域,存放該節(jié)點在某種遍歷次序下的前驅(qū)和后繼點的指針(這種附加的指針稱為線索)。
  2. 這種加了線索的二叉鏈表稱為線索鏈表,相應(yīng)的二叉樹稱為線索二叉樹(Threaded BinaryTree)。根據(jù)線索的性質(zhì)不同,線索二叉樹可分為前序線索二叉樹、中序線索二叉樹、后序線索二叉樹三種。
  3. 一個節(jié)點的前一個節(jié)點,稱為前驅(qū)節(jié)點。
  4. 一個節(jié)點的后一個節(jié)點,稱為后繼節(jié)點。

中序線索二叉樹圖解


中序遍歷的結(jié)果{8,3,10,1,14,6}

說明:當(dāng)線索化二叉樹后,Node節(jié)點的屬性left和right,有如下情況:

  1. left指向的值左子樹,也可能是指向的前驅(qū)節(jié)點,比如①節(jié)點left指向的左子樹,而⑩節(jié)點的left指向的就是前驅(qū)節(jié)點。
  2. right指向的右子樹,也可能是指向后繼節(jié)點,比如①節(jié)點right指向的是右子樹,而⑩節(jié)點的right指向的是后繼節(jié)點。

代碼案例

  1. package com.xie.tree.threadedbinarytree; 
  2.  
  3. public class ThreadedBinaryTreeDemo { 
  4.     public static void main(String[] args) { 
  5.         //測試中序線索二叉樹 
  6.         HeroNode root = new HeroNode(1, "tom"); 
  7.         HeroNode node2 = new HeroNode(3, "jack"); 
  8.         HeroNode node3 = new HeroNode(6, "smith"); 
  9.         HeroNode node4 = new HeroNode(8, "mary"); 
  10.         HeroNode node5 = new HeroNode(10, "king"); 
  11.         HeroNode node6 = new HeroNode(14, "dim"); 
  12.  
  13.         root.setLeft(node2); 
  14.         root.setRight(node3); 
  15.  
  16.         node2.setLeft(node4); 
  17.         node2.setRight(node5); 
  18.  
  19.         node3.setLeft(node6); 
  20.  
  21.         ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree(); 
  22.         threadedBinaryTree.setRoot(root); 
  23.         threadedBinaryTree.threadedNodes(); 
  24.  
  25.         //測試:以10號節(jié)點測試 
  26.         HeroNode left = node5.getLeft(); 
  27.         System.out.println("10號節(jié)點的前驅(qū)節(jié)點是:" + left); 
  28.         HeroNode right = node5.getRight(); 
  29.         System.out.println("10號節(jié)點的后繼節(jié)點是:" + right); 
  30.  
  31.         System.out.println("使用線索化的方式遍歷 線索二叉樹"); 
  32.         threadedBinaryTree.threadedBinaryTreeList(); 
  33.  
  34.         /** 
  35.          * 10號節(jié)點的前驅(qū)節(jié)點是:HeroNode{no=3, name=jack} 
  36.          * 10號節(jié)點的后繼節(jié)點是:HeroNode{no=1, name=tom} 
  37.          * 使用線索化的方式遍歷 線索二叉樹 
  38.          * HeroNode{no=8, name=mary} 
  39.          * HeroNode{no=3, name=jack} 
  40.          * HeroNode{no=10, name=king} 
  41.          * HeroNode{no=1, name=tom} 
  42.          * HeroNode{no=14, name=dim} 
  43.          * HeroNode{no=6, name=smith} 
  44.          */ 
  45.  
  46.     } 
  47.  
  48. //實現(xiàn)了線索化功能的二叉樹 
  49. class ThreadedBinaryTree { 
  50.     private HeroNode root; 
  51.     //為了實現(xiàn)線索化,需要創(chuàng)建一個指向當(dāng)前節(jié)點的前驅(qū)節(jié)點的指針 
  52.     //在遞歸進(jìn)行線索化時,pre總是保留前一個節(jié)點 
  53.     private HeroNode pre; 
  54.  
  55.     public void setRoot(HeroNode root) { 
  56.         this.root = root; 
  57.     } 
  58.  
  59.     /** 
  60.      * 遍歷線索化二叉樹的方法。 
  61.      */ 
  62.     public void threadedBinaryTreeList() { 
  63.         //定義一個變量,存儲當(dāng)前遍歷的節(jié)點,從root開始 
  64.         HeroNode node = root; 
  65.         while (node != null) { 
  66.             //循環(huán)找到leftType==1的節(jié)點,第一個找到就是8節(jié)點 
  67.             //后面隨著遍歷而變化,因為當(dāng)leftType==1時,說明該節(jié)點是按照線索化處理后的有效節(jié)點 
  68.             while (node.getLeftType() == 0) { 
  69.                 node = node.getLeft(); 
  70.             } 
  71.             //打印當(dāng)前節(jié)點 
  72.             System.out.println(node); 
  73.             //如果當(dāng)前節(jié)點的右指針指向的是后繼節(jié)點,就一直輸出 
  74.             while (node.getRightType() == 1) { 
  75.                 //獲取到當(dāng)前節(jié)點的后繼節(jié)點 
  76.                 node = node.getRight(); 
  77.                 System.out.println(node); 
  78.             } 
  79.             //替換這個遍歷的節(jié)點 
  80.             node = node.getRight(); 
  81.         } 
  82.     } 
  83.  
  84.     /** 
  85.      * 重載threadedNodes方法 
  86.      */ 
  87.     public void threadedNodes() { 
  88.         threadedNodes(root); 
  89.     } 
  90.  
  91.     /** 
  92.      * 編寫對二叉樹進(jìn)行線索化的方法 
  93.      * 
  94.      * @param node 當(dāng)前需要線索化的節(jié)點 
  95.      */ 
  96.     public void threadedNodes(HeroNode node) { 
  97.         if (node == null) { 
  98.             return
  99.         } 
  100.  
  101.         //先線索化左子樹 
  102.         threadedNodes(node.getLeft()); 
  103.         //線索化當(dāng)前節(jié)點【有難度】 
  104.  
  105.         //處理當(dāng)前節(jié)點的前驅(qū)節(jié)點 
  106.         //以8節(jié)點來理解,8節(jié)點.left=null 
  107.         if (node.getLeft() == null) { 
  108.             //讓當(dāng)前節(jié)點的左指針指向前驅(qū)節(jié)點 
  109.             node.setLeft(pre); 
  110.             //修改當(dāng)前節(jié)點的左指針類型 
  111.             node.setLeftType(1); 
  112.         } 
  113.  
  114.         //處理后繼節(jié)點 
  115.         if (pre != null && pre.getRight() == null) { 
  116.             //讓前驅(qū)節(jié)點的右指針指向當(dāng)前節(jié)點 
  117.             pre.setRight(node); 
  118.             //修改前驅(qū)節(jié)點的右指針類型 
  119.             pre.setRightType(1); 
  120.         } 
  121.         //每處理一個節(jié)點后,讓當(dāng)前節(jié)點是下一個節(jié)點的前驅(qū)節(jié)點 
  122.         pre = node; 
  123.  
  124.         //再線索化右子樹 
  125.         threadedNodes(node.getRight()); 
  126.     } 
  127.  
  128.  
  129. //創(chuàng)建HeroNode節(jié)點 
  130. class HeroNode { 
  131.     static int preCount = 0; 
  132.     static int infoxCount = 0; 
  133.     static int postCount = 0; 
  134.  
  135.     private int no
  136.     private String name
  137.     private HeroNode left
  138.     private HeroNode right
  139.  
  140.     //0 表示指向的是左子樹,1 表示指向的是前驅(qū)節(jié)點 
  141.     private int leftType; 
  142.     //0 表示指向右子樹,1 表示指向的是后繼節(jié)點 
  143.     private int rightType; 
  144.  
  145.     public HeroNode(int no, String name) { 
  146.         this.no = no
  147.         this.name = name
  148.     } 
  149.  
  150.     public int getNo() { 
  151.         return no
  152.     } 
  153.  
  154.     public void setNo(int no) { 
  155.         this.no = no
  156.     } 
  157.  
  158.     public String getName() { 
  159.         return name
  160.     } 
  161.  
  162.     public void setName(String name) { 
  163.         this.name = name
  164.     } 
  165.  
  166.     public HeroNode getLeft() { 
  167.         return left
  168.     } 
  169.  
  170.     public void setLeft(HeroNode left) { 
  171.         this.left = left
  172.     } 
  173.  
  174.     public HeroNode getRight() { 
  175.         return right
  176.     } 
  177.  
  178.     public void setRight(HeroNode right) { 
  179.         this.right = right
  180.     } 
  181.  
  182.     public int getLeftType() { 
  183.         return leftType; 
  184.     } 
  185.  
  186.     public void setLeftType(int leftType) { 
  187.         this.leftType = leftType; 
  188.     } 
  189.  
  190.     public int getRightType() { 
  191.         return rightType; 
  192.     } 
  193.  
  194.     public void setRightType(int rightType) { 
  195.         this.rightType = rightType; 
  196.     } 
  197.  
  198.     @Override 
  199.     public String toString() { 
  200.         return "HeroNode{" + 
  201.                 "no=" + no + 
  202.                 ", name=" + name + 
  203.                 '}'
  204.     } 
  205.  
  206.     //前序遍歷 
  207.     public void preOrder() { 
  208.         System.out.println(this); 
  209.         //遞歸向左子樹前序遍歷 
  210.         if (this.left != null) { 
  211.             this.left.preOrder(); 
  212.         } 
  213.  
  214.         //遞歸向右子樹前序遍歷 
  215.         if (this.right != null) { 
  216.             this.right.preOrder(); 
  217.         } 
  218.     } 
  219.  
  220.     //中序遍歷 
  221.     public void infixOrder() { 
  222.         //遞歸向左子樹中序遍歷 
  223.         if (this.left != null) { 
  224.             this.left.infixOrder(); 
  225.         } 
  226.         System.out.println(this); 
  227.         //遞歸向右子樹中序遍歷 
  228.         if (this.right != null) { 
  229.             this.right.infixOrder(); 
  230.         } 
  231.     } 
  232.  
  233.     //后序遍歷 
  234.     public void postOrder() { 
  235.         //遞歸向左子樹后序遍歷 
  236.         if (this.left != null) { 
  237.             this.left.postOrder(); 
  238.         } 
  239.         //遞歸向右子樹后序遍歷 
  240.         if (this.right != null) { 
  241.             this.right.postOrder(); 
  242.         } 
  243.         System.out.println(this); 
  244.     } 
  245.  
  246.     //遞歸刪除節(jié)點 
  247.     //1.如果刪除的節(jié)點是葉子節(jié)點,則刪除該節(jié)點。 
  248.     //2.如果刪除的節(jié)點是非葉子節(jié)點,則刪除該樹。 
  249.     public void delNo(int no) { 
  250.         /** 
  251.          * 1.因為我們的二叉樹是單向的,所以我們是判斷當(dāng)前節(jié)點的子節(jié)點是否是需要刪除的節(jié)點,而不能去判斷當(dāng)前節(jié)點是否是需要刪除的節(jié)點。 
  252.          * 2.如果當(dāng)前節(jié)點的左子節(jié)點不為空,并且左子節(jié)點就是需要刪除的節(jié)點,就將this.left = null;并且返回(結(jié)束遞歸)。 
  253.          * 3.如果當(dāng)前節(jié)點的右子節(jié)點不為空,并且右子節(jié)點就是需要刪除的節(jié)點,將將this.right = null;并且返回(結(jié)束遞歸)。 
  254.          * 4.如果第2步和第3步?jīng)]有刪除節(jié)點,那么就要向左子樹進(jìn)行遞歸刪除。 
  255.          * 5.如果第4步也沒有刪除節(jié)點,則應(yīng)當(dāng)向右子樹進(jìn)行遞歸刪除。 
  256.          */ 
  257.         if (this.left != null && this.left.no == no) { 
  258.             this.left = null
  259.             return
  260.         } 
  261.  
  262.         if (this.right != null && this.right.no == no) { 
  263.             this.right = null
  264.             return
  265.         } 
  266.  
  267.         if (this.left != null) { 
  268.             this.left.delNo(no); 
  269.         } 
  270.  
  271.         if (this.right != null) { 
  272.             this.right.delNo(no); 
  273.         } 
  274.  
  275.     } 
  276.  
  277.     //前序遍歷查找 
  278.     public HeroNode preOrderSearch(int no) { 
  279.  
  280.         HeroNode res = null
  281.  
  282.         preCount++;//這里必須放在this.no == no 判斷之前,才進(jìn)行實際的比較 
  283.         //若果找到,就返回 
  284.         if (this.no == no) { 
  285.             return this; 
  286.         } 
  287.         //沒有找到,向左子樹遞歸進(jìn)行前序查找 
  288.         if (this.left != null) { 
  289.             res = this.left.preOrderSearch(no); 
  290.         } 
  291.         //如果res != null 就直接返回 
  292.         if (res != null) { 
  293.             return res; 
  294.         } 
  295.         //如果左子樹沒有找打,向右子樹進(jìn)行前序查找 
  296.         if (this.right != null) { 
  297.             res = this.right.preOrderSearch(no); 
  298.         } 
  299.         //如果找到就返回 
  300.         if (res != null) { 
  301.             return res; 
  302.         } 
  303.         return res; 
  304.     } 
  305.  
  306.     //中序遍歷查找 
  307.     public HeroNode infixOrderSearch(int no) { 
  308.  
  309.         HeroNode res = null
  310.         if (this.left != null) { 
  311.             res = this.left.infixOrderSearch(no); 
  312.         } 
  313.         if (res != null) { 
  314.             return res; 
  315.         } 
  316.         infoxCount++;//這里必須放在this.no == no 判斷之前,才進(jìn)行實際的比較 
  317.         if (this.no == no) { 
  318.             return this; 
  319.         } 
  320.         if (this.right != null) { 
  321.             res = this.right.infixOrderSearch(no); 
  322.         } 
  323.         if (res != null) { 
  324.             return res; 
  325.         } 
  326.         return res; 
  327.     } 
  328.  
  329.     //后序遍歷查找 
  330.     public HeroNode postOrderSearch(int no) { 
  331.  
  332.         HeroNode res = null
  333.         if (this.left != null) { 
  334.             res = this.left.postOrderSearch(no); 
  335.         } 
  336.         if (res != null) { 
  337.             return res; 
  338.         } 
  339.  
  340.         if (this.right != null) { 
  341.             res = this.right.postOrderSearch(no); 
  342.         } 
  343.         if (res != null) { 
  344.             return res; 
  345.         } 
  346.         postCount++;//這里必須放在this.no == no 判斷之前,才進(jìn)行實際的比較 
  347.         if (this.no == no) { 
  348.             return this; 
  349.         } 
  350.         return res; 
  351.     } 

 【編輯推薦】

 

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

2021-03-19 10:25:12

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

2021-04-01 10:34:18

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

2021-04-28 20:12:27

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

2021-03-29 10:13:47

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

2020-11-02 09:15:47

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

2021-03-18 08:44:20

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

2020-09-23 18:25:40

算法二叉樹多叉樹

2021-04-19 07:47:42

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

2021-04-20 08:37:14

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

2021-04-07 09:26:37

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

2021-03-24 10:41:04

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

2013-01-30 10:34:02

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

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-05-12 09:07:09

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-01-07 08:12:47

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

2021-03-17 09:27:36

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

2021-03-10 08:42:19

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

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