在前面的一章中,我们知道了如何实现简单的二叉树,可以实现get查询,put插入,以及delete删除。
下面我们对二叉树的查询进行一定的扩展,查询二叉树中的最小值和最大值
查询二叉树中的最小键
在某些情况下,我们需要查找出树中存储的所有元素的键的最小值,比如我们树中存储的是学生的排名和姓名数据。那么我们需要查找出排名最低是多少名?这里我们设计以下两个方法来完成:
方法 | 作用 |
---|---|
public Key min() | 找出树中最小的键 |
private Node min(Node x) | 找出指定树X中,最小键所在的结点 |
好的,看完了需求之后我们最直接开始实现:
public String min(){
return min(root).value;
}
private Node min(Node tree){
if (tree==null){
return null;
}
while(tree.left!=null){
return min(tree.left);
}
return tree;
}
上面这段代码几句话就可以讲清楚,也是通过递归的思想,这种情况下的二叉树大量运用了递归的思想,就是不断的对二叉树的左子结点进行递归,直到最后左结点值为null为止!
查询二叉树中的最大键
在某些情况下,我们需要查找出树中存储的所有元素的键的最小值,比如我们树中存储的是学生的排名和姓名数据。那么我们需要查找出分数最高是多少名?这里我们设计以下两个方法来完成:
方法 | 作用 |
---|---|
public Key max() | 找出树中最小的键 |
private Node max(Node x) | 找出指定树X中,最小键所在的结点 |
public String max(){
return max(root).value;
}
private Node max(Node tree){
if (tree==null){
return null;
}
while(tree.right!=null){
return max(tree.right);
}
return tree;
}
思想与第一种情况类似,这里就不过度探究了!
然后这篇博文我们来研究下二叉树的遍历
很多情况下,我们可能需要像遍历数组一样,遍历树,从而拿出树中存储的每一个元素,由于树状结构和线性结构不一样,它没有办法从头开始依次向后遍历,所以存在如何遍历,也就是按照什么样的搜索路劲进行遍历的问题。
- 前序遍历:先访问根结点,然后再访问左子树,最后访问右子树
- 中序遍历:先访问左子树,中间访问根结点,最后访问右子树
- 后序遍历:先访问左子树,再访问右子树,最后访问根结点
首先我们先看下前序遍历的API:
方法 | 作用 |
---|---|
public Queue preErgodic() | 使用前序遍历,获取整个树中的所有键 |
private void preErgodic(Node x,Queue keys) | 使用前序遍历,把指定树x中的所有键放入到keys队列中 |
实现过程中,我们通过前序遍历,把每个结点的键取出,放入到队列中返回即可
实现步骤:
- 把当前结点的key放入到队列中;
- 找到当前结点的左子树,如果不为空,遍历左子树
- 找到当前结点的右子树,如果不为空,递归遍历右子树
下面我们开始进行代码实现,我们方法中用到的Queue是我们前面自己定义的队列,你也可以使用自己写的,或者去我前面的博客直接用我的队列结构实现
首先写个给用户操作的接口:
public Queue preErgodic(){
Queue keys=new Queue();
preErgodic(root,keys);
return keys;
}
由于是遍历操作,所以我们不传递参数进去,并且在方法里面写一个队列,然后将队列传递进我们的入口,最后将这个队列返回。
private void preErgodic(Node tree,Queue keys){
if (tree==null){
return ;
}
//把当前结点的key放入到队列中
keys.enqueue(tree.key+"");
//找到当前结点的左子树,如果不为空,递归遍历左子树
if(tree.left!=null){
preErgodic(tree.left,keys);
}
//找到当前结点的右子树
if(tree.right!=null){
preErgodic(tree.right,keys);
}
}
- 判断树是否为空,如果树为空的话,直接结束循环不用返回任何值。
- 如果不为空的话才开始遍历,首先将根结点放入队列
- 遍历左子树
- 遍历右子树
以上就是前序遍历
而后序遍历实现方法与前序遍历基本相同,不过就是改变了位置,最后遍历根结点罢了。
顺序是:
- 遍历左子树
- 遍历右子树
- 遍历根结点
//后序遍历开始
public Queue afterErgodic(){
Queue queue=new Queue();
afterErgodic(root,queue);
return queue;
}
private void afterErgodic(Node tree,Queue keys){
if(tree!=null){
return ;
}
if(tree.left!=null){
midErgodic(tree.left,keys);
}
if(tree.right!=null){
midErgodic(tree.right,keys);
}
keys.enqueue(tree.key+"");
}
//后序遍历结束
好了,前面的都是小儿科,接下来我们来研究我们二叉树遍历的重点:层序遍历
层序遍历,顾名思意就是将二叉树按层次一层层遍历出来,先遍历根结点,放入队列,然后将根结点弹出来,再将根结点的左右结点放入放入队列,再依次将那两个结点遍历弹出来,再将其左右4个结点放入队列中,依次类推。
这就是层序遍历的实现思想
思想听不懂没关系,我们代码看的懂就够了,先看实现步骤:
- 创建队列,存储每一层的结点
- 使用循环从队列中弹出一个结点
2.1:获取当前结点的key;
2.2:如果当前结点的左子结点不为空,则吧左结点放入队列中
2.3:如果当前结点的右子结点不为空,则把右子结点放入队列中
下面我们看代码实现:
public Queue layerErgodic() {
// 创建一个队列,存储每一层的节点
Queue nodes = new Queue();
// 创建一个队列,用于存储遍历的节点
Queue keys = new Queue();
// 将当前节点存储到nodes中
nodes.enqueue(root.key + "");
// 遍历queue
while (!nodes.isEmpty()) {
// 出列
String key = nodes.dequeue();
Node currentNode = getNode(root, Integer.parseInt(key));
// 把节点的key存入到keys中
keys.enqueue(currentNode.key + "");
// 如果当前节点的左子节点不为空,则把左子节点放入到队列中
if (currentNode.left != null) {
nodes.enqueue(currentNode.left.key + "");
}
// 如果当前节点的右子节点不为空,把右子节点放到队列中
if (currentNode.right != null) {
nodes.enqueue(currentNode.right.key + "");
}
}
return keys;
}