java数据结构——二叉树(BinaryTree)

前面我们已经学习了一些线性结构的数据结构和算法,接下来我们开始学习非线性结构的内容。

二叉树

前面显示增、删、查、遍历方法,完整代码在最后面。

/**
 * 为什么我们要学习树结构。
 * 1、有序数组插入数据项和删除数据项太慢。
 * 2、链表查找数据太慢。
 * 3、在树中能非常快速的查找、插入、删除数据,结合了有序数组和链表的优点
 * 4、暂时还不知道
 */

结点打包类

 1 public class BinaryTree {
 2     //数据项(对象什么都可以)
 3     public long data;    
 4     //左孩子
 5     public BinaryTree leftChiled;    
 6     //右孩子
 7     public BinaryTree rightChiled;
 8     
 9     public BinaryTree(int value) {
10         this.data = value;
11     }
12     
13 }

 

 1 public void add(int value) {
 2         // 封装结点
 3         BinaryTree newnode = new BinaryTree(value);
 4 
 5         BinaryTree parent;// 引用父节点
 6 
 7         BinaryTree current = root;// current引用根结点
 8 
 9         if (root == null) {// 如果root为null,也就是第一次插入
10             root = newnode;
11             return;
12         } else {
13             while (true) {
14 
15                 parent = current;// 父节点指向指向当前节点,保存上一个结点
16                 if (current.data > value) {
17                     current = current.leftChiled;
18                     if (current == null) {
19                         parent.leftChiled = newnode;
20                         return;
21                     }
22                 } else {
23                     current = current.rightChiled;
24 
25                     if (current == null) {
26                         parent.rightChiled = newnode;
27                         return;
28                     }
29                 }
30 
31             }
32         }
33     }
添加方法
 

一、删除节点是二叉树操作中最复杂的。在删除之前首先要查找要删的节点。找到节点后,这个要删除的节点可能会有三种情况需要考虑。

1.该节点是叶子节点,没有子节点。
要删除叶节点,只需要改变该节点的父节点的引用值,将指向该节点的引用设置为null就可以了。
2.该节点有一个子节点。
改变父节点的引用,将其直接指向要删除节点的子节点。
3.该节点有两个子节点。
要删除有两个子节点的节点,就需要使用它的中序后继来替代该节点。
费我九牛二虎之力还是给整出来了。
 

 

 1 public boolean delete(long value) {// 删除
 2         BinaryTree current = root;// current保存根结点
 3         BinaryTree parent = root;// parent保存parent的父节点
 4         boolean isLeftchild = true;
 5         while (current.data != value) {
 6             parent = current;
 7             // 进行比较,比较当前值和查找值的大小
 8             if (current.data > value) {
 9                 current = current.leftChiled;
10                 isLeftchild = true;// true为左子树
11             } else {
12                 current = current.rightChiled;
13                 isLeftchild = false;
14             }
15             if (current == null) {
16                 return false;
17             }
18         }
19         if (current.leftChiled == null && current.rightChiled == null) {// 第1种情况
20             if (isLeftchild) {
21                 parent.leftChiled = null;
22             } else {
23                 parent.rightChiled = null;
24             }
25         } else if (current.rightChiled == null) {// 第2种情况
26             if (current == root) {
27                 root = current.leftChiled;
28             } else if (isLeftchild) {
29                 parent.leftChiled = current.leftChiled;
30             } else {
31                 parent.rightChiled = current.leftChiled;
32             }
33         } else if (current.leftChiled == null) {
34             if (current == root) {
35                 root = current.rightChiled;
36             } else if (isLeftchild) {
37                 parent.leftChiled = current.rightChiled;
38             } else {
39                 parent.rightChiled = current.rightChiled;
40             }
41         } else {// 第3种情况
42             BinaryTree successor = getSuccessor(current);// 根结点开始,successor存放中序后继结点
43             if (current == root) {// 替换工作
44                 root = successor;
45             } else if (isLeftchild) {// 要删除的父节点的左子节点
46                 parent.leftChiled = successor;
47             } else {// 要删除的父节点的右子节点
48                 parent.rightChiled = successor;
49             }
50             successor.leftChiled = current.leftChiled;// 中序后继结点引用删除的左边的结点
51         }
52 
53         return true;
54     }
55 
56     public BinaryTree getSuccessor(BinaryTree delBin) {// 找中序后继结点方法
57         // delBin为要删除的结点
58         BinaryTree successor = delBin;// successor为查找的中序后继结点
59         BinaryTree successorParent = delBin; // successor的父节点
60         BinaryTree current = delBin.rightChiled; // 当前开始遍历的结点
61 
62         while (current != null) {// 这里完成elBin.rightChiled是叶子结点
63             successorParent = successor;// successorParent保存上一个successor的引用
64             successor = current;// 循环完成以后,successor保存的就是中序后继结点
65             current = current.leftChiled;
66         }
67         // 中序后继结点有两种情况,就是delBin.rightChiled是否为叶子结点的两种情况
68 
69         if (successor != delBin.rightChiled) {// elBin.rightChiled不是叶子结点,中序后继结点是左边的
70             successorParent.leftChiled = successor.rightChiled;// 中序后继结点后面肯定只有右子节点
71             successor.rightChiled = delBin.rightChiled;// 中序后继结点的右子节点指向要删除的右边的结点
72             // successor.rightChiled指向要删除的rightChiled
73             // 交换成功
74         }
75         return successor;
76 
77     }
删除方法

二、

 1     public BinaryTree find(int value) {// 查找
 2         // 引用当前结点,从根结点开始
 3         BinaryTree current = root;
 4         // 循环,只要查找值不等于当前结点的数据项
 5         while (current.data != value) {
 6             // 进行比较,比较当前值和查找值的大小
 7             if (current.data > value) {
 8                 current = current.leftChiled;
 9             } else {
10                 current = current.rightChiled;
11             }
12             if (current == null) {
13                 return null;
14             }
15 
16         }
17         return current;
18     }
查找方法

 遍历二叉树,有3种遍历方法。其中,中序遍历最为常用,因为可以让特定的数据排序输出,前面我们已经学习了递归方法,接下来我们也使用递归方法实现。

前序遍历。
(1)访问根结点
(2)前序遍历左子树
(3)前序遍历右子树
1 public void frontOrder(BinaryTree localBin) {// 前序
2         if (localBin != null) {// 递归结束条件
3             System.out.println(localBin.data);
4             frontOrder(localBin.leftChiled);
5             frontOrder(localBin.rightChiled);
6         }
7     }
前序遍历

 


中序遍历。
(1)中序遍历左子树
(2)访问根结点
(3)中序遍历右子树
1 public void middleOrder(BinaryTree localBin) {// 前序
2         if (localBin != null) {// 递归结束条件
3             middleOrder(localBin.leftChiled);
4             System.out.println(localBin.data);
5             middleOrder(localBin.rightChiled);
6         }
7     }
中序遍历

 


后序遍历。
(1)后序遍历左子树
(2)后序遍历右子树
(3)访问根结点
1 public void endOrder(BinaryTree localBin) {// 前序
2         if (localBin != null) {// 递归结束条件
3             endOrder(localBin.leftChiled);
4             endOrder(localBin.rightChiled);
5             System.out.println(localBin.data);
6         }
7     }
后序遍历

 前辈的头发秃光不是没有原因的,哈哈哈

 

 

  1 package binarytree;
  2 
  3 public class TestTree {
  4     // 根结点
  5     public BinaryTree root;
  6 
  7     public static void main(String[] args) {
  8         TestTree tt = new TestTree();
  9         tt.add(10);
 10         tt.add(5);
 11         tt.add(4);
 12         tt.add(6);
 13         tt.add(12);
 14         tt.add(11);
 15         tt.add(14);
 16         tt.add(13);
 17 
 18         tt.middleOrder(tt.root);
 19         tt.delete(10);
 20         System.out.println();
 21         tt.middleOrder(tt.root);
 22 
 23     }
 24 
 25     public void frontOrder(BinaryTree localBin) {// 前序
 26         if (localBin != null) {// 递归结束条件
 27             System.out.print(localBin.data + " ");
 28             frontOrder(localBin.leftChiled);
 29             frontOrder(localBin.rightChiled);
 30         }
 31     }
 32 
 33     public void middleOrder(BinaryTree localBin) {// 中序
 34         if (localBin != null) {// 递归结束条件
 35             middleOrder(localBin.leftChiled);
 36             System.out.print(localBin.data + " ");
 37             middleOrder(localBin.rightChiled);
 38         }
 39     }
 40 
 41     public void endOrder(BinaryTree localBin) {// 后序
 42         if (localBin != null) {// 递归结束条件
 43             endOrder(localBin.leftChiled);
 44             endOrder(localBin.rightChiled);
 45             System.out.print(localBin.data + " ");
 46         }
 47     }
 48 
 49     public void add(int value) {
 50         // 封装结点
 51         BinaryTree newnode = new BinaryTree(value);
 52 
 53         BinaryTree parent;// 引用父节点
 54 
 55         BinaryTree current = root;// current引用根结点
 56 
 57         if (root == null) {// 如果root为null,也就是第一次插入
 58             root = newnode;
 59             return;
 60         } else {
 61             while (true) {
 62 
 63                 parent = current;// 父节点指向指向当前节点,保存上一个结点
 64                 if (current.data > value) {
 65                     current = current.leftChiled;
 66                     if (current == null) {
 67                         parent.leftChiled = newnode;
 68                         return;
 69                     }
 70                 } else {
 71                     current = current.rightChiled;
 72 
 73                     if (current == null) {
 74                         parent.rightChiled = newnode;
 75                         return;
 76                     }
 77                 }
 78 
 79             }
 80         }
 81     }
 82 
 83     public BinaryTree find(int value) {// 查找
 84         // 引用当前结点,从根结点开始
 85         BinaryTree current = root;
 86         // 循环,只要查找值不等于当前结点的数据项
 87         while (current.data != value) {
 88             // 进行比较,比较当前值和查找值的大小
 89             if (current.data > value) {
 90                 current = current.leftChiled;
 91             } else {
 92                 current = current.rightChiled;
 93             }
 94             if (current == null) {
 95                 return null;
 96             }
 97 
 98         }
 99         return current;
100     }
101 
102     public boolean delete(long value) {// 删除
103         BinaryTree current = root;// current保存根结点
104         BinaryTree parent = root;// parent保存parent的父节点
105         boolean isLeftchild = true;
106         while (current.data != value) {
107             parent = current;
108             // 进行比较,比较当前值和查找值的大小
109             if (current.data > value) {
110                 current = current.leftChiled;
111                 isLeftchild = true;// true为左子树
112             } else {
113                 current = current.rightChiled;
114                 isLeftchild = false;
115             }
116             if (current == null) {
117                 return false;
118             }
119         }
120         if (current.leftChiled == null && current.rightChiled == null) {// 第1种情况
121             if (isLeftchild) {
122                 parent.leftChiled = null;
123             } else {
124                 parent.rightChiled = null;
125             }
126         } else if (current.rightChiled == null) {// 第2种情况
127             if (current == root) {
128                 root = current.leftChiled;
129             } else if (isLeftchild) {
130                 parent.leftChiled = current.leftChiled;
131             } else {
132                 parent.rightChiled = current.leftChiled;
133             }
134         } else if (current.leftChiled == null) {
135             if (current == root) {
136                 root = current.rightChiled;
137             } else if (isLeftchild) {
138                 parent.leftChiled = current.rightChiled;
139             } else {
140                 parent.rightChiled = current.rightChiled;
141             }
142         } else {// 第3种情况
143             BinaryTree successor = getSuccessor(current);// 根结点开始,successor存放中序后继结点
144             if (current == root) {// 替换工作
145                 root = successor;
146             } else if (isLeftchild) {// 要删除的父节点的左子节点
147                 parent.leftChiled = successor;
148             } else {// 要删除的父节点的右子节点
149                 parent.rightChiled = successor;
150             }
151             successor.leftChiled = current.leftChiled;// 中序后继结点引用删除的左边的结点
152         }
153 
154         return true;
155     }
156 
157     public BinaryTree getSuccessor(BinaryTree delBin) {// 找中序后继结点方法
158         // delBin为要删除的结点
159         BinaryTree successor = delBin;// successor为查找的中序后继结点
160         BinaryTree successorParent = delBin; // successor的父节点
161         BinaryTree current = delBin.rightChiled; // 当前开始遍历的结点
162 
163         while (current != null) {// 这里完成elBin.rightChiled是叶子结点
164             successorParent = successor;// successorParent保存上一个successor的引用
165             successor = current;// 循环完成以后,successor保存的就是中序后继结点
166             current = current.leftChiled;
167         }
168         // 中序后继结点有两种情况,就是delBin.rightChiled是否为叶子结点的两种情况
169 
170         if (successor != delBin.rightChiled) {// elBin.rightChiled不是叶子结点,中序后继结点是左边的
171             successorParent.leftChiled = successor.rightChiled;// 中序后继结点后面肯定只有右子节点
172             successor.rightChiled = delBin.rightChiled;// 中序后继结点的右子节点指向要删除的右边的结点
173             // successor.rightChiled指向要删除的rightChiled
174             // 交换成功
175         }
176         return successor;
177 
178     }
179 }
complete code

 

posted @ 2019-08-06 23:28  hardhp74520  阅读(661)  评论(0编辑  收藏  举报