Java中二叉樹存儲結構實現


一、二叉樹

二叉樹指的是每個節點最多只能有兩個子樹的有序樹。通常左邊的子樹被稱為“左子樹”(left subtree),右邊的子樹被稱為右子樹。

二叉樹的每個節點最多只有2棵子樹,二叉樹的子樹次序不能顛倒。

二、順序存儲二叉樹的實現

  1 package com.ietree.basic.datastructure.tree.binarytree;
  2 
  3 /**
  4  * Created by ietree
  5  * 2017/5/1
  6  */
  7 public class ArrayBinTree<T> {
  8 
  9     // 使用數組來記錄該樹的所有節點
 10     private Object[] datas;
 11     private int DEFAULT_DEEP = 8;
 12     // 保存該樹的深度
 13     private int deep;
 14     private int arraySize;
 15 
 16     // 以默認的深度創建二叉樹
 17     public ArrayBinTree() {
 18         this.deep = DEFAULT_DEEP;
 19         this.arraySize = (int) (Math.pow(2, deep) - 1);
 20         datas = new Object[arraySize];
 21     }
 22 
 23     // 以指定深度創建二叉樹
 24     public ArrayBinTree(int deep) {
 25         this.deep = deep;
 26         this.arraySize = (int) Math.pow(2, deep) - 1;
 27         datas = new Object[arraySize];
 28     }
 29 
 30     // 以指定深度、指定節點創建二叉樹
 31     public ArrayBinTree(int deep, T data) {
 32         this.deep = deep;
 33         this.arraySize = (int) Math.pow(2, deep) - 1;
 34         datas = new Object[arraySize];
 35         datas[0] = data;
 36     }
 37 
 38     /**
 39      * 為指定節點添加子節點
 40      *
 41      * @param index 需要添加子節點的父節點的索引
 42      * @param data  新子節點的數據
 43      * @param left  是否為左節點
 44      */
 45     public void add(int index, T data, boolean left) {
 46         if (datas[index] == null) {
 47             throw new RuntimeException(index + "處節點為空,無法添加子節點");
 48         }
 49         if (2 * index + 1 >= arraySize) {
 50             throw new RuntimeException("樹底層的數組已滿,樹越界異常");
 51         }
 52         // 添加左子節點
 53         if (left) {
 54             datas[2 * index + 1] = data;
 55         } else {
 56             datas[2 * index + 2] = data;
 57         }
 58     }
 59 
 60     // 判斷二叉樹是否為空
 61     public boolean empty() {
 62         // 根據根元素判斷二叉樹是否為空
 63         return datas[0] == null;
 64     }
 65 
 66     // 返回根節點
 67     public T root() {
 68         return (T) datas[0];
 69     }
 70 
 71     // 返回指定節點(非根結點)的父節點
 72     public T parent(int index) {
 73         return (T) datas[(index - 1) / 2];
 74     }
 75 
 76     // 返回指定節點(非葉子)的左子節點,當左子節點不存在時返回null
 77     public T left(int index) {
 78         if (2 * index + 1 >= arraySize) {
 79             throw new RuntimeException("該節點為葉子節點,無子節點");
 80         }
 81         return (T) datas[index * 2 + 1];
 82     }
 83 
 84     // 返回指定節點(非葉子)的右子節點,當右子節點不存在時返回null
 85     public T right(int index) {
 86         if (2 * index + 1 >= arraySize) {
 87             throw new RuntimeException("該節點為葉子節點,無子節點");
 88         }
 89         return (T) datas[index * 2 + 2];
 90     }
 91 
 92     // 返回該二叉樹的深度
 93     public int deep(int index) {
 94         return deep;
 95     }
 96 
 97     // 返回指定節點的位置
 98     public int pos(T data) {
 99         // 該循環實際上就是按廣度遍歷來搜索每個節點
100         for (int i = 0; i < arraySize; i++) {
101             if (datas[i].equals(data)) {
102                 return i;
103             }
104 
105         }
106         return -1;
107     }
108 
109     public String toString() {
110         return java.util.Arrays.toString(datas);
111     }
112 
113 }

測試類:

 1 package com.ietree.basic.datastructure.tree.binarytree;
 2 
 3 /**
 4  * Created by ietree
 5  * 2017/5/1
 6  */
 7 public class ArrayBinTreeTest {
 8 
 9     public static void main(String[] args) {
10 
11         ArrayBinTree<String> binTree = new ArrayBinTree<String>(4, "根");
12         binTree.add(0, "第二層右子節點", false);
13         binTree.add(2, "第三層右子節點", false);
14         binTree.add(6, "第四層右子節點", false);
15         System.out.println(binTree);
16         
17     }
18 
19 }

程序輸出:

[根, null, 第二層右子節點, null, null, null, 第三層右子節點, null, null, null, null, null, null, null, 第四層右子節點]

三、二叉樹的二叉鏈表存儲

 二叉鏈表存儲的思想是讓每個節點都能“記住”它的左、右兩個子節點。為每個節點增加left、right兩個指針,分別引用該節點的左、右兩個子節點。

  1 package com.ietree.basic.datastructure.tree.binarytree;
  2 
  3 /**
  4  * Created by ietree
  5  * 2017/5/1
  6  */
  7 public class TwoLinkBinTree<E> {
  8 
  9     public static class TreeNode {
 10 
 11         Object data;
 12         TreeNode left;
 13         TreeNode right;
 14 
 15         public TreeNode() {
 16 
 17         }
 18 
 19         public TreeNode(Object data) {
 20             this.data = data;
 21         }
 22 
 23         public TreeNode(Object data, TreeNode left, TreeNode right) {
 24             this.data = data;
 25             this.left = left;
 26             this.right = right;
 27         }
 28 
 29     }
 30 
 31     private TreeNode root;
 32 
 33     // 以默認的構造器創建二叉樹
 34     public TwoLinkBinTree() {
 35         this.root = new TreeNode();
 36     }
 37 
 38     // 以指定根元素創建二叉樹
 39     public TwoLinkBinTree(E data) {
 40         this.root = new TreeNode(data);
 41     }
 42 
 43     /**
 44      * 為指定節點添加子節點
 45      *
 46      * @param parent 需要添加子節點的父節點的索引
 47      * @param data   新子節點的數據
 48      * @param isLeft 是否為左節點
 49      * @return 新增的節點
 50      */
 51     public TreeNode addNode(TreeNode parent, E data, boolean isLeft) {
 52 
 53         if (parent == null) {
 54             throw new RuntimeException(parent + "節點為null, 無法添加子節點");
 55         }
 56         if (isLeft && parent.left != null) {
 57             throw new RuntimeException(parent + "節點已有左子節點,無法添加左子節點");
 58         }
 59         if (!isLeft && parent.right != null) {
 60             throw new RuntimeException(parent + "節點已有右子節點,無法添加右子節點");
 61         }
 62 
 63         TreeNode newNode = new TreeNode(data);
 64         if (isLeft) {
 65             // 讓父節點的left引用指向新節點
 66             parent.left = newNode;
 67         } else {
 68             // 讓父節點的left引用指向新節點
 69             parent.right = newNode;
 70         }
 71         return newNode;
 72     }
 73 
 74     // 判斷二叉樹是否為空
 75     public boolean empty() {
 76         // 根據元素判斷二叉樹是否為空
 77         return root.data == null;
 78     }
 79 
 80     // 返回根節點
 81     public TreeNode root() {
 82         if (empty()) {
 83             throw new RuntimeException("樹為空,無法訪問根節點");
 84         }
 85         return root;
 86     }
 87 
 88     // 返回指定節點(非根節點)的父節點
 89     public E parent(TreeNode node) {
 90         // 對於二叉樹鏈表存儲法,如果要訪問指定節點的父節點必須遍歷二叉樹
 91         return null;
 92     }
 93 
 94     // 返回指定節點(非葉子)的左子節點,當左子節點不存在時返回null
 95     public E leftChild(TreeNode parent) {
 96         if (parent == null) {
 97             throw new RuntimeException(parent + "節點為null,無法添加子節點");
 98         }
 99         return parent.left == null ? null : (E) parent.left.data;
100     }
101 
102     // 返回指定節點(非葉子)的右子節點,當右子節點不存在時返回null
103     public E rightChild(TreeNode parent) {
104         if (parent == null) {
105             throw new RuntimeException(parent + "節點為null,無法添加子節點");
106         }
107         return parent.right == null ? null : (E) parent.right.data;
108     }
109 
110     // 返回該二叉樹的深度
111     public int deep() {
112         // 獲取該樹的深度
113         return deep(root);
114     }
115 
116     // 這是一個遞歸方法:每一棵子樹的深度為其所有子樹的最大深度 + 1
117     private int deep(TreeNode node) {
118         if (node == null) {
119             return 0;
120         }
121         // 沒有子樹
122         if (node.left == null && node.right == null) {
123             return 1;
124         } else {
125             int leftDeep = deep(node.left);
126             int rightDeep = deep(node.right);
127             // 記錄其所有左、右子樹中較大的深度
128             int max = leftDeep > rightDeep ? leftDeep : rightDeep;
129             // 返回其左右子樹中較大的深度 + 1
130             return max + 1;
131         }
132 
133     }
134 
135 }

測試類:

 1 package com.ietree.basic.datastructure.tree.binarytree;
 2 
 3 /**
 4  * Created by ietree
 5  * 2017/5/1
 6  */
 7 public class TwoLinkBinTreeTest {
 8 
 9     public static void main(String[] args) {
10 
11         TwoLinkBinTree<String> binTree = new TwoLinkBinTree<String>("根節點");
12         // 依次添加節點
13         TwoLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二層左節點", true);
14         TwoLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二層右節點", false);
15         TwoLinkBinTree.TreeNode tn3 = binTree.addNode(tn2, "第三層左節點", true);
16         TwoLinkBinTree.TreeNode tn4 = binTree.addNode(tn2, "第三層右節點", false);
17         TwoLinkBinTree.TreeNode tn5 = binTree.addNode(tn3, "第四層左節點", true);
18 
19         System.out.println("tn2的左子節點:" + binTree.leftChild(tn2));
20         System.out.println("tn2的右子節點:" + binTree.rightChild(tn2));
21         System.out.println(binTree.deep());
22 
23     }
24 
25 }

程序輸出:

tn2的左子節點:第三層左節點
tn2的右子節點:第三層右節點
4

四、二叉樹的三叉鏈表存儲

 三叉鏈表存儲方式是對二叉鏈表的一種改進,通過為樹節點增加一個parent引用,可以讓每個節點都能非常方便的訪問其父節點,三叉鏈表存儲的二叉樹即可方便地向下訪問節點,也可方便地向上訪問節點。

  1 package com.ietree.basic.datastructure.tree.binarytree;
  2 
  3 /**
  4  * Created by ietree
  5  * 2017/5/1
  6  */
  7 public class ThreeLinkBinTree<E> {
  8 
  9     public static class TreeNode {
 10 
 11         Object data;
 12         TreeNode left;
 13         TreeNode right;
 14         TreeNode parent;
 15 
 16         public TreeNode() {
 17 
 18         }
 19 
 20         public TreeNode(Object data) {
 21             this.data = data;
 22         }
 23 
 24         public TreeNode(Object data, TreeNode left, TreeNode right, TreeNode parent) {
 25             this.data = data;
 26             this.left = left;
 27             this.right = right;
 28             this.parent = parent;
 29         }
 30 
 31     }
 32 
 33     private TreeNode root;
 34 
 35     // 以默認的構造器創建二叉樹
 36     public ThreeLinkBinTree() {
 37         this.root = new TreeNode();
 38     }
 39 
 40     // 以指定根元素創建二叉樹
 41     public ThreeLinkBinTree(E data) {
 42         this.root = new TreeNode(data);
 43     }
 44 
 45     /**
 46      * 為指定節點添加子節點
 47      *
 48      * @param parent 需要添加子節點的父節點的索引
 49      * @param data   新子節點的數據
 50      * @param isLeft 是否為左節點
 51      * @return 新增的節點
 52      */
 53     public TreeNode addNode(TreeNode parent, E data, boolean isLeft) {
 54 
 55         if (parent == null) {
 56             throw new RuntimeException(parent + "節點為null, 無法添加子節點");
 57         }
 58         if (isLeft && parent.left != null) {
 59             throw new RuntimeException(parent + "節點已有左子節點,無法添加左子節點");
 60         }
 61         if (!isLeft && parent.right != null) {
 62             throw new RuntimeException(parent + "節點已有右子節點,無法添加右子節點");
 63         }
 64 
 65         TreeNode newNode = new TreeNode(data);
 66         if (isLeft) {
 67             // 讓父節點的left引用指向新節點
 68             parent.left = newNode;
 69         } else {
 70             // 讓父節點的left引用指向新節點
 71             parent.right = newNode;
 72         }
 73         // 讓新節點的parent引用到parent節點
 74         newNode.parent = parent;
 75         return newNode;
 76     }
 77 
 78     // 判斷二叉樹是否為空
 79     public boolean empty() {
 80         // 根據元素判斷二叉樹是否為空
 81         return root.data == null;
 82     }
 83 
 84     // 返回根節點
 85     public TreeNode root() {
 86         if (empty()) {
 87             throw new RuntimeException("樹為空,無法訪問根節點");
 88         }
 89         return root;
 90     }
 91 
 92     // 返回指定節點(非根節點)的父節點
 93     public E parent(TreeNode node) {
 94         if (node == null) {
 95             throw new RuntimeException("節點為null,無法訪問其父節點");
 96         }
 97         return (E) node.parent.data;
 98     }
 99 
100     // 返回指定節點(非葉子)的左子節點,當左子節點不存在時返回null
101     public E leftChild(TreeNode parent) {
102         if (parent == null) {
103             throw new RuntimeException(parent + "節點為null,無法添加子節點");
104         }
105         return parent.left == null ? null : (E) parent.left.data;
106     }
107 
108     // 返回指定節點(非葉子)的右子節點,當右子節點不存在時返回null
109     public E rightChild(TreeNode parent) {
110         if (parent == null) {
111             throw new RuntimeException(parent + "節點為null,無法添加子節點");
112         }
113         return parent.right == null ? null : (E) parent.right.data;
114     }
115 
116     // 返回該二叉樹的深度
117     public int deep() {
118         // 獲取該樹的深度
119         return deep(root);
120     }
121 
122     // 這是一個遞歸方法:每一棵子樹的深度為其所有子樹的最大深度 + 1
123     private int deep(TreeNode node) {
124         if (node == null) {
125             return 0;
126         }
127         // 沒有子樹
128         if (node.left == null && node.right == null) {
129             return 1;
130         } else {
131             int leftDeep = deep(node.left);
132             int rightDeep = deep(node.right);
133             // 記錄其所有左、右子樹中較大的深度
134             int max = leftDeep > rightDeep ? leftDeep : rightDeep;
135             // 返回其左右子樹中較大的深度 + 1
136             return max + 1;
137         }
138 
139     }
140 
141 }

測試類:

 1 package com.ietree.basic.datastructure.tree.binarytree;
 2 
 3 /**
 4  * Created by ietree
 5  * 2017/5/1
 6  */
 7 public class ThreeLinkBinTreeTest {
 8 
 9     public static void main(String[] args) {
10 
11         ThreeLinkBinTree<String> binTree = new ThreeLinkBinTree<String>("根節點");
12         // 依次添加節點
13         ThreeLinkBinTree.TreeNode tn1 = binTree.addNode(binTree.root(), "第二層左節點", true);
14         ThreeLinkBinTree.TreeNode tn2 = binTree.addNode(binTree.root(), "第二層右節點", false);
15         ThreeLinkBinTree.TreeNode tn3 = binTree.addNode(tn2, "第三層左節點", true);
16         ThreeLinkBinTree.TreeNode tn4 = binTree.addNode(tn2, "第三層右節點", false);
17         ThreeLinkBinTree.TreeNode tn5 = binTree.addNode(tn3, "第四層左節點", true);
18 
19         System.out.println("tn2的左子節點:" + binTree.leftChild(tn2));
20         System.out.println("tn2的右子節點:" + binTree.rightChild(tn2));
21         System.out.println(binTree.deep());
22 
23     }
24 
25 }

程序輸出:

tn2的左子節點:第三層左節點
tn2的右子節點:第三層右節點
4

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM