1. 程式人生 > >資料結構與演算法---線索化二叉樹(Threaded BinaryTree)

資料結構與演算法---線索化二叉樹(Threaded BinaryTree)

先看一個問題

將數列 {1, 3, 6, 8, 10, 14  } 構建成一顆二叉樹

問題分析:

  1. 當我們對上面的二叉樹進行中序遍歷時,數列為 {8, 3, 10, 1, 6, 14 }
  2. 但是 6, 8, 10, 14 這幾個節點的 左右指標,並沒有完全的利用上.
  3. 如果我們希望充分的利用 各個節點的左右指標, 讓各個節點可以指向自己的前後節點,怎麼辦?
  4. 解決方案-線索二叉樹

 線索二叉樹基本介紹

1、n個結點的二叉連結串列中含有n+1  【公式 2n-(n-1)=n+1】 個空指標域。利用二叉連結串列中的空指標域,存放指向該結點在某種遍歷次序下的前驅和後繼結點的指標(這種附加的指標稱為"線索")

2、這種加上了線索的二叉連結串列稱為線索連結串列,相應的二叉樹稱為線索二叉樹(Threaded BinaryTree)。根據線索性質的不同,線索二叉樹可分為前序線索二叉樹、中序線索二叉樹和後序線索二叉樹三種

3、一個結點的前一個結點,稱為前驅結點

4、一個結點的後一個結點,稱為後繼結點

線索二叉樹應用案例

應用案例說明:將下面的二叉樹,進行中序線索二叉樹。中序遍歷的數列為 {8, 3, 10, 1, 14, 6}

思路分析: 中序遍歷的結果:{8, 3, 10, 1, 14, 6}

 

說明: 當線索化二叉樹後,Node節點的 屬性 left 和 right ,有如下情況:

  1. left 指向的是左子樹,也可能是指向的前驅節點. 比如 ① 節點 left 指向的左子樹, 而 ⑩ 節點的 left 指向的就是前驅節點.
  2. right指向的是右子樹,也可能是指向後繼節點,比如 ① 節點right 指向的是右子樹,而⑩ 節點的right 指向的是後繼節點.

程式碼實現:

 1 class BinaryTree {
 2 private HeroNode root;
 3 privateHeroNode pre=null;
 4 public void threadNodes() {
 5 threadNodes(root);
 6 }
 7 public void threadNodes(HeroNode node) {
 8 if(node==null) {
 9 return;
10 }
11 threadNodes(node.getLeft());
12 if(node.getLeft()==null){
13 node.setLeft(pre);
14 node.setLeftType(1);
15 }
16 if(pre!=null&&pre.getRight()==null) {
17 pre.setRight(node);
18 pre.setRightType(1); }
19 pre=node;
20 threadNodes(node.getRight());}}
程式碼
 1 public class BinaryTreeDemo {
 2 public static void main(String[] args) {
 3 BinaryTree binaryTree = new BinaryTree();
 4 HeroNode root = new HeroNode(1, "jack");
 5 HeroNode node1 = new HeroNode(3, "tom");
 6 HeroNode node2 = new HeroNode(6, "mike");
 7 
 8 root.setLeftNode(node1);
 9 root.setRightNode(node2);
10 binaryTree.setRoot(root);
11 
12 HeroNode node3 = new HeroNode(8, "林沖");
13 HeroNode node4 = new HeroNode(10, "關勝");
14 node1.setLeftNode(node3);
15 node1.setRightNode(node4);
16 HeroNode node5 = new HeroNode(14, "jerry");
17 node2.setLeftNode(node5);
18 
19 System.out.println("---中序---");
20 binaryTree.infixOrder();
21 //中序線索化二叉樹
22 binaryTree.threadNodes();
23 
24 HeroNode afterHeroNode10 = node4.getRight();
25 System.out.println(afterHeroNode10);// no=1 name=jack ok了
26 }}
測試

遍歷線索化二叉樹

說明:對前面的中序線索化的二叉樹, 進行遍歷

分析:因為線索化後,各個結點指向有變化,因此原來的遍歷方式不能使用,這時需要使用新的方式遍歷線索化二叉樹,各個節點可以通過線型方式遍歷,因此無需使用遞迴方式,這樣也提高了遍歷的效率。遍歷的次序應當和中序遍歷保持一致。

 1 //遍歷線索化二叉樹的方法
 2     public void threadedList() {
 3         //定義一個變數,儲存當前遍歷的結點,從root開始
 4         HeroNode node = root;
 5         while(node != null) {
 6             //迴圈的找到leftType == 1的結點,第一個找到就是8結點
 7             //後面隨著遍歷而變化,因為當leftType==1時,說明該結點是按照線索化
 8             //處理後的有效結點
 9             while(node.getLeftType() == 0) {
10                 node = node.getLeft();
11             }
12             
13             //列印當前這個結點
14             System.out.println(node);
15             //如果當前結點的右指標指向的是後繼結點,就一直輸出
16             while(node.getRightType() == 1) {
17                 //獲取到當前結點的後繼結點
18                 node = node.getRight();
19                 System.out.println(node);
20             }
21             //替換這個遍歷的結點
22             node = node.getRight();
23             
24         }
25     }
程式碼
 1 public static void main(String[] args) {
 2         //測試一把中序線索二叉樹的功能
 3         HeroNode root = new HeroNode(1, "tom");
 4         HeroNode node2 = new HeroNode(3, "jack");
 5         HeroNode node3 = new HeroNode(6, "smith");
 6         HeroNode node4 = new HeroNode(8, "mary");
 7         HeroNode node5 = new HeroNode(10, "king");
 8         HeroNode node6 = new HeroNode(14, "dim");
 9         
10         //二叉樹,後面我們要遞迴建立, 現在簡單處理使用手動建立
11         root.setLeft(node2);
12         root.setRight(node3);
13         node2.setLeft(node4);
14         node2.setRight(node5);
15         node3.setLeft(node6);
16         
17         //測試中序線索化
18         ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
19         threadedBinaryTree.setRoot(root);
20         threadedBinaryTree.threadedNodes();
21         
22         //測試: 以10號節點測試
23         HeroNode leftNode = node5.getLeft();
24         HeroNode rightNode = node5.getRight();
25         System.out.println("10號結點的前驅結點是 ="  + leftNode); //3
26         System.out.println("10號結點的後繼結點是="  + rightNode); //1
27         
28         //當線索化二叉樹後,能在使用原來的遍歷方法
29         //threadedBinaryTree.infixOrder();
30         System.out.println("使用線索化的方式遍歷 線索化二叉樹");
31         threadedBinaryTree.threadedList(); // 8, 3, 10, 1, 14, 6
32         
33     }
測試

&n