zoukankan      html  css  js  c++  java
  • 二叉树

    • 二叉树的第 (i) 层结点数不多于 (2^{i-1})
    • 深度为 (k) 的二叉树结点数不多于 (2^k-1)

    满二叉树 :指的是深度为 (k) 且含有 (2^k - 1) 个结点的二叉树。
    完全二叉树 :树中所含的 (n) 个结点和满二叉树中编号为 1 至 n 的结点一一对应。

    public class BinaryTree<T> {
    
    	private Node root;
    
    	class Node {
    		T val;
    		Node left;
    		Node right;
    
    		Node(T val) {
    			this.val = val;
    		}
    	}
    }
    

    遍历

    1. 前序遍历

    根 - 左 -右

    // 非递归
    public List<T> preorder() {
    	List<T> res = new LinkedList<>();
    	Stack<Node> stack = new Stack<>();
    	if (root != null)
    		stack.push(root);
    	while (!stack.isEmpty()) {
    		Node node = stack.pop();
    		res.add(node.val);
    		if (node.right != null)			// 栈 先保存 后访问
    			stack.push(node.right);
    		if (node.left != null)
    			stack.push(node.left);
    	}
    	return res;
    }
    
    // 递归
    public void preorder(Node node) {
    	if (node == null)
    		return;
    	System.out.print(node.val + " ");
    	preorder(node.left);
    	preorder(node.right);
    }
    
    2. 中序遍历

    左 - 根 - 右

    // 非递归
    public List<T> inorder() {
    	List<T> res = new LinkedList<>();
    	Stack<Node> stack = new Stack<>();
    	Node node = root;
    	while (!stack.isEmpty() || node != null) {
    		while (node != null) {
    			stack.add(node);
    			node = node.left;
    		}
    		if (!stack.isEmpty()) {
    			node = stack.pop();
    			res.add(node.val);
    			node = node.right;
    		}
    	}
    	return res;
    }
    
    // 递归
    public void inorder(Node node) {
    	if (node == null)
    		return;
    	inorder(node.left);
    	System.out.print(node.val + " ");
    	inorder(node.right);
    }
    
    3. 后序遍历

    左 - 右 - 根

    // 非递归
    // 后序遍历等价于镜像树前序遍历的逆序
    public List<T> postorder() {
    	List<T> res = new LinkedList<>();
    	Stack<Node> stack = new Stack<>();
    	if (root != null)
    		stack.push(root);
    	while (!stack.isEmpty()) {
    		Node node = stack.pop();
    		res.add(node.val);
    		if (node.left != null)
    			stack.push(node.left);
    		if (node.right != null)
    			stack.push(node.right);
    	}
    	Collections.reverse(res);
    	return res;
    }
    
    // 递归
    public void postorder(Node node) {
    	if (node == null)
    		return;
    	postorder(node.left);
    	postorder(node.right);
    	System.out.print(node.val + " ");
    }
    
    4. 层次遍历
    public List<T> level() {
    	List<T> res = new LinkedList<>();
    	Queue<Node> queue = new LinkedList<>();
    	if (root != null)
    		queue.offer(root);
    	while (!queue.isEmpty()) {
    		int num = queue.size();
    		for (int i = 0; i < num; i++) {
    			Node node = queue.poll();
    			res.add(node.val);
    			if (node.left != null)
    				queue.offer(node.left);
    			if (node.right != null)
    				queue.offer(node.right);
    		}
    	}
    	return res;
    }
    

    树高

    public int height(Node node) {
    	if (node == null)
    		return 0;
    	return Math.max(height(node.left), height(node.right)) + 1;
    }
    

    直径

    即树中任两结点间的最长路径。
    一棵二叉树的直径长度是任意两个结点路径长度中的最大值。
    这条路径可能穿过也可能不穿过根结点。

    private int res = 0;
    
    public int diameter(Node root) {
        height(root);
        return res;
    }
    
    private int height(Node node) {
        if (node == null)
            return 0;
        int l = height(node.left);
        int r = height(node.right);
        res = Math.max(res, l + r);
        return Math.max(l, r) + 1;
    }
    

    翻转

    public Node invert(Node node) {
    	if (node == null)
    		return null;
    	Node tmp = invert(node.left);
    	node.left = invert(node.right);
    	node.right = tmp;
    	return node;
    }
    

    对称

    public boolean isSymmetric() {
    	return isSymmetric(root, root);
    }
    
    private boolean isSymmetric(Node n1, Node n2) {
    	if (n1 == null && n2 == null)
    		return true;
    	if (n1 == null || n2 == null)
    		return false;
    	return n1.val == n2.val && isSymmetric(n1.left, n2.right) && isSymmetric(n1.right, n2.left);
    }
    

    森林和二叉树

    将森林中的每一棵树采用二叉链表(孩子-兄弟)法表示,根结点的右子树为空,再将所有树的根结点依次连接起来。

    孩子-兄弟:二叉树结点的左孩子为该结点第一个孩子,右孩子为兄弟结点。

    每棵树的后序遍历等价于二叉树的中序遍历。

    字典树

    Trie,字典树,或称前缀树,用于存储字符串,判断字符串前缀,检索字符串集中的键。如:

    • 自动补全
    • 拼写检查
    • IP路由 最长前缀匹配
    • 九宫格打字预测
    • 单词游戏
    public class Trie {
    
    	private TrieNode root;
    
    	public Trie() {
    		root = new TrieNode();
    	}
    
    	public void insert(String word) {
    		TrieNode node = root;
    		for (int i = 0; i < word.length(); i++) {
    			char currentChar = word.charAt(i);
    			if (!node.containsKey(currentChar)) {
    				node.put(currentChar, new TrieNode());
    			}
    			node = node.get(currentChar);
    		}
    		node.setEnd();
    	}
    
    	private TrieNode searchPrefix(String word) {
    		TrieNode node = root;
    		for (int i = 0; i < word.length(); i++) {
    			char curLetter = word.charAt(i);
    			if (node.containsKey(curLetter)) {
    				node = node.get(curLetter);
    			} else {
    				return null;
    			}
    		}
    		return node;
    	}
    
    	public boolean search(String word) {
    		TrieNode node = searchPrefix(word);
    		return node != null && node.isEnd();
    	}
    
    	public boolean startsWith(String prefix) {
    		TrieNode node = searchPrefix(prefix);
    		return node != null;
    	}
    
    	class TrieNode {
    		// TrieNode 中并不需要保存字符信息
    		// 该结点储存的字符记录在它的父结点中
    		private TrieNode[] links;
    
    		private final int R = 26;	// 26 个小写字母
    
    		private boolean isEnd;		// 是否为一个单词的结尾
    
    		public TrieNode() {
    			links = new TrieNode[R];
    		}
    
    		public boolean containsKey(char ch) {
    			return links[ch - 'a'] != null;
    		}
    
    		public TrieNode get(char ch) {
    			return links[ch - 'a'];
    		}
    
    		public void put(char ch, TrieNode node) {
    			links[ch - 'a'] = node;
    		}
    
    		public void setEnd() {
    			isEnd = true;
    		}
    
    		public boolean isEnd() {
    			return isEnd;
    		}
    	}
    }
    

    哈夫曼树

    哈夫曼编码:根据数据出现的频率对数据进行编码,从而压缩原始数据。

    思路: 贪心策略
    每次选取频率最小的两个结点,生成一个新结点,其频率为这两个结点的和,作为他们的父结点。
    (n) 个结点进行 (n-1) 次选择,生成一棵 (2n-1) 个结点的树。树的叶子结点为数据。

    编码:每个结点的左侧路径标记为 0,右侧路径标记为 1。从根结点出发,到叶结点结束,经过的路径即为该叶子结点的编码。

  • 相关阅读:
    [BZOJ]2589: Spoj 10707 Count on a tree II
    [BZOJ]2434: [Noi2011]阿狸的打字机
    Codeforces Round #408 (Div. 2)
    [BZOJ]2653: middle
    洛谷4月月赛R1
    2017省夏令营Day8
    2017省夏令营Day7
    2017省夏令营Day6
    【20170604校内模拟赛】香蕉
    【20170602模拟赛】秋之国的夏日祭
  • 原文地址:https://www.cnblogs.com/JL916/p/12565450.html
Copyright © 2011-2022 走看看