二叉树

目录

1、搜索方式:

2、BST搜索二叉树:

3、从左边看过去的所有元素:

4、二叉树两个节点最近的祖先

5、判断是不是BST树

6、AVL平衡树

7、红黑树:

8、完全二叉树

9、求根节点到叶子节点的最短路径的节点个数

10、根到叶节点数字之和

11、二叉树序列化和反序列化


1、搜索方式:

前序遍历:先访问根节点,再访问左子节点,最后访问右子节点

中序遍历:先访问左子节点,再访问根节点,最后访问右子节点

中序遍历:先访问左子节点,再访问根节点,最后访问右子节点

深度优先遍历(DFS):从根节点出发,沿着左子树方向进行纵向遍历,直到找到叶子节点为止。然后回溯到前一个节点,进行右子树节点的遍历,直到遍历完所有可达节点为止。

广度优先遍历(BFS):从根节点出发,在横向遍历二叉树层段节点的基础上纵向遍历二叉树的层次。

DFS实现:【栈】父节点入栈,父节点出栈,先右子节点入栈,后左子节点入栈。(也可以用递归,递归就是栈)

void dfs(TreeNode root) {
    if (root == null) {
        return;
    }
    dfs(root.left);
    dfs(root.right);
}

BFS实现:【队列】父节点入队,父节点出队列,先左子节点入队,后右子节点入队。

void bfs(TreeNode root) {
    Queue<TreeNode> queue = new ArrayDeque<>();
    queue.add(root);
    while (!queue.isEmpty()) {
        TreeNode node = queue.poll(); // Java 的 pop 写作 poll()
        if (node.left != null) {
            queue.add(node.left);
        }
        if (node.right != null) {
            queue.add(node.right);
        }
    }
}

2、BST搜索二叉树:

#include <iostream>

using namespace std;

struct BiTree {
    int data;
    BiTree *lchild;
    BiTree *rchild;
};

BiTree* InsertBST(BiTree *t,int key) {
    if (t == NULL) {
        t = new BiTree();
        t->lchild = t->rchild = NULL;
        t->data = key;
        return t;
    }
    if (key < t->data)
        t->lchild = InsertBST(t->lchild, key);
    else
        t->rchild = InsertBST(t->rchild, key);
    return t;
}

BiTree* CreateBiTree(BiTree *tree, int d[], int n) {
    for (int i = 0; i < n; i++)
        tree = InsertBST(tree, d[i]);
    return tree;
}

void PrintBST(BiTree *t) {
    if (t == NULL) {
        cout << "null tree";
    }
    if (t->lchild != NULL) {
        PrintBST(t->lchild);
    }
    cout << t->data << ", ";
    if (t->rchild != NULL) {
        PrintBST(t->rchild);
    }
}

void PrePrintBST(BiTree *t) {
    if (t == NULL) {
        cout << "null tree";
    }
    cout << t->data << ", ";
    if (t->lchild != NULL) {
        PrePrintBST(t->lchild);
    }
    if (t->rchild != NULL) {
        PrePrintBST(t->rchild);
    }
}

void AfterPrintBST(BiTree *t) {
    if (t == NULL) {
        cout << "null tree";
    }
    if (t->lchild != NULL) {
        AfterPrintBST(t->lchild);
    }
    if (t->rchild != NULL) {
        AfterPrintBST(t->rchild);
    }
    cout << t->data << ", ";
}

void MidPrintBST(BiTree *t) {
    if (t == NULL) {
        cout << "null tree";
    }
    if (t->lchild != NULL) {
        MidPrintBST(t->lchild);
    }
    cout << t->data << ", ";
    if (t->rchild != NULL) {
        MidPrintBST(t->rchild);
    }
}

int main() {
    BiTree *root = NULL;
    int d[7] = {6,8,1,5,4,3,9};
    root = CreateBiTree(root, d, 7);
    PrintBST(root);
    cout << endl;
    PrePrintBST(root);
    cout << endl;
    AfterPrintBST(root);
    cout << endl;
    MidPrintBST(root);
    cout << endl;
}
结果:
1, 3, 4, 5, 6, 8, 9,
6, 1, 5, 4, 3, 8, 9,
3, 4, 5, 1, 9, 8, 6,
1, 3, 4, 5, 6, 8, 9,

中序遍历就是排序结果

3、从左边看过去的所有元素:

void PrintLeftLookSide(BiTree *t, int depth, int res[]) {
    if (t == NULL) {
        cout << "null tree";
    }
    if (res[1] < depth) {
        res[0] = t->data;
        res[1] = depth;
        cout << res[0] << ", ";
    }
    if (t->lchild != NULL) {
        PrintLeftLookSide(t->lchild, depth+1, res);
    }
    if (t->rchild != NULL) {
        PrintLeftLookSide(t->rchild, depth+1, res);
    }
}

int main() {
    BiTree *root = NULL;
    int d[10] = {5,9,2,1,4,7,8,6,3,6};
    int res[2] = {0,0};  存深度和节点数据
    root = CreateBiTree(root, d, 10);
    PrintLeftLookSide(root, 1, res);  从深度为1开始搜
}
结果:
5, 2, 1, 3, 6,

打印的地方先看左边元素,如果有就就打印,如果没有就递归右子树,总之打印位置就是当前深度的最左树。从右边看就交换一下

4、二叉树两个节点最近的祖先

【解答】:后序遍历递归+DFS

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
         当越过叶节点,则直接返回 null
         当 root 等于 p, q,则直接返回 root
        if (root == null || root == p || root == q) {
            return root;
        }
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);

         当left和right同时为空:说明root的左/右子树中都不包含p,q,返回null
         当left和right同时不为空:说明p, q分列在root的 异侧 (分别在左/右子树),因此root为最近公共祖先,返回root
         当left为空,right不为空p,q都不在root的左子树中,直接返回right。具体可分为两种情况:
             p,q其中一个在root的右子树中,此时right指向 p(假设为p)
             p,q两节点都在root的右子树中,此时的right指向最近公共祖先节点
         当left不为空,right为空:与情况3.同理

         这段代码可以做一些合并,但是可读性就会变差
        if (left == null && right == null) {
            return null;
        } else if (left != null && right != null) {
            return root;
        } else if (left == null && right != null) {
            return right;
        } else {
            return left;
        }
    }
}

5、判断是不是BST树

题意:判断一棵树是不是BST树。即判断一棵树的左节点是否全比根节点小,所有右节点是否全比根节点大。 
思路一:最直接的方法是用中序遍历,发现不是有序的就不是BST,如果是有序那就是BST。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        List<Integer> out = new ArrayList<Integer>();
        MidSort(root, out);
        for (int i = 1; i < out.size(); i++) {
            if (out.get(i-1) >= out.get(i)) {
                return false;
            }
        }
        return true;
    }
    
    public void MidSort(TreeNode root, List<Integer> out) {
        if (root.left != null) {
            MidSort(root.left, out);
        }
        out.add(Integer.valueOf(root.val));
        if (root.right != null) {
            MidSort(root.right, out);
        }
    }
}

6、AVL平衡树

左旋转
右旋转

 

7、红黑树:

性质1、节点是红色或黑色。

性质2、根节点是黑色。

性质3、每个叶节点(NIL节点,空节点)是黑色的。

性质4、每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

性质5、从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

默认插入元素为红色

8、完全二叉树

  • 从作为第一层的根开始,除了最后一层之外,第N层的元素个数都必须是2的N次方;第一层一个元素,第二层4个,第三层8个,以此类推。
  • 而最后一行的元素,都要紧贴在左边,换句话说,每一行的元素都从最左边开始安放,两个元素之间不能有空闲,具备了这两个特点的树,就是一棵完全二叉树。

9、求根节点到叶子节点的最短路径的节点个数

1、没有根节点,那结果就是0 
2、有根节点,没有左右子树,结果为1 
3、没有左子树,有右子树。把右子树看成一棵新的树,用子问题求解。 
4、没有右子树,有左子树。把左子树看成一棵新的树,用子问题求解 
5、既有左子树,又有右子树。那就把左右子树分别都看成新的树,最后比较谁的最近叶子的路径短,就取哪边。 
因为都把左右子树看成新的树了,所以每一棵树都可以用2-3-4-5来判断找出最近叶子的最短路径。 每一棵树都调用这个判断的方法,所以就是递归

10、根到叶节点数字之和

For example,

      1
     / \
    2   3
The root-to-leaf path1->2represents the number12.
The root-to-leaf path1->3represents the number13.
Return the sum = 12 + 13 =25.

中序思想

int sumTree(BiTree *t, int sum) {
    if (t == NULL) {
        return 0;
    }
    sum = sum * 10 + t->data;
    if (t->lchild == NULL && t->rchild == NULL) {
        return sum;
    }
    int lSum = sumTree(t->lchild, sum);
    int rSum = sumTree(t->rchild, sum);
    return lSum + rSum;
}

11、二叉树序列化和反序列化

层序遍历思想,采用队列数据结构

这里注意用StringBuffer不要用String,效率会不一样

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        StringBuffer s = new StringBuffer("");
        if (root == null) {
            return s.toString();
        }
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode front = queue.poll();
            if (front != null) {
                s.append(front.val+"");
                queue.add(front.left);
                queue.add(front.right);
            } else {
                s.append("n");
            }
            s.append(" ");
        }
        return s.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data.equals("")) {
            return null;
        }
        String[] sArr = data.split(" ");
        int i = 0;
        TreeNode root = new TreeNode(Integer.parseInt(sArr[i++]));
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode front = queue.poll();
            if (front == null) {
                continue;
            }
            
            if (sArr[i].equals("n")) {
                front.left = null;
            } else {
                front.left = new TreeNode(Integer.parseInt(sArr[i]));
            }
            
            if (sArr[i+1].equals("n")) {
                front.right = null;
            } else {
                front.right = new TreeNode(Integer.parseInt(sArr[i+1]));
            }
            i += 2;
            queue.add(front.left);
            queue.add(front.right);
        }
        return root;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值