码迷,mamicode.com
首页 > 编程语言 > 详细

一步一图一代码之排序二叉树

时间:2015-01-27 14:42:48      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong/

属性:

①若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。

②若它的右子树不为空,则右子树上所有节点的值均大于它的根节点的值。

③它的左、右子树也都是排序二叉树。

添加操作:

当根节点为空时,添加进的节点作为根节点。然后每次添加节点时,都从根节点过滤,以根节点作为当前节点,如果新节点大于当前节点,则走当前节点的右子节点分支,如果新节点小于当前节点,则走当前节点的左子节点分支。然后再用右子节点或左子节点作为当前节点与新加节点比较,如果新加节点大,则当前节点的右子节点,如果新加节点小,则当前节点的左子节点。依次类推直到左子树或右子树为null时,将该新节点添加在这里。

图解:

技术分享

代码解析:

技术分享
 1 public void add(T data){
 2     Node newNode=new Node(data);
 3     if(root==null){
 4         root=newNode;
 5     }else {
 6         add(newNode, root);
 7     }
 8 }
 9 public void add(Node addNode,Node parentNode) {
10     T data=addNode.data;
11     Node currentNode=parentNode;
12     Node parent=null;
13     int flag=0;
14     while(currentNode!=null){
15         parent=currentNode;
16         flag=data.compareTo(currentNode.data);
17         if(flag>0){
18             currentNode=currentNode.rightChild;
19         }else {
20             currentNode=currentNode.leftChild;
21         }
22     }
23     if(flag>0){
24         parent.rightChild=addNode;
25     }else {
26         parent.leftChild=addNode;
27     }
28     addNode.parent=parent;        
29 }
View Code

添加操作相对简单,麻烦的是删除操作。

删除操作

该操作有很多的情况:

      第一:待删除的节点是叶子节点

      第二:待删除的节点有左子树没有右子树

      第三:待删除的节点没有左子树有右子树

      第四:待删除的节点既没有左子树也没有右子树。

图解

在第一大类中我们还可分:

1、该叶子节点就是根节点,即树中只有一个根节点。

这是最简单的情况,直接树的根root指向null即可。

技术分享

2、否则便要判断该叶子节点是其父节点的左子节点呢还是其父节点的右子节点

下图为叶子节点是其父节点的左子节点,右子节点一样。

技术分享

在第二大类中我们还可以细分:

1、待删除的节点就是根节点。

只需将根节点的左子节点(因为这是根节点只有左子节点)指向父节点的指针打断,并将该左子节点设为根节点即可。

技术分享

2、如果待删除的节点不是根节点,那就必须讨论待删除的节点是其父节点的左子节点还是右子节点。

以是其父节点的左子节点为例(右子节点的情况一样),我们需要让待删除节点的父节点的指向其左孩子的指针重新指向待删除节点的左孩子,让待删除节点的左孩子的指向父节点的指针重新指向待删除节点的父节点。

技术分享

这期间,我们并没有打断图中节点5指向其左孩子节点3的指针,也没有打断节点5指向其父节点6的指针。这是因为,没这个必要。我们不打断这些节点5永远也不会被访问到,而且会被垃圾回收。

第三大类和第二大类一样。

第四大类

总的思想就是:找到待删除节点左子树中的最大节点(leftMaxNode),然后用leftMaxNode替代待删除的节点即可。这句话看似简单,但是实现起来可不是那么的容易!!!

我们也可以细分:

1、待删除节点就是根节点

     1.1 leftMaxNode就是待删除节点的左孩子。即待删除节点左子树中没有右节点。

技术分享

     1.2 如果待删除的节点不是根节点

对于这种情况,我们需要显示显示打断的“指针”只有两个:如下图中,节点3指向其右子节点4(leftMaxNode)的指针,即节点4(leftMaxNode)指向其父节点3的指针。然后用节点4(leftMaxNode)替换节点5(根节点)即可。

技术分享

2、待删除的节点不是根节点

     2.1 被删除节点的左子树中最大节点不是其左子节点

如下图所示:

技术分享

在这种情况下使用节点节点4替换节点5的时候,对于节点4和节点8、节点9的之间的“指针”创建比较容易,但是节点3与节点4之间的“指针”却不好创建,因为节点4的左子树可能很复杂,我们不知道将节点3插入哪里合适,所以,解决办法为,将节点3利用排序二叉树添加新节点的功能以新节点的形式加入节点4 中。

技术分享

     2.2 被删除节点的左子树中最大节点就是是其左子节点

即,如下情况,

技术分享

这种情况很简单了,就不详细说明了。

完整代码

技术分享
  1 package com.yyl.tree;
  2 
  3 import java.util.ArrayDeque;
  4 import java.util.ArrayList;
  5 import java.util.List;
  6 import java.util.Queue;
  7 
  8 public class SortedBinaryTree<T extends Comparable<T>> {
  9     public class Node{
 10         T data=null;
 11         Node parent=null;
 12         public Node getParent() {
 13             return parent;
 14         }
 15         public void setParent(Node parent) {
 16             this.parent = parent;
 17         }
 18 
 19         Node leftChild=null;
 20         Node rightChild=null;
 21         //region【访问器】
 22         public T getData() {
 23             return data;
 24         }
 25         public void setData(T data) {
 26             this.data = data;
 27         }
 28         public Node getLeftChild() {
 29             return leftChild;
 30         }
 31         public void setLeftChild(Node leftChild) {
 32             this.leftChild = leftChild;
 33         }
 34         public Node getRightChild() {
 35             return rightChild;
 36         }
 37         public void setRightChild(Node rightChild) {
 38             this.rightChild = rightChild;
 39         }
 40         //endregion
 41         
 42         // region 【构造器】
 43         public Node(){}
 44         public Node(T data){
 45             this.data=data;
 46         }
 47         public Node(T data, Node leftChild, Node rightChild){
 48             this.data=data;
 49             this.leftChild=leftChild;
 50             this.rightChild=rightChild;
 51         }
 52         //endregion
 53         @Override
 54         public boolean equals(Object obj) {
 55             if(this.data==obj){
 56                 return true;
 57             }else if(this.getClass()==obj.getClass()){
 58                 Node nodeObj=(Node)obj;
 59                  return this.data.compareTo(nodeObj.data) ==0 && this.leftChild.equals(nodeObj.leftChild) 
 60                         && this.rightChild.equals(nodeObj);
 61             }
 62             return false;
 63         }
 64     
 65         public String toString(){
 66             return "[data:"+this.data+"]";
 67         }
 68     }
 69     
 70     Node root=null;
 71     public SortedBinaryTree() {}
 72     public SortedBinaryTree(Node root){
 73         this.root=root;
 74     }
 75     
 76     //添加节点
 77     public void add(T data){
 78         Node newNode=new Node(data);
 79         if(root==null){
 80             root=newNode;
 81         }else {
 82             add(newNode, root);
 83         }
 84     }
 85     public void add(Node addNode,Node parentNode) {
 86         T data=addNode.data;
 87         Node currentNode=parentNode;
 88         Node parent=null;
 89         int flag=0;
 90         while(currentNode!=null){
 91             parent=currentNode;
 92             flag=data.compareTo(currentNode.data);
 93             if(flag>0){
 94                 currentNode=currentNode.rightChild;
 95             }else {
 96                 currentNode=currentNode.leftChild;
 97             }
 98         }
 99         if(flag>0){
100             parent.rightChild=addNode;
101         }else {
102             parent.leftChild=addNode;
103         }
104         addNode.parent=parent;        
105     }
106     // 删除节点
107     public void remove(T data){
108         if(root==null){
109             return;
110         }else {
111             Node removeNode=null;//待删除的节点
112             removeNode = getNode(data);
113             //endregion
114             
115             //如果没有找见抛出异常
116             if(removeNode==null){
117                 throw new RuntimeException("未找见要删除的节点");
118             }
119             System.out.println("待删除的节点为:"+removeNode.toString());
120             //如果待删除的节点既没有左孩子也没有右孩子
121             if(removeNode.leftChild==null && removeNode.rightChild==null){
122                 if(removeNode==root){//如果待删除的节点就是根节点,即树中只有一个根节点
123                     root=null;
124                 }else {//如果待删除的节点不是根节点,这就要考虑这个节点是其父节点的左孩子还是右孩子
125                     if(isLeftNodeOfParent(removeNode)){//如果待删除是其父节点的左孩子,则断开其父节点指向左孩子的“指针”
126                         removeNode.parent.leftChild=null;
127                     }else {//如果待删除是其父节点的有孩子,则断开其父节点指向右孩子的“指针”
128                         removeNode.parent.rightChild=null;
129                     }
130                     //【注】断开他的指向父节点的“指针”
131                     //removeNode.parent=null;
132                 }
133             }else if (removeNode.leftChild!=null && removeNode.rightChild==null) {//如果待删除的节点有左孩子但是没有右孩子
134                 if(removeNode==root){//如果待删除的节点就是根节点
135                     
136                     //这条语句并不是必须的,因为对于数而言,不管怎么都是以root为起点开始所有操作,所以遍历等操作不会涉及
137                     //到root.leftChild.parent.不将它设为null,同样不影响树的正常运行。但是root.leftChild.parent所引
138                     //用的对象并不会被当成垃圾而被回收,因为从root.leftChild.parent依然可以访问到该Java对象
139                     root.leftChild.parent=null;
140                     
141                     root=root.leftChild;
142                 }else {//如果待删除的节点不是根节点,那就必须讨论待删除的节点是其父节点的左子节点还是右子节点
143                     if(isLeftNodeOfParent(removeNode)){
144                         removeNode.parent.leftChild=removeNode.leftChild;
145                     }else {
146                         removeNode.parent.rightChild=removeNode.leftChild;
147                     }
148                     //这条语句不要更精炼,加上会让程序更清晰
149                     //removeNode.parent=null;        
150                     
151                     
152                     removeNode.leftChild.parent=removeNode.parent;                
153                 }
154                 //这条语句不要更精炼,加上会让程序更清晰
155                 //removeNode.leftChild=null;
156             }
157             else if (removeNode.leftChild==null && removeNode.rightChild!=null) {//如果待删除的节点没有左孩子但是有右孩子
158                 if(root==removeNode){//如果待删除的节点就是根节点
159                     root=root.rightChild;
160                     //释放内存,让垃圾回收removeNode
161                     removeNode.rightChild.parent=null;                    
162                 }else {//如果待删除的节点不是根节点
163                     if(isLeftNodeOfParent(removeNode)){
164                         removeNode.parent.leftChild=removeNode.rightChild;
165                     }else {
166                         removeNode.parent.rightChild=removeNode.rightChild;
167                     }                
168                     removeNode.rightChild.parent=removeNode.parent;
169                     
170                     //这条语句不要更精炼,加上会让程序更清晰
171                     //removeNode.parent=null;
172                 }
173                 //这条语句不要更精炼,加上会让程序更清晰
174                 //removeNode.rightChild=null;
175             }else {//如果待删除的节点既有左孩子也有右孩子
176                 Node leftMaxNode=null;
177                 //region【寻找被删除节点左子树中最大节点】                
178                 Node tmp=removeNode.leftChild;
179                 while(tmp.rightChild!=null){                    
180                     tmp=tmp.rightChild;                
181                 }
182                 leftMaxNode=tmp;
183                 //endregion
184                 
185                 System.out.println("leftmaxnode:"+leftMaxNode.toString());
186                 if(removeNode==root){//如果待删除的节点就是根节点
187                     if(leftMaxNode==removeNode.leftChild){//如果被删除节点的左子树中最大节点就是其左子节点            
188                         leftMaxNode.rightChild=root.rightChild;
189                         root.rightChild.parent=leftMaxNode;
190                         root=leftMaxNode;
191                         leftMaxNode.parent=null;
192                         
193                         //这条语句不要更精炼,加上会让程序更清晰
194                         //root.leftChild=null;
195                     }else {
196                         leftMaxNode.rightChild=root.rightChild;    
197                         leftMaxNode.leftChild=root.leftChild;
198                         
199                         root.rightChild.parent=leftMaxNode;
200                         root.leftChild.parent=leftMaxNode;
201                         
202                         leftMaxNode.parent.rightChild=null;
203                         leftMaxNode.parent=null;                        
204                         root=leftMaxNode;
205                     }
206                 }else {//如果待删除的节点不是根节点
207                     if(leftMaxNode!=removeNode.leftChild){//如果被删除节点的左子树中最大节点不是其左子节点                        
208                         Node addNode=removeNode.leftChild;
209                         removeNode.leftChild=null;
210                         addNode.parent=null;
211                         add(addNode,leftMaxNode);    
212                         leftMaxNode.parent.rightChild=null;
213                     }    
214                     leftMaxNode.rightChild=removeNode.rightChild;            
215                     removeNode.rightChild.parent=leftMaxNode;    
216                     
217                     leftMaxNode.parent=removeNode.parent;    
218                     
219                     
220                     if(isLeftNodeOfParent(removeNode)){
221                         removeNode.parent.leftChild=leftMaxNode;
222                     }else {                    
223                         removeNode.parent.rightChild=leftMaxNode;                        
224                     }                    
225                 }
226             }
227         }
228     }
229     
230     public Node getNode(T data) {
231         Node removeNode=null;
232         Node current=root;//临时变量,用于辅助查找待删除的节点            
233         //region 【寻找要待删除的节点】
234         while(current!=null){
235             if(data.compareTo(current.data)>0){
236                 current=current.rightChild;
237             }else if (data.compareTo(current.data)<0) {
238                 current=current.leftChild;
239             }else {
240                 removeNode=current;
241                 break;
242             }
243         }
244         return removeNode;
245     }
246     
247     private boolean isLeftNodeOfParent(Node node) {
248         return node.data.compareTo(node.parent.data)<=0;
249     }
250     //中序遍历
251     public List<Node> midIterator(){
252         return midIterator(root);
253     }
254     private List<Node> midIterator(Node node) {
255         List<Node> list=new ArrayList<Node>();
256         if(node==null){
257             return null;
258         }
259         if(node.leftChild!=null){
260             list.addAll(midIterator(node.leftChild));
261         }
262         list.add(node);
263         if(node.rightChild!=null){
264             list.addAll(midIterator(node.rightChild));
265         }
266         return list;
267     }
268 
269     //先序遍历
270     public List<Node> preIterator(){
271         return preIterator(root);
272     }
273     private List<Node> preIterator(Node root) {
274         List<Node> list=new ArrayList<Node>();
275         if(root==null)
276             return null;
277         list.add(root);
278         if(root.leftChild!=null){
279             list.addAll(preIterator(root.leftChild));
280         }
281         if(root.rightChild!=null){
282             list.addAll(preIterator(root.rightChild));
283         }
284         return list;
285     }
286 
287     //广度优先遍历
288     public List<Node> breadthFirst(){
289         return breadthFirst(root);
290     }
291     private List<Node> breadthFirst(Node root) {
292         Queue<Node> queue=new ArrayDeque<Node>();
293         List<Node> list=new ArrayList<Node>();
294         if(root==null)
295             return null;
296         queue.offer(root);
297         while(!queue.isEmpty()){
298             Node node=queue.poll();
299             list.add(node);
300             if(node.leftChild!=null){
301                 queue.offer(node.leftChild);
302             }
303             if(node.rightChild!=null){
304                 queue.offer(node.rightChild);
305             }
306         }
307         return list;
308     }
309 }
View Code

可能有些地方理解的还是不到位,并且代码的性能不是很高,请大家批评指正。

注:版权所有,转载请注明出处

一步一图一代码之排序二叉树

标签:

原文地址:http://www.cnblogs.com/yaoyinglong/p/DataStruct排序二叉树.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!