二叉树的操作-java

二叉树

TreeNode定义:

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
中序遍历

左子树——根——右子树的顺序

public void inOrder(TreeNode r) {
        if (r != null) {
            inOrder(r.left);
            System.out.println(x.key);
            inOrder(r.right);
        }
    }
层次遍历

意思是:从上到下按层次访问该二叉树(每一层单独输出一行)

    public static void levelOrder(TreeNode r) {
        Queue<TreeNode> q = new ArrayDeque<TreeNode>();
        q.add(r);
        while(!q.isEmpty()) {
            TreeNode tmp = q.poll();
            System.out.println(tmp.val);
            if (tmp.left != null) {
                q.add(tmp.left);
            }
            if (tmp.right != null) {
                q.add(tmp.right);
            }
        }
    }
求树高
public static int depth(TreeNode root) {
        if (r == null)
            return 0;
        int l = depth(root.left);
        int r = depth(root.right);
        return (l > r ? l : r) + 1;
    }
总结点数
public static int nodeNumbers(TreeNode r) {
        if (r == null)
            return 0;
        return nodeNumbers(r.left) + nodeNumbers(r.right) + 1;
    }
叶结点数
public static int leafNumbers(TreeNode r) {
        if (r == null)
            return 0;
        if (r.left == null && r.right == null) {
            return 1;
        }
        return leafNumbers(r.left) + leafNumbers(r.right) + 1;
    }
判断二叉排序树
public static boolean isBST(TreeNode root) {
        return isBST(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
    }
    public static boolean isBST(TreeNode root, int left, int right) {
        if(root == null) return true;
        return (left < root.val && root.val < right && isBST(root.left, left ,root.val) && isBST(root.right, root.val, right));
    }
求二叉树的最长距离

对于二叉树,若要两个节点U,V相距最远,有两种情况:
1,从U节点到V节点之间的路径经过根节点
2,从U节点到V节点之间的路径不经过根节点,这种情况下,U,V节点必定在根节点的左子树或者右子树上,
这样就转化为求以根节点的孩子节点为根节点的二叉树中最远的两个节点间的距离
上面所说的经过根节点,是指路径中包含根节点,例如:假如上图中只有左子树FGHA,
那么最长距离的两个节点是F, A,该路径中包含根节点F,也称为经过根节点。

/*
     * 思想就是使用动态规划的方式每次求得节点左右子树的最大路径长度,
     * 分别记录在leftLen与rightLen中,这样就记录了每个节点左右分支的最大深度
     * 后序,dfs
     */
    public int findMaxLen2(TreeNode root) {
        if(root == null) {
            return 0;  
        }
        if(root.left != null)  
        {  
            root.leftMaxValue = findMaxLen2(root.left) + 1;  
        } else {  
            root.leftMaxValue = 0;  
        }  
        if(root.right != null)  
        {  
            root.rightMaxValue = findMaxLen2(root.right) + 1;  
        } else {  
            root.rightMaxValue = 0;  
        }  
        maxLen = Math.max(maxLen, root.leftMaxValue + root.rightMaxValue);  
        return root.rightMaxValue > root.leftMaxValue ? root.rightMaxValue : root.leftMaxValue;  
    }
求二叉树宽度

就是层次遍历。在上一层遍历完成后,下一层的所有节点已经放到队列中,此时队列中的元素个数就是下一层的宽度。以此类推,依次遍历下一层即可求出二叉树的最大宽度。

public static int levelOrder(TreeNode r) {
        if (r == null) {
            return 0;
        }
        Queue<TreeNode> q = new ArrayDeque<TreeNode>();
        int maxWidth = 1;
        q.add(r);
        while(!q.isEmpty()) {
            int size = q.size();
            while (size > 0) {
                TreeNode tmp = q.poll();
                if (tmp.left != null) {
                    q.add(tmp.left);
                }
                if (tmp.right != null) {
                    q.add(tmp.right);
                }
                size--;
            }
            maxWidth = Math.max(maxWidth, q.size());
        }
        return maxWidth;
    }
打印二叉树两个叶子节点之间的路径

最近公共祖先
第一遍从节点1开始回溯到根,第二遍从节点2回溯到visited为true的点(temp2.father为公共祖先)。用stack保存第二遍回溯的结果以便输出
再遍历一遍输出就行了

public static void printPath(TreeNode leaf1, TreeNode leaf2) {
        Stack<Integer> stack = new Stack<Integer>();
        TreeNode temp1 = leaf1;
        temp1.visited = true;
        while (temp1.father != null) {
            temp1 = temp1.father;
            temp1.visited = true;
        }
        TreeNode temp2 = leaf2;
        temp2.visited = true;
        while (!temp2.father.visited) { // temp2.father为公共祖先
            stack.add(temp2.val);
            temp2 = temp2.father;
            temp2.visited = true;
        }
        print(leaf1, temp2, stack);
    }
    public static void print(TreeNode temp1, TreeNode temp2, Stack<Integer> stack) {
        while (temp1.father != temp2.father) {
            System.out.println(temp1.val);
            temp1 = temp1.father;
            temp1.visited = true;
        }
        System.out.println(temp1.father.val);
        while (!stack.isEmpty()) {
            System.out.println(stack.pop());
        }
    }
public class TreeNode {
    int val;
    boolean visited;
    TreeNode left;
    TreeNode right;
    TreeNode father;
    public TreeNode (int val) {
        this.val = val;
    }
}

二叉搜索树

定义:对任何结点,其左子树中的关键字最大不超过x.key,右子树的关键字最小不低于x.key(算法导论)

给定关键字,查找结点
public TreeNode search(TreeNode r,int k) {
        while(r != null && r.key != k) {
            if (k < r.key) {
                r = r.left;
            } else{
                r = r.right;
            }
        }
        return r;
    }
最小关键字和最大关键字
public TreeNode findMinimum(TreeNode x) {
        while (x.left != null) {
            x = x.left;
        }
        return x;
    }
public TreeNode findMaximum(TreeNode x) {
        while(x.right != null){
            x = x.right;
        }
        return x;
    }
后继
public TreeNode successor(TreeNode x) {
        //(1)如果节点右子树非空,则x的后继是x右子树中的最左节点
        if(x.right != null) {
            return findMinimum(x.right);
        }
        //(2)若右子树为空且有一个后继y,则y是x的最底层祖先
        TreeNode y = x.parent;
        while (y != null && x == y.right) {
            x = y;
            y = y.parent;
        }
        return y;
    }
插入结点

注意:插入的点一定在树的最底分支

public TreeNode insert(TreeNode x,TreeNode z) {
        TreeNode y = null;
        TreeNode root = x;
        if (x == null) {
            x = z;//tree T was empty
            return x;
        }
        while(x != null) {
            y = x;    //important step
            if(z.key < y.key) {
                x = x.left;
            }
            else{x = x.right;}
        }
        z.parent = y; // 若TreeNode结构无parent,直接删去此行即可
        if(z.key < y.key){
            y.left = z;
        }
        else{
            y.right = z;
        }       
        return root;
    }
删除结点

定义子过程transplant,完成用另一个子树替换子树并成为双亲的孩子节点
用一个以v为根的子树替换以u为根的子树,u的双亲变为v的双亲,v成为u的双亲的相应孩子

public void transplant(TreeNode r,TreeNode u,TreeNode v) {
        if (u.parent == null) {
            r = v;
        }
        else if (u == u.parent.left) {
            u.parent.left = v;
        }
        else {
            u.parent.right = v;
        }
        if (v != null) {
            v.parent = u.parent;
        }
    }
    public void delete(TreeNode r,TreeNode z) {
        if (z.left == null) {
            transplant(r, z, z.right);
        }
        else if (z.right == null) {
            transplant(r, z, z.left);
        }
        else{
            TreeNode y = findMinimum(z.right);
            if (y.parent != z) {
                transplant(r, y, y.right);
                y.right = z.right;
                y.right.parent = y;
            }
            transplant(r,z,y);
            y.left = z.left;
            y.left.parent = y;
        }
    }
合并两个排序二叉树

很容易想到把一颗树的每一个结点依次添加到另一颗树中,每次插入的平均时间复杂度为O(logn),在最坏情况下的插入时间复杂度为O(m + logn)。合并为一棵树的平均时间复杂度为O(mlog(m + n))。
第二种思路:先将二叉树转为链表,合并链表之后,再将链表转为二叉树

转二叉树为双向链表:
TreeNode change(TreeNode root) {
    if (root == null) {
        return null;
    }
    //转换左子树,连接到根节点
    if (root.left != null) {
        TreeNode left = change(root.left);
        for(;left.right != null; left =left.right);

        left.right = root;
        root.left =left;
    }
    //转换右子树,根节点连接到右子树
    if (root.right!= null) {
        TreeNode right= change(root.right);
        for(;left.left!= null; right=right.left);

        right.left = root;
        root.right=right;
    }
    return root;
}



需要o(1)空间的方法:
public TreeNode prev = null;
    // 按中序(左中右)顺序转二叉树为list(适合二叉搜索树,根为4,结果:1234567)
        public void BSTtoList(TreeNode root) {
        if (root == null) {
            return;
        }
        BSTtoList(root.left);
        if (prev != null) {
            prev.right = root;
            prev.left = null;
        }
        prev = root;
        BSTtoList(root.right);
    }
    // 前序(根左右)转二叉树为list,根为1,结果:1234567
    /*树:
       1
     2   5
    3 4 6 7
    */
    public void flatten(TreeNode root) {
        if (root == null)
            return;
        flatten(root.right);
        flatten(root.left);
        root.right = prev;
        root.left = null;
        prev = root;
    }
链表转二叉树(leetcode 109):
方法1:(in place)
public TreeNode LinkedListToBalancedBST(TreeNode root) {
        int num = 0;
        TreeNode r = root;
        while (r != null) {
            num++;
            r = r.right;
        }
        return ListToBST(root, num);
    }
    public TreeNode cur = null;
    public TreeNode ListToBST(TreeNode root, int num) {
        if (num <= 0) return null;
        if (cur == null) cur = root;
        TreeNode left = ListToBST(root, num / 2);
        TreeNode temp = cur;
        cur = cur.right;
        temp.right = ListToBST(cur, num - 1 - num / 2);
        temp.left = left;
        return temp;
    }

方法2:
private ListNode node;

public TreeNode sortedListToBST(ListNode head) {
    if(head == null){
        return null;
    }

    int size = 0;
    ListNode runner = head;
    node = head;

    while(runner != null){
        runner = runner.next;
        size ++;
    }

    return inorderHelper(0, size - 1);
}

public TreeNode inorderHelper(int start, int end){
    if(start > end){
        return null;
    }

    int mid = start + (end - start) / 2;
    TreeNode left = inorderHelper(start, mid - 1);

    TreeNode treenode = new TreeNode(node.val);
    treenode.left = left;
    node = node.next;

    TreeNode right = inorderHelper(mid + 1, end);
    treenode.right = right;

    return treenode;
}
方法3:
public TreeNode sortedListToBST(ListNode head) {  
    if(head==null) return null;  
    return toBST(head,null);  
}  
public TreeNode toBST(ListNode head, ListNode tail){  
    ListNode slow = head;  
    ListNode fast = head;  
    if(head==tail) return null;  

    while(fast!=tail&&fast.next!=tail){  
        fast = fast.next.next;  
        slow = slow.next;  
    }  
    TreeNode thead = new TreeNode(slow.val);  
    thead.left = toBST(head,slow);  
    thead.right = toBST(slow.next,tail);  
    return thead;  
}  

参考链接:
http://www.cnblogs.com/shinning/p/6243503.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值