Java面试-树算法

本文是秋招面试总结,重点讨论了二叉树的构建、遍历、节点查找、序列化、镜像操作等核心算法,涵盖了二叉搜索树、红黑树、平衡二叉树等相关概念,旨在帮助理解二叉树在数据结构和算法中的应用。
摘要由CSDN通过智能技术生成

秋招总结。

二叉树

​ 二叉树是每个结点最多有两个子树的树结构。 一棵深度为k,且有 2^k-1个结点的二叉树,称为满二叉树。这种树的特点是每一层上的结点数都是最大结点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,并且或者最后一层是满的,或者是在右边缺少连续若干结点,则此二叉树为完全二叉树。具有n个结点的完全二叉树的深度为floor(log2n)+1。深度为k的完全二叉树,至少有2^(k-1)个叶子结点,至多有2^k-1个结点。

二叉树的构建以及三种遍历方式
  • 要求:把一个数组的值存入二叉树中,然后进行3种方式的遍历打印。
import java.util.LinkedList;  
import java.util.List;  
  
/** 
 * 功能:把一个数组的值存入二叉树中,然后进行3种方式的遍历 
 * 参考资料0:数据结构(C语言版)严蔚敏 
 * 参考资料1:http://zhidao.baidu.com/question/81938912.html 
 * 参考资料2:http://cslibrary.stanford.edu/110/BinaryTrees.html#java 
 *  
 */  
public class BinTreeTraverse2 {
     
  
    private int[] array = {
    1, 2, 3, 4, 5, 6 };  
    private static List<Node> nodeList = null;  
  
    /** 
     * 内部类:节点 
     */  
    private static class Node {
     
        Node leftChild;  
        Node rightChild;  
        int data;  
  
        Node(int newData) {
     
            leftChild = null;  
            rightChild = null;  
            data = newData;  
        }  
    }  
  
    public void createBinTree() {
     
        nodeList = new LinkedList<Node>();  
        // 将一个数组的值依次转换为Node节点  
        for (int nodeIndex = 0; nodeIndex < array.length; nodeIndex++) {
     
            nodeList.add(new Node(array[nodeIndex]));  
        }  
        // 对前lastParentIndex-1个父节点按照父节点与孩子节点的数字关系建立二叉树  
        for (int parentIndex = 0; parentIndex < array.length / 2 - 1; parentIndex++) {
     
            // 左孩子  
            nodeList.get(parentIndex).leftChild = nodeList  
                    .get(parentIndex * 2 + 1);  
            // 右孩子  
            nodeList.get(parentIndex).rightChild = nodeList  
                    .get(parentIndex * 2 + 2);  
        }  
        // 最后一个父节点:因为最后一个父节点可能没有右孩子,所以单独拿出来处理  
        int lastParentIndex = array.length / 2 - 1;  
        // 左孩子  
        nodeList.get(lastParentIndex).leftChild = nodeList  
                .get(lastParentIndex * 2 + 1);  
        // 右孩子,如果数组的长度为奇数才建立右孩子  
        if (array.length % 2 == 1) {
     
            nodeList.get(lastParentIndex).rightChild = nodeList  
                    .get(lastParentIndex * 2 + 2);  
        }  
    }  
  
    /** 
     * 先序遍历 
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     * @param node 遍历的节点 
     */  
    public static void preOrderTraverse(Node node) {
     
        if (node == null)  
            return;  
        System.out.print(node.data + " ");  
        preOrderTraverse(node.leftChild);  
        preOrderTraverse(node.rightChild);  
    }  
  
    /** 
     * 中序遍历 
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     * @param node 遍历的节点 
     */  
    public static void inOrderTraverse(Node node) {
     
        if (node == null)  
            return;  
        inOrderTraverse(node.leftChild);  
        System.out.print(node.data + " ");  
        inOrderTraverse(node.rightChild);  
    }  
  
    /** 
     * 后序遍历 
     * 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已 
     * @param node 遍历的节点 
     */  
    public static void postOrderTraverse(Node node) {
     
        if (node == null)  
            return;  
        postOrderTraverse(node.leftChild);  
        postOrderTraverse(node.rightChild);  
        System.out.print(node.data + " ");  
    }  
  
    public static void main(String[] args) {
     
        BinTreeTraverse2 binTree = new BinTreeTraverse2();  
        binTree.createBinTree();  
        // nodeList中第0个索引处的值即为根节点  
        Node root = nodeList.get(0);  
  
        System.out.println("先序遍历:");  
        preOrderTraverse(root);  
        System.out.println();  
  
        System.out.println("中序遍历:");  
        inOrderTraverse(root);  
        System.out.println();  
  
        System.out.println("后序遍历:");  
        postOrderTraverse(root);  
    }  
}

运行结果:

先序遍历:
1 2 4 5 3 6 
中序遍历:
4 2 5 1 6 3 
后序遍历:
4 5 2 6 3 1
  • 要求:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
 public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
   
        TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
        return root;
    }
    //前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
    private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {
   
          
        if(startPre>endPre||startIn>endIn)
            return null;
        TreeNode root=new TreeNode(pre[startPre]);
          
        for(int i=startIn;i<=endIn;i++)
            if(in[i]==pre[startPre]){
   
                root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
                root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
            }
                  
        return root;
    }
  • 要求:非递归先序遍历
 public static void preOrder2(Node root)
    {
    // 前序遍历,"根左右"
    	
    	Stack<Node> s = new Stack<Node>();
    	
    	if(root != null)
    	{
   
    		s.push(root);
    		while(!s.isEmpty())
    		{
   
    			Node c = s.pop();
    			System.out.print(c.data + "->");
    			if(c.right != null)
    			{
   
    				s.push(c.right);
    			}
    			if(c.left != null)
    			{
   
    				s.push(c.left);
    			}
    		}
    	}

    }
  • 要求:非递归中序遍历
public void inOrder() {
   
		Node current = root;
		//把LinkedList作为栈使用
		LinkedList<Node> s = new LinkedList<Node>();
		while (current != null || !s.isEmpty()) {
   
			while (current != null) {
   
				s.addFirst(current);
				current = current.left;
			}
			if (!s.isEmpty()) {
   
				current = s.removeFirst();
				System.out.print(current.data + " -> ");
				current = current.right;
			}
		}
	}
  • 要求:后序遍历非递归
 public static void postOrder2(Node root)
    {
    // 后序遍历,"左右根"
    	Stack<Node> s1 = new Stack<Node>();
    	Stack<Node> s2 = new Stack<Node>();
    	
    	if(root != null)
    	{
   
    		s1.push(root);
    		while(!s1.empty())
    		{
   
    			root = s1.pop();
    			s2.push(root);
    			if(root.left != null)
    			{
   
    				s1.push(root.left);
    			}
    			if(root.right != null)
    			{
   
    				s1.push(root.right);
    			}
    		}
    		 while(!s2.empty()) 
    		 {
   
    			 System.out.print(s2.pop().data + "->");
    		 }
    	}
    }
二叉树的打印
  • 要求:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
   
     ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        if(pRoot == null){
   
            return result;
        }
        Queue<TreeNode> layer = new LinkedList<TreeNode>();
        ArrayList<Integer> layerList = new ArrayList<Integer>();
        layer.add(pRoot);
        int start = 0, end = 1;
        while(!layer.isEmpty()){
   
            TreeNode cur = layer.remove();
            layerList.add(cur.val);
            start++;
            if(cur.left!=null){
   
                layer.add(cur.left);           
            }
            if(cur.right!=null){
   
                layer.add(cur.right);
            }
            if(start == end){
   
                end = layer.size();
                start = 0;
                result.add(layerList);
                layerList = new ArrayList<Integer>();
            }
        }
        return result;
    }
  • 要求:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
 public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
   
         ArrayList<Integer> list = new ArrayList<Integer>();
         if(root == null) return list;
         Deque<TreeNode> deque = new LinkedList<TreeNode>();
         
         deque.add(root);
         while(!deque.isEmpty()){
   
             TreeNode t = deque.pop();
             list.add(t.val);
             if(t.left != null) deque.add(t.left);
             if(t.right != null) deque.add(t.right);
         }
         return list;
    }
  • 要求:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
   
  ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
    if (pRoot == null) {
   
        return ret;
    }
    ArrayList<Integer> list = new ArrayList<>();
    LinkedList<TreeNode> queue = new LinkedList<>();
    queue.addLast(null);//层分隔符
    queue.addLast(pRoot);
    boolean leftToRight = true;
     
    while (queue.size() != 1) {
   
        TreeNode node = queue.removeFirst();
        if (node == null) {
   //到达层分隔符
            Iterator<TreeNode> iter = null;
            if (leftToRight) {
   
                iter = queue.iterator();//从前往后遍历
            } else {
   
                iter = queue.descendingIterator();//从后往前遍历
            }
            leftToRight = !leftToRight;
            while (iter.hasNext()) {
   
                TreeNode temp = (TreeNode)iter.next();
                list.add(temp.val);
            }
            ret.add(new ArrayList<Integer>(list));
            list.clear();
            queue.addLast(null);//添加层分隔符
            continue;//一定要continue
        }
        if (node.left != null) {
   
            queue.addLast(node.left);
        }
        if (node.right != null) {
   
            queue.addLast(node.right);
        }
    }
    return ret;
}
二叉树的节点查找
  • 要求:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
public TreeLinkNode GetNext(TreeLinkNode node)
    {
   
          if(node==null)return null;
        if(node.right!=null)
        {
   
            node=node.right;
            while(node.left!=null)
            {
   
                node=node.left;
               
            }return node;
        }
        while(node.next!=null)
        {
   
            if(node.next.left==node)return node.next;
            node
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值