二叉树前序、中序、后续的递归和非递归实现

源码地址:https://gitee.com/zjtMeng/data_structure

一、什么是二叉树

二叉排序树又叫二叉查找树或者二叉搜索树,它首先是一个二叉树,而且必须满足下面的条件:

1)若左子树不空,则左子树上所有结点的值均小于它的根节点的值;

2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值

3)左、右子树也分别为二叉排序树

二、创建二叉树

1.首先创建树节点

树节点包含4个信息:键值、数据域和两个指针域。

public class Node {

    //键值(存放索引)
    public long value;
    //数据域(存储数据)
    public String sData;
    //指针域
    public Node leftNode;
    //指针域
    public Node rightNode;

    public Node(long value, String sData) {
        this.value = value;
        this.sData = sData;
    }
}

2.开始创建二叉树

public class Tree {

    public Node root;

    //待补充方法
}

1.插入方法

    public void insert(long value, String string){

        Node newNode = new Node(value,string);

        Node current = root;

        Node parent;

        if (root == null){
            root = newNode;
        }
        else {
            while (true){
                parent = current;
                if (current.value > value){
                    current = current.leftNode;
                    if (current ==null){
                        parent.leftNode = newNode;
                        return;
                    }
                }
                else {
                    current = current.rightNode;
                    if (current==null){
                        parent.rightNode = newNode;
                        return;
                    }
                }
            }
        }
    }

2.查找指定索引的树节点

 public Node find(long value){

        Node current = root;

        while (current.value != value){
            if (current.value > value){
                current =current.leftNode;
            }
            else {
                current = current.rightNode;
            }
            if (current == null){
                return null;
            }
        }
        return current;
    }

3.1 遍历——前序遍历(根节点最前遍历,即根、左、右)

前序遍历的规则:(1)访问根节点

                             (2)前序遍历左子树

                             (3)前序遍历右子树

前序遍历:只要当前树节点存在左子树,就优先遍历左子树,直到没有当前节点不存在左子树,这时候才开始遍历右子树,在二叉树为空的时候,结束返回。。如图所示二叉树:

前序遍历结果为:ABDECF

递归方法:

    public void frontOrder(Node localNode){
        if (localNode != null){
            System.out.println(localNode.value+", "+localNode.sData);

            frontOrder(localNode.leftNode);

            frontOrder(localNode.rightNode);
        }
    }

非递归方法:通过栈来存放

   public void preOrder(Node localNode){
        Stack<Node> stack = new Stack<>();
        while (localNode != null || !stack.empty()){

            while (localNode != null){
                System.out.println(localNode.sData + "");
                stack.push(localNode);
                localNode = localNode.leftNode;
            }
            //切换到右节点
            if (!stack.empty()){
                localNode = stack.pop();
                localNode = localNode.rightNode;
            }
        }
    }

3.2 遍历——中序遍历(根节点中间遍历,即左、根、右)

中序遍历的规则:

(1)中序遍历左子树

(2)访问根节点

(3)中序遍历右子树

中序遍历:中序遍历返回的节点是有序的,遍历可以记为左根右,也就是说在二叉树的遍历过程中,首先要遍历二叉树的左子树,接着遍历根节点,最后遍历右子树,在二叉树为空的时候,结束返回。如图所示二叉树:

中序遍历结果为:DBEAFC  (可以理解D<B<E<A<F<C

递归方法

    public void inOrder(Node localNode){

        if (localNode !=null) {
            //中序遍历左子树
            inOrder(localNode.leftNode);

            //访问根节点
            System.out.println(localNode.value+", "+localNode.sData);

            //中序遍历右子树
            inOrder(localNode.rightNode);
        }
    }

非递归方法

public void midOrder(Node localNode){
        Stack<Node> stack = new Stack<>();
        while (localNode != null || !stack.empty()){
            while (localNode != null){
                stack.push(localNode);
                localNode = localNode.leftNode;
            }
            if (!stack.empty()){
                localNode = stack.pop();
                System.out.println(localNode.sData + "");
                localNode = localNode.rightNode;
            }
        }
    }

3.3 遍历——后序遍历(根节点最后遍历,即左、右、根)

后序遍历二叉树的规则:

(1)后序遍历左子树

(2)后序遍历右子树

(3)访问根节点

后序遍历:反推可以得出树的结构,后序遍历可以记为左右根,也就是说在二叉树的遍历过程中,首先按照后序遍历的规则遍历左子树,接着按照后序遍历的规则遍历右子树,最后访问根节点。在二叉树为空的时候,结束返回。如图所示二叉树:

中序遍历结果为:DEBFCA

递归遍历:

   /*
* 后序遍历(反推可以得出树的结构)
*/
    public void afterOrder(Node localNode) {
        if (localNode != null) {
            //后序遍历左子树
            afterOrder(localNode.leftNode);
            //后序遍历右子树
            afterOrder(localNode.rightNode);
            //访问根节点
            System.out.println(localNode.value+", "+localNode.sData);

        }
    }

非递归遍历

    public void posOrder(Node localNode)
    {
        Stack<Node> stack1 = new Stack<>();
        Stack<Integer> stack2 = new Stack<>();
        int i = 1;
        while(localNode != null || !stack1.empty())
        {
            while (localNode != null)
            {
                stack1.push(localNode);
                stack2.push(0);
                localNode = localNode.leftNode;
            }

            while(!stack1.empty() && stack2.peek() == i)
            {
                stack2.pop();
                System.out.print(stack1.pop().sData + "   ");
            }

            if(!stack1.empty())
            {
                stack2.pop();
                stack2.push(1);
                localNode = stack1.peek();
                localNode = localNode.rightNode;
            }
        }
    }

三种递归遍历的效果:

4. 获取中序后继节点

这是当删除节点的两个子节点都存在时,需要用的中序后继方法。

    //获取中序后继节点
    public Node getSubNode(Node delNode) {
        Node subNode = delNode;
        //中序后继节点的父节点
        Node subParent = delNode;

        Node current = delNode.rightNode;
        while (current !=null) {
            subParent = subNode;
            subNode = current;
            current = current.leftNode;
        }
        if (subNode != delNode.rightNode) {
            subParent.leftNode = subNode.rightNode;
            subNode.rightNode = delNode.rightNode;
        }
        return subNode;
    }

5. 删除树节点

/*
	 * 删除节点
	 */
    public boolean delete(long value) {
        //引用当前节点
        Node current = root;
        //引用当前节点的父节点
        Node parent = root;
        //判断是否是左子节点
        boolean isLeftNode = true;
        //循环,只要查找值value不等于当前节点的数据项data,就继续循环,直至找到位置或者遍历完所有节点
        while (current.value != value) {
            parent = current;
            //进行比较,查找当前值和当前节点的大小
            if (current.value >value) {
                current = current.leftNode;
                isLeftNode = true;
            }
            else {
                current = current.rightNode;
                isLeftNode = false;
            }
            //如果查不到,则返回false
            if (current == null) {
                return false;
            }
        }
        //删除叶子节点,即该节点没有子节点
        if (current.leftNode ==null && current.rightNode == null) {
            if (current == root) {
                root = null;
            }
            //如果它是父节点的子节点
            else if (isLeftNode) {
                parent.leftNode = null;
            }
            else {
                parent.rightNode = null;
            }
        }
        //如果该节点有一个左节点
        else if (current.rightNode == null) {
            if (current == root) {
                root = current.leftNode;
            }

            else if (isLeftNode) {
                parent.leftNode = current.leftNode;
            }else {
                parent.rightNode = current.leftNode;
            }
        }
        //如果该节点有一个右节点
        else if (current.leftNode == null) {
            if (current == root ) {
                root = current.leftNode;
            }
            else if (isLeftNode) {
                parent.leftNode = current.rightNode;
            }else {
                parent.leftNode = current.rightNode;
            }
        }
        //如果该节点有左节点和右节点
        else{
            Node subNode = getSubNode(current);
            if (current == root) {
                root = subNode;
            }else if (isLeftNode) {
                parent.leftNode = subNode;
            }else {
                parent.rightNode = subNode;
            }
            subNode.leftNode = current.leftNode;
        }
        return true;
    }

猜你喜欢

转载自blog.csdn.net/zjt980452483/article/details/82414329