欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

二叉树汇总

程序员文章站 2022-09-13 22:15:20
根据先序和中序遍历数组采用双队列建树import java.util.concurrent.LinkedBlockingQueue;public class BuildTree { public TreeNode build(int[] preOrder, int[] midOrder) { return buildTree(toQueue(preOrder), toQueue(midOrder)); } private LinkedBlockingQ...

树节点

public class TreeNode {
    public int value;
    public TreeNode leftChild;
    public TreeNode rightChild;
    public TreeNode(int value) {
        this.value = value;
    }
}

根据先序和中序遍历数组采用双队列建树

import java.util.concurrent.LinkedBlockingQueue;

public class BuildTree {

    public TreeNode buildTree(int[] preOrder, int[] midOrder) {
        return buildTree(toQueue(preOrder), toQueue(midOrder));
    }

    private LinkedBlockingQueue<Integer> toQueue(int[] arrays) {//将数组转换成队列
        LinkedBlockingQueue queue = new LinkedBlockingQueue<Integer>();
        for (int a : arrays) {
            queue.add(a);
        }
        return queue;
    }

    //双队列建树
    public TreeNode buildTree(LinkedBlockingQueue<Integer> preOrder, LinkedBlockingQueue<Integer> midOrder) {
        if (preOrder.size() == 0)
            return null;
        TreeNode root = new TreeNode(preOrder.poll());//根据先序遍历依次录入节点
        if (midOrder.size() > 1) {
            LinkedBlockingQueue leftTree = new LinkedBlockingQueue<Integer>();//左子树队列
            LinkedBlockingQueue rightTree = new LinkedBlockingQueue<Integer>();//右子树队列
            boolean flag = true;//true时构建左子树,false时构建右子树
            while (midOrder.size() > 0) {//将当前中序遍历队列拆分成左右子树队列
                if (flag) {
                    int temp;
                    if ((temp = midOrder.poll()) != root.value) {//根据中序遍历判定节点在树中的位置
                        leftTree.add(temp);
                    } else
                        flag = false;
                } else
                    rightTree.add(midOrder.poll());
            }
            if (leftTree.size() != 0)
                root.leftChild = buildTree(preOrder, leftTree);
            if (rightTree.size() != 0)
                root.rightChild = buildTree(preOrder, rightTree);
        }
        return root;
    }
}

关于JAVA中的队列

ArrayBlockingQueue :一个由数组支持的有界队列。
LinkedBlockingQueue :一个由链接节点支持的可选有界队列。
PriorityBlockingQueue :一个由优先级堆支持的*优先级队列。
DelayQueue :一个由优先级堆支持的、基于时间的调度队列。
SynchronousQueue :一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制。

add      增加一个元索               如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove   移除并返回队列头部的元素     如果队列为空,则抛出一个NoSuchElementException异常
element  返回队列头部的元素          如果队列为空,则抛出一个NoSuchElementException异常
offer    添加一个元素并返回true      如果队列已满,则返回false
poll     移除并返问队列头部的元素     如果队列为空,则返回null
peek     返回队列头部的元素          如果队列为空,则返回null
put      添加一个元素                如果队列满,则阻塞
take     移除并返回队列头部的元素     如果队列为空,则阻塞

求二叉树最大深度与最小深度

    public int getMaxDepth(TreeNode node) {//求二叉树最大深度
        if (node == null) {
            return 0;
        }
        int left = getMaxDepth(node.leftChild);
        int right = getMaxDepth(node.rightChild);
        return 1 + Math.max(left, right);
    }

    public int getMinDepth(TreeNode node) {//求二叉树最小深度
        if (node == null) {//首先判断根节点
            return 0;
        }
        return getMinD(node);
    }

    private int getMinD(TreeNode node) {
        if (node == null) {//空节点置为最大值,防止加入到计算中
            return Integer.MAX_VALUE;
        }
        if (node.leftChild == null && node.rightChild == null) {
            return 1;
        }
        int left = getMinD(node.leftChild);
        int right = getMinD(node.rightChild);
        return Math.min(left, right)+1;
    }

判断平衡二叉树

    public boolean isBalanced(TreeNode node) {//判断平衡二叉树
        if (node == null) {
            return true;
        }
        /*两个条件:
        1、左子树与右子树深度之差小于1
        2、左子树与右子树均为平衡二叉树
         */
        if (Math.abs(getMaxDepth(node.leftChild) - getMaxDepth(node.rightChild)) <= 1) {
            return isBalanced(node.leftChild)&&isBalanced(node.rightChild);
        }
        return false;
    }

    public int getMaxDepth(TreeNode node) {//求二叉树最大深度
        if (node == null) {
            return 0;
        }
        int left = getMaxDepth(node.leftChild);
        int right = getMaxDepth(node.rightChild);
        return 1 + Math.max(left, right);
    }

从根节点寻找和为指定值的路径

    public LinkedList<LinkedList<TreeNode>> findPath(int req, TreeNode root) {
        if (root == null) {
            return null;
        }
        LinkedList path=new LinkedList();//存储当前路径
        LinkedList pathSet=new LinkedList();//存储所有符合条件的路径集合
        findPath(req, 0, path, pathSet, root);
        return pathSet;
    }
    private void findPath(int req,int sum, LinkedList path, LinkedList pathSet,TreeNode root) {
        if (root == null) {
            return;
        }
        path.add(root);
        sum+=root.value;
        //符合路径的判定条件:1、终点为叶子节点。2、路径值为指定的值。
        if (root.leftChild == null && root.rightChild == null) {
            if (sum == req) {
                pathSet.add(new LinkedList<TreeNode>(path));//符合条件的路径需要复制存储以免被返回时删除
            }
        } else {
            findPath(req, sum, path, pathSet, root.leftChild);
            findPath(req, sum, path, pathSet, root.rightChild);
        }
        sum-=root.value;
        path.removeLast();//每次递归结束删除当前路径中末尾节点
    }

先序、中序和后序遍历

    public void preOrder(TreeNode node, ArrayList traverse) {//先序
        if (node == null) {
            return;
        }
        traverse.add(node.value);
        preOrder(node.leftChild, traverse);
        preOrder(node.rightChild, traverse);
    }

    public void midOrder(TreeNode node, ArrayList traverse) {//中序
        if (node == null) {
            return;
        }
        midOrder(node.leftChild, traverse);
        traverse.add(node.value);
        midOrder(node.rightChild, traverse);
    }

    public void postOrder(TreeNode node, ArrayList traverse) {//后序
        if (node == null) {
            return;
        }
        postOrder(node.leftChild, traverse);
        postOrder(node.rightChild, traverse);
        traverse.add(node.value);
    }

从上至下打印二叉树

    public void printUptodown(TreeNode root) {
    //利用队列机制,将队首元素取出打印并将其子节点加入到队尾
        LinkedBlockingQueue<TreeNode> queue=new LinkedBlockingQueue();
        queue.add(root);
        TreeNode node;
        while (queue.size() != 0) {
            node=queue.poll();
            System.out.print(node.value+" ");
            if (node.leftChild != null) {
                queue.add(node.leftChild);
            }
            if (node.rightChild != null) {
                queue.add(node.rightChild);
            }
        }
    }

从上至下按层次打印二叉树

    public void printUptodown2(TreeNode root) {
        LinkedBlockingQueue<TreeNode> queue=new LinkedBlockingQueue();
        queue.add(root);
        TreeNode node;
        int current=1;//当前层需打印节点数
        int nextLevel=0;//下一层需打印节点数
        while (queue.size() != 0) {
            node=queue.poll();
            System.out.print(node.value+" ");
            //当前层所有节点的子节点数=下一层需打印节点数
            if (node.leftChild != null) {
                queue.add(node.leftChild);
                nextLevel++;
            }
            if (node.rightChild != null) {
                queue.add(node.rightChild);
                nextLevel++;
            }
            if (--current == 0) {
                System.out.println();
                current=nextLevel;
                nextLevel=0;
            }
        }
    }

从上至下按Z字形打印二叉树

public void printUptodown3(TreeNode root) {
        Deque<TreeNode> deque=new LinkedList();//双端队列,两头可进可出
        deque.addFirst(root);
        int current=1;
        int nextLevel=0;
        boolean flag=true;//打印方向标,true为从左至右,false为从右至左
        TreeNode node;
        while (deque.size()>0){
            if (flag) {//从左至右打印
                node=deque.pollFirst();//从头结点取元素
                System.out.print(node.value+" ");
                if (node.leftChild != null) {//左子树优先!
                    deque.addLast(node.leftChild);//从尾结点加元素
                    nextLevel++;
                }
                if (node.rightChild != null) {
                    deque.addLast(node.rightChild);
                    nextLevel++;
                }
            }
            else {//从右至左打印
                node=deque.pollLast();//从尾结点取元素
                System.out.print(node.value+" ");
                if (node.rightChild != null) {//右子树优先!
                    deque.addFirst(node.rightChild);//从头结点加元素
                    nextLevel++;
                }
                if (node.leftChild != null) {
                    deque.addFirst(node.leftChild);
                    nextLevel++;
                }
            }
            if (--current == 0) {
                flag=!flag;
                System.out.println();
                current=nextLevel;
                nextLevel=0;
            }
        }

    }

双端队列Deque

ArrayDeque:大小可变数组的实现。数组双端队列没有容量限制;可根据需要增加以支持使用。不是线程安全的;禁止 null 元素。
LinkedBlockingDeque:一个基于已链接节点的、任选范围的阻塞双端队列。 
LinkedList:List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。

头部:
addFirst      头部增加一个元索               如果队列已满,则抛出一个IIIegaISlabEepeplian异常
removeFirst   移除并返回队列头部的元素        如果队列为空,则抛出一个NoSuchElementException异常
getFirst      返回队列头部的元素              如果队列为空,则抛出一个NoSuchElementException异常
offerFirst    头部添加一个元素并返回true      如果队列已满,则返回false
pollFirst     移除并返问队列头部的元素        如果队列为空,则返回null
peekFirst     返回队列头部的元素             如果队列为空,则返回null
尾部:
addLast      尾部增加一个元索               如果队列已满,则抛出一个IIIegaISlabEepeplian异常
removeLast   移除并返回队列尾部的元素        如果队列为空,则抛出一个NoSuchElementException异常
getLast      返回队列尾部的元素             如果队列为空,则抛出一个NoSuchElementException异常
offerLast    尾部添加一个元素并返回true      如果队列已满,则返回false
pollLast     移除并返问队列尾部的元素        如果队列为空,则返回null
peekLast     返回队列尾部的元素              如果队列为空,则返回null

 

本文地址:https://blog.csdn.net/qq_29110265/article/details/107150628