Java数据结构与算法之树_动力节点Java学院整理
来源:互联网 发布:vb控件加到窗体上 编辑:程序博客网 时间:2024/05/22 12:51
为什么使用树:
树结合了两种数据结构的有点:一种是有序数组,树在查找数据项的速度和在有序数组中查找一样快;另一种是链表,树在插入数据和删除数据项的速度和链表一样。既然这样,就要好好去学了....
(最主要讨论的是二叉树中的二叉搜索树,即一个节点的左子节点关键值小于这个节点,右子节点的关键值大于这个节点)
设计前的思考:
树——>元素(节点)
class Node
{
public int iData ;
public float fData ;
public Node left ;
public Node right ;
//方法
public Node(int iData,float fData){}
public void displayNode(){}
}
class Tree
{
Node root ;//树根
//方法
public void insert(){}
public void displayTree(){}
public void find(){}
public void delete(){}
}
插入数据:
1 //插入子节点
2 public void insert(int iData ,float fData)
3 {
4 Node newNode =new Node(iData,fData) ;
5
6 if(root ==null)
7 root = newNode ;
8 else
9 {
10 Node current = root ;
11 Node parent ;
12 while(true)//寻找插入的位置
13 {
14 parent = current ;
15 if(iData<current.iData)
16 {
17 current = current.left ;
18 if(current ==null)
19 {
20 parent.left = newNode ;
21 return ;
22 }
23 }
24 else
25 {
26 current =current.right ;
27 if(current ==null)
28 {
29 parent.right = newNode ;
30 return ;
31 }
32 }
33 }
34 }
35 }
遍历树:
1 //中序遍历方法
2 public void inOrder(Node localRoot)
3 {
4 if(localRoot !=null)
5 {
6 inOrder(localRoot.left) ;//调用自身来遍历左子树
7 localRoot.displayNode() ;//访问这个节点
8 inOrder(localRoot.right) ;//调用自身来遍历右子树
9 }
10 }
查找某个节点:
1 //查找某个节点
2 public Node find(int iData)
3 {
4 Node current = root ;
5 while(current.iData != iData)
6 {
7 if(current.iData<iData)
8 current = current.right ;
9 else
10 current = current.left ;
11 if(current ==null)
12 return null ;
13 }
14 return current ;
15 }
查找树中关键字的最大值和最小值:
最大值:不断地寻找右子节点
最小值:不断地寻找左子节点
1 //查找关键字最小的节点
2 public Node findMinNode()
3 {
4 Node current , last ;
5 last =null ;
6 current = root ;
7 if(current.left ==null)
8 return current ;
9 else
10 {
11 while(current !=null)
12 {
13 last = current ;
14 current = current.left ;
15 }
16 return last ;
17 }
18 }
删除某个节点:
思考:
1).先找到要删除的节点:
1 public boolean delete(int key)
2 {
3 //先找到需要删除的节点
4 Node current = root ;
5 Node parent = root ;
6 boolean isLeftChild =false ;
7
8 while(current.iData != key)//显然,当current.iData == key 时,current就是要找的节点
9 {
10 parent = current ;
11 if(key < current.iData)
12 {
13 isLeftChild =true ;
14 current = current.left ;
15 }
16 else
17 {
18 isLeftChild =false ;
19 current = current.right ;
20 }
21 if(current ==null)//找不到key时返回false
22 return false ;
23 }
24 //continue ........
25 }
2).再考虑要删除的节点是怎样的节点,经分析,有三种情况:叶节点、有一个节点的节点、有两个节点的节点
A).如果删除的是一个叶子节点,直接删除即可
//接上................
//分情况考虑删除的节点
//删除的节点为叶节点时
if(current.left ==null && current.right == null)
{
if(current == root)
root = null ;
else
if(isLeftChild)
parent.left = null ;
else
parent.right = null ;
}
//continue...........
B).如果删除的节点有一个节点时:分两种情况,删除的节点只有一个左子节点,或者只有一个右子节点
//接上.......
//删除的节点有一个子节点
else
if(current.right ==null)//删除的节点只有一个左子节点时
{
if(current == root)//要删除的节点为根节点
root = current.left ;
else
if(isLeftChild)//要删除的节点是一个左子节点
parent.left = current.left ;
else
parent.right = current.left ;//要删除的节点是一个右子节点
}
else
if(current.left ==null)//删除的节点只有一个右子节点时
{
if(current == root)//要删除的节点为根节点
root = current.right ;
else
if(isLeftChild)//要删除的节点是一个左子节点
parent.left = current.right ;
else
parent.right = current.right ;//要删除的节点是一个右子节点
}
//continue.......
c).如果删除的节点有两个节点时:
这种情况就比较复杂,需要去寻找一个节点去替代要删除的节点。这个节点应该是什么节点呢?
据书本介绍,最合适的节点是后继节点,即比要删除的节点的关键值次高的节点是它的后继节点。
说得简单一些,后继节点就是比要删除的节点的关键值要大的节点集合中的最小值。
以上面的为例,40的后继节点为74,10的后继节点是13,19的后继节点时26
以下是寻找后继节点的代码:
1 //返回后继节点
2 private Node getSuccessor(Node delNode)
3 {
4 Node successorParent = delNode ;//后继节点的父节点
5 Node successor = delNode ;//后继节点
6 Node current = delNode.right ;//移动到位置节点位置
7 while(current !=null)
8 {
9 successorParent = successor ;
10 successor = current ;
11 current = current.left ;
12 }
13 if(successor != delNode.right)
14 {
15 successorParent.left = successor.right ;
16 successor.right = delNode.right ;
17 }
18 return successor ;
19 }
找到了后继节点,接着就要讨论如何用后继节点替代药删除的节点
a)如果后继节点是刚好是要删除节点的右子节点(此时可以知道,这个右子节点没有左子点,如果有,就不该这个右子节点为后继节点)
//要删除的节点为左子节点时
parent.left = successor ;
successor.left = current.left ;
//要删除的节点是右子节点时
parent.right = successor ;
successor.left = current.left ;
b)如果后继节点为要删除节点的右子节点的左后代:
//假如要删除的节点为右子节点
successorParent.left = successor.right ;//第一步
successor.right = current.right ;//第二步
parent.right = successor ;
successor.left = current.left ;
//假设要删除的节点为左子节点
successorParent.left = successor.right ;
successor.right = current.right ;
parent.left = successor ;
successor.left = current.left ;
注意:第一步和第二步在getSuccessor()方法的最后的if语句中完成
以下是删除的节点有连个节点的代码:
1 //接上
2 //删除的节点有两个子节点
3 else
4 {
5 Node successor = getSuccessor(current) ;//找到后继节点
6 if(current == root)
7 root = successor ;
8 else
9 if(isLeftChild)
10 parent.left = successor ;
11 else
12 parent.right = successor ;
13 successor.left = current.left ;
14 }
15 //continue....
综合上述,给出delete()方法的代码:
1 //删除某个节点
2 public boolean delete(int key)
3 {
4 //先找到需要删除的节点
5 Node current = root ;
6 Node parent = root ;
7 boolean isLeftChild =false ;
8
9 while(current.iData != key)//显然,当current.iData == key 时,current就是要找的节点
10 {
11 parent = current ;
12 if(key < current.iData)
13 {
14 isLeftChild =true ;
15 current = current.left ;
16 }
17 else
18 {
19 isLeftChild =false ;
20 current = current.right ;
21 }
22 if(current ==null)//找不到key时返回false
23 return false ;
24 }
25
26 //分情况考虑删除的节点
27 //删除的节点为叶节点时
28 if(current.left ==null && current.right == null)
29 {
30 if(current == root)
31 root =null ;
32 else
33 if(isLeftChild)
34 parent.left =null ;
35 else
36 parent.right =null ;
37 }
38 //删除的节点有一个子节点
39 else
40 if(current.right ==null)//删除的节点只有一个左子节点时
41 {
42 if(current == root)//要删除的节点为根节点
43 root = current.left ;
44 else
45 if(isLeftChild)//要删除的节点是一个左子节点
46 parent.left = current.left ;
47 else
48 parent.right = current.left ;//要删除的节点是一个右子节点
49 }
50 else
51 if(current.left ==null)//删除的节点只有一个右子节点时
52 {
53 if(current == root)//要删除的节点为根节点
54 root = current.right ;
55 else
56 if(isLeftChild)//要删除的节点是一个左子节点
57 parent.left = current.right ;
58 else
59 parent.right = current.right ;//要删除的节点是一个右子节点
60 }
61 //删除的节点有两个子节点
62 else
63 {
64 Node successor = getSuccessor(current) ;//找到后继节点
65 if(current == root)
66 root = successor ;
67 else
68 if(isLeftChild)
69 parent.left = successor ;
70 else
71 parent.right = successor ;
72 successor.left = current.left ;
73 }
74 return true ;
75 }
进一步考虑:
删除那么复杂,那删除是必要的吗?我们可以给每个节点定义一个标志,该标志用于记录该节点是否已经删除了,
显示树时,先判断该节点是否已经删除,如果没有,则显示。
这样的结果是,节点其实是没有删除的,这样显然逃避责任了。当树中没有那么多的删除操作时,这也不失为一种好方法,例如:
已经离职的员工的档案要永久地保存在员工的记录中。
本文转自互联网,由动力节点整理发布
- Java数据结构与算法之树_动力节点Java学院整理
- Java数据结构与算法之选择排序_动力节点Java学院整理
- Java数据结构与算法之栈_动力节点Java学院整理
- Java数据结构之队列_动力节点Java学院整理
- Java数据结构之数组_动力节点Java学院整理
- Java数据结构之图_动力节点Java学院整理
- Java数据结构和算法之冒泡排序_动力节点Java学院整理
- Java数据结构之链表_动力节点Java学院整理
- Java数据结构之散列表_动力节点Java学院整理
- Java虚拟机 (JVM)运行机制_动力节点Java学院整理
- Java代码注释规范_动力节点Java学院整理
- Java运算符_动力节点Java学院整理
- Java中的关键字_动力节点Java学院整理
- Java字符编码原理_动力节点Java学院整理
- JVM(Java虚拟机)简介_动力节点Java学院整理
- Java初学者问题图解_动力节点Java学院整理
- Java多态_动力节点Java学院整理
- Java构造方法_动力节点Java学院整理
- jquery设置checked及复选框 多个提交
- 【NOIP模板】 树状数组
- 【Spring in action】SpringMVC基于xml及java配置的简单运用
- 【安卓学习之常见问题】 apk崩溃,找不到so文件(dex file "couldn't find "libSDL.so)
- API Hook
- Java数据结构与算法之树_动力节点Java学院整理
- 常用的可视化数据展示工具有哪些
- Hdu 5405 Sometimes Naive 树链剖分+线段树
- 动态规划——最长公共子序列问题(LCS)
- Windows 7系统想要查看事件日志时候要如何查看
- Mac上搭建Xcode9.0+appium1.6.5过程及链接模拟器测试app
- jQuery 遍历
- curl 模拟表单发送
- 理解OAuth 2.0