二叉树实战(二) - 二叉树的遍历方式

二叉树的遍历方式分为三种,  根据根节点的访问时机,定义以下三种方式:

1). 前序遍历

    先访问跟结点,再访问左子树,最后访问右子树。

2). 中序遍历

    先访问左子树,再访问根结点,最后访问右子树。

3). 后序遍历

    先访问左子树,再访问右子树,最后访问根结点。

 

在二叉查找树的代码基础上实现遍历以上遍历功能:

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * 二叉查找树遍历
 *
 * @param <Key>
 * @param <Value>
 */
public class BinaryTreeErgodic<Key extends Comparable<Key>, Value> {

    public static void main(String[] args) {
        BinaryTreeErgodic<String, String> tree = new BinaryTreeErgodic<>();
        tree.put("E", "5");
        tree.put("B", "2");
        tree.put("G", "7");
        tree.put("A", "1");
        tree.put("D", "4");
        tree.put("F", "6");
        tree.put("H", "8");
        tree.put("C", "3");

        //Queue<String> keys = tree.preErgodic();
        //System.out.println(keys.toString());

        //Queue<String> keys = tree.midErgodic();
        //System.out.println(keys.toString());

        Queue<String> keys = tree.afterErgodic();
        System.out.println(keys.toString());
    }


    /********************************************
     *  二叉查找树,实现核心功能
     * 1.插入
     * 2.查找
     * 3.删除
     * 4.查询最小值
     * 5.查询最大值
     *
     * 遍历方式:
     * 1.前序遍历
     * 2.中序遍历
     * 3.后序遍历
     ********************************************/

    // 记录根节点
    private Node root;

    // 记录树中元素的个数
    private int N;

    /**
     * 树节点结构体类
     */
    private class Node {

        public Key key;  // 存储键
        public Value value;  //  存储值
        public Node left;  // 记录左子节点
        public Node right; // 记录右子节点

        public Node(Key key, Value value, Node left, Node right) {
            this.key = key;
            this.value = value;
            this.left = left;
            this.right = right;
        }
    }

    // 获取树中元素的个数
    public int getSize() {
        return N;
    }

    // 向树中添加元素 key-value
    public void put(Key key, Value value) {
        root = put(root, key, value);
    }

    // 向指定的树x中添加key-value,并返回添加元素后的新树
    private Node put(Node x, Key key, Value value) {
        //  如果x的子树为空
        if (x == null) {
            N++;
            return new Node(key, value, null, null);
        }
        // 如果x的子树不为空,则比较x节点的键和key的大小
        // 如果key小于x结点的键,则继续找x结点的左子树。如果key大于x结点的键,则继续找x结点的右子树,如果key等于x结点的键,则替换x结点的值为value即可。
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {
            x.right = put(x.right, key, value);
        } else if (cmp < 0) {
            x.left = put(x.left, key, value);
        } else {
            x.value = value;
        }
        return x;
    }

    // 查询树中指定的key对应的value
    public Value get(Key key) {
        return get(root, key);
    }

    // 从指定的树x中,查找key对应的值
    private Value get(Node x, Key key) {
        // x树为NULL
        if (x == null) {
            return null;
        }
        // x树不为NULL,比较键的大小
        // 如果key小于x结点的键,则继续找x结点的左子树。如果key大于x结点的键,则继续找x结点的右子树,如果key等于x结点的键,则返回该键的值
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {
            return get(x.right, key);
        } else if (cmp < 0) {
            return get(x.left, key);
        } else {
            return x.value;
        }
    }

    // 删除树中key对应的value
    public void delete(Key key) {
        delete(root, key);
    }

    // 删除指定树x中key对应的value,并返回删除后的新树
    private Node delete(Node x, Key key) {
        // x树为null
        if (x == null) {
            return null;
        }
        // x树不为NULL,比较键的大小
        // 如果key小于x结点的键,则继续找x结点的左子树。如果key大于x结点的键,则继续找x结点的右子树,如果key等于x结点的键,执行真正的删除操作
        int cmp = key.compareTo(x.key);
        if (cmp > 0) {
            return x.right = delete(x.right, key);
        } else if (cmp < 0) {
            return x.left = delete(x.left, key);
        } else {
            N--;
            if (x.right == null) {
                return x.left;
            }
            if (x.left == null) {
                return x.right;
            }
            // 找到右子树的最小结点
            Node minNode = x.right;
            while (minNode.left != null) {
                minNode = minNode.left;
            }
            // 删除右子树中最小的结点
            Node n = x.right;
            while (n.left != null) {
                if (n.left.left == null) {
                    n.left = null;
                } else {
                    n = n.left;  // 变换n结点
                }
            }
            // 让x结点的左子树成为minNode的左子树
            minNode.left = x.left;
            // 让x结点的右子树成为minNode的右子树
            minNode.right = x.right;
            // 让x结点的父结点指向minNode
            x = minNode;
            return x;
        }
    }

    // 找出整个树中最小的键
    public Key getMin() {
        return min(root).key;
    }

    // 找到指定树x中最小值的键所在的结点
    private Node min(Node x) {
        if (x.left != null) {
            return min(x.left);
        } else {
            return x;
        }
    }

    // 找出整个树中最大的键
    public Key getMax() {
        return max(root).key;
    }

    // 找到指定树x中最大值的键所在的结点
    private Node max(Node x) {
        if (x.right != null) {
            return max(x.right);
        } else {
            return x;
        }
    }

    // 获取整个树中所有的键(采用先序遍历)
    public Queue<Key> preErgodic() {
        Queue<Key> keys = new ConcurrentLinkedQueue<>();
        preErgodic(root, keys);
        return keys;
    }

    private void preErgodic(Node x, Queue<Key> keys) {
        if (x == null) {
            return;
        }
        // 把x结点的key放入到keys中
        keys.offer(x.key);
        // 递归遍历x结点的左子树
        if (x.left != null) {
            preErgodic(x.left, keys);
        }
        // 递归遍历x结点的右子树
        if (x.right != null) {
            preErgodic(x.right, keys);
        }
    }

    // 获取整个树中所有的键(采用先序遍历)
    public Queue<Key> midErgodic() {
        Queue<Key> keys = new ConcurrentLinkedQueue<>();
        midErgodic(root, keys);
        return keys;
    }

    private void midErgodic(Node x, Queue<Key> keys) {
        if (x == null) {
            return;
        }
        // 递归遍历x结点的左子树
        if (x.left != null) {
            midErgodic(x.left, keys);
        }
        // 把x结点的key放入到keys中
        keys.offer(x.key);
        // 递归遍历x结点的右子树
        if (x.right != null) {
            midErgodic(x.right, keys);
        }
    }

    // 获取整个树中所有的键(采用先序遍历)
    public Queue<Key> afterErgodic() {
        Queue<Key> keys = new ConcurrentLinkedQueue<>();
        afterErgodic(root, keys);
        return keys;
    }

    private void afterErgodic(Node x, Queue<Key> keys) {
        if (x == null) {
            return;
        }
        // 递归遍历x结点的左子树
        if (x.left != null) {
            afterErgodic(x.left, keys);
        }
        // 递归遍历x结点的右子树
        if (x.right != null) {
            afterErgodic(x.right, keys);
        }
        // 把x结点的key放入到keys中
        keys.offer(x.key);
    }

}

 

posted @ 2020-05-03 16:29  灰色飘零  阅读(98)  评论(0)    收藏  举报