二叉查找树的遍历
一、二叉树相关概念介绍
1.二叉树:二叉树就是度不超多2的树,每个结点最多有两个子结点;
2.满二叉树:除了最后一层,每一层的结点都有左右子结点,则该树就是满二叉树。如果一个满二叉树的层数为k,则结点总数为:(2^k)-1;
3. 完全二叉树:叶子结点只能出现在最下层和次下层,且最下面一层的结点都集中在最左边的若干位置;
4. 二叉查找树:一种特殊的二叉树,对于任意非叶子结点,左子结点的值小于该结点值,右子结点值大于该结点值。
二叉树示例如下图所示:
删除结点前后对比下图所示(用于测试使用数据):
二叉树的遍历
1、前序遍历:20-13-9-18-19-26-24-27
2、中序遍历:9-13-18-19-20-24-26-27
3、后序遍历:9-19-18-13-24-27-26-20
3、层序遍历:20-13-26-9-18-24-27-19
二、二叉树查找树实现代码
package mongo.util.dataStructure;
import java.util.LinkedList;
import java.util.Queue;
/**
* 二叉树
* <p>
* 二叉树就是度不超多2的树,每个结点最多有两个子结点
* <p>
* 满二叉树:
* 除了最后一层,每一层的结点都有左右子结点,则该树就是满二叉树
* 如果一个满二叉树的层数为k,则结点总数为:(2^k)-1
* <p>
* 完全二叉树
* 叶子结点只能出现在最下层和次下层,且最下面一层的结点都集中在最左边的若干位置
* <p>
* 二叉查找树
* 一种特殊的二叉树,对于任意非叶子结点,左子结点的值小于该结点值,右子结点值大于该结点值
*/
public class BinaryTree {
//根结点
private Node root;
private int size;
public void put(Integer key, String value) {
root = this.put(key, value, root);
}
//给指定树上插入新结点,并返回新树
private Node put(Integer key, String value, Node target) {
if (target == null) {
target = new Node(key, value, null, null);
size++;
return target;
}
//如果新增结点小于target,则添加到target左子结点
if (key < target.key) {
Node node = put(key, value, target.left);
target.left = node;
}
//如果新增结点大于target,则添加到target右子结点
if (key > target.key) {
Node node = put(key, value, target.right);
target.right = node;
}
//如果新增结点等于target, 则更新target
target.vaule = value;
return target;
}
public String get(Integer key) {
Node node = get(key, root);
return node == null ? null : node.vaule;
}
/**
* get方法思路,从根结点开始查找
* 1.如果查询的key小于当前结点的key,则继续查询当前结点的左子结点
* 2.如果查询的key大于当前结点的key,则继续查询当前结点的右子结点
* 3.如果查询的key等当前结点的key,则查询命中,返回当前结点的value
*
* @return
*/
private Node get(Integer key, Node node) {
if (node == null) {
return null;
}
if (key.equals(node.key)) {
return node;
}
if (key < node.key) {
return get(key, node.left);
}
if (key > node.key) {
return get(key, node.right);
}
return null;
}
public void delete(Integer key) {
root = delete(key, root);
}
/**
* 删除结点思路:
* 1.先查询到被删除的结点X
* 2.找到结点X的右子树中的最小结点minNode
* 3.让结点X的左子树成为minNode的左子树,让结点X的右子树成为minNode的右子树
* 4.让结点X的父结点指向minNode
*
* @param key
* @param node
*/
private Node delete(Integer key, Node node) {
if (node == null) {
return null;
}
//如果被删结点小于当前结点node,则继续从node左子结点查询
if (key < node.key) {
node.left = delete(key, node.left);
}
///如果被删结点大于当前结点node,则继续从node右子结点查询
else if (key > node.key) {
node.right = delete(key, node.right);
} else {
//key == node.key,已经找到被删除结点
Node deleteNode = node;
//如果被删结点deleteNode无左子结点,则返回deleteNode的右子结点
if (deleteNode.left == null) {
return deleteNode.right;
}
//如果被删结点deleteNode无右子结点,则返回deleteNode的左子结点
if (deleteNode.right == null) {
return deleteNode.left;
}
//如果被删结点deleteNode存在左右子树,则找到被删结点deleteNode的右子树中的最小结点minNode
Node minNode = deleteNode.right;
if (minNode.left != null) {
minNode = minNode.left;
}
Node n = deleteNode.right;
while (n.left != null) {
if (n.left.left == null) {
//说明n.left已经为叶子结点,删除n.left
n.left = null;
minNode = n.left;
} else {
n = n.left;
}
}
if (n.left == null) {
deleteNode.right = null;
}
//最小结点已经删除,让deleteNode的左子树成为minNode的左子树,让deleteNode的右子树成为minNode的右子树
minNode.left = deleteNode.left;
minNode.right = deleteNode.right;
size--;
//返回新树
return minNode;
}
return node;
}
/**
* 前序遍历:先访问根结点,再访问左子树,最后访问右子树
*
* @return
*/
public Queue<Integer> preorderErgodic() {
Queue<Integer> queue = new LinkedList<>();
preorderErgodic(root, queue);
return queue;
}
private void preorderErgodic(Node node, Queue<Integer> queue) {
if (node == null) {
return;
}
//把当前结点放入队列
queue.add(node.key);
if (node.left != null) {
//如果当前结点有左结点,则继续访问左子树
preorderErgodic(node.left, queue);
}
if (node.right != null) {
//如果当前结点没右左结点,则说明左子树已经访问完毕,再访问右子树
preorderErgodic(node.right, queue);
}
}
/**
* 中遍历:先访问左子树,再访问根结点,最后访问右子树
*
* @return
*/
public Queue<Integer> inorderErgodic() {
Queue<Integer> queue = new LinkedList<>();
inorderErgodic(root, queue);
return queue;
}
private void inorderErgodic(Node node, Queue<Integer> queue) {
if (node == null) {
return;
}
if (node.left != null) {
//如果当前结点有左结点,则继续访问左子树
inorderErgodic(node.left, queue);
}
queue.add(node.key);
if (node.right != null) {
//如果当前结点没右左结点,则说明左子树已经访问完毕,再访问右子树
inorderErgodic(node.right, queue);
}
}
/**
* 后序遍历:先访问左子树,再访问根结点,最后访问右子树
*
* @return
*/
public Queue<Integer> postorderErgodic() {
Queue<Integer> queue = new LinkedList<>();
postorderErgodic(root, queue);
return queue;
}
private void postorderErgodic(Node node, Queue<Integer> queue) {
if (node == null) {
return;
}
if (node.left != null) {
//如果当前结点有左结点,则继续访问左子树
postorderErgodic(node.left, queue);
}
if (node.right != null) {
//如果当前结点没右左结点,则说明左子树已经访问完毕,再访问右子树
postorderErgodic(node.right, queue);
}
queue.add(node.key);
}
/**
* 层序遍历,逐层按顺序输出
*
* @return
*/
public Queue<Integer> layerErgodic() {
//用于弹出结点队列
Queue<Node> popQueue = new LinkedList<>();
//用于添加结点,作为最后的返回结果
Queue<Integer> enQueue = new LinkedList<>();
popQueue.add(root);
/**
* 实现思路:
* 1.将当前结点从popQueue中取出,加入到enQueue
* 2.将当前结点的左右子结点添加到popQueue,继续循环
*/
while (popQueue.peek() != null) {
Node node = popQueue.poll();
if (node.left != null) {
popQueue.add(node.left);
}
if (node.right != null) {
popQueue.add(node.right);
}
enQueue.add(node.key);
}
return enQueue;
}
public int size() {
return size;
}
/**
* 构建树的结点
*/
class Node {
private Integer key;
private String vaule;
private Node left;
private Node right;
private Node(Integer key, String vaule, Node left, Node right) {
this.key = key;
this.vaule = vaule;
this.left = left;
this.right = right;
}
}
}
三、结果测试
package mongo.util.dataStructure;
import java.util.Queue;
public class TreeMainTest {
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
tree.put(20, "1");
tree.put(13, "2");
tree.put(26, "3");
tree.put(9, "4");
tree.put(18, "5");
tree.put(24, "6");
tree.put(27, "7");
tree.put(19, "8");
System.out.println(tree.size());
//前序遍历
Queue<Integer> preorder = tree.preorderErgodic();
String treeKeys_preorder = "";
while (preorder.peek() != null) {
treeKeys_preorder += "--" + preorder.poll();
}
System.out.println("前序遍历" + treeKeys_preorder);
//中序遍历
Queue<Integer> inorder = tree.inorderErgodic();
String treeKeys_inorder = "";
while (inorder.peek() != null) {
treeKeys_inorder += "--" + inorder.poll();
}
System.out.println("中序遍历" + treeKeys_inorder);
//后序遍历
Queue<Integer> postorder = tree.postorderErgodic();
String treeKeys_postorder = "";
while (postorder.peek() != null) {
treeKeys_postorder += "--" + postorder.poll();
}
System.out.println("后序遍历" + treeKeys_postorder);
//层序遍历
Queue<Integer> layerErgodic = tree.layerErgodic();
String treeKeys_layer = "";
while (layerErgodic.peek() != null) {
treeKeys_layer += "--" + layerErgodic.poll();
}
System.out.println("层序遍历" + treeKeys_layer);
}
}
备注:测试数据如上图,删除前后对比图中数据
测试结果: