树/二叉树(哈夫曼树/红黑树)笔记

1.是一种常用数据结构,它是非线性结构。

2.树中任一普通节点可以有0或者多个子节点,但只能有一个父节点。

根节点没有父节点,
叶子节点没有子节点。

3.二叉树:

1)每个节点最多只能有两个子树的有序树

2)左边的子树称为左子树

3)右边的子树成为右子树

4)一棵深度为k的二叉树,如果它包含了(2^k-1)个节点,就把这棵二叉树称为满二叉树

4.满二叉树的特点:

1)每一层上的节点数都是最大节点数,即各层为1,2,4,8,16 .... (2^k-1)

2)一棵有n个节点的二叉树,按满二叉树的编号方式对它进行编号,若树中所有节点和满二叉树1~n编号完全一致,则称该树为
完全二叉树

当完全二叉树最后一层的所有节点都是满的时候,这棵完全二叉树就变成了

满二叉树

3)
二叉树的性质:

1.二叉树第i层上的节点数目至多为(2^i-1)

2.深度为k的二叉树,至多有(2^k-1)个节点

3.在任何一棵二叉树中,如果其叶子节点的数量为n0,度为2的子节电数量为n2,则n0=n2+1

4.具有n个节点的完全二叉树的深度为(log2n+1)

5.要实现二叉树这种数据结构,有以下3种选择

1).
顺序存储
        -采用数组来记录二叉树的所有节点

采用顺序存储二叉树会造成一定的空间浪费

不管是遍历树中节点,还是查找树中的节点,都可以非常高效地完成,唯一缺点就是空间浪费很大

2).
二叉链表存储        -每个节点保留一个left,right域

二叉链表存储的思想是让每个节点都能记住它的左右两个子节点

3).
三叉链表存储
        -每个节点保留一个left,right,parent域

为了克服二叉链表存储方式中访问父节点不方便的问题,可以将二叉链表扩展成三叉链表

三叉链表存储的思
想是让每个节点不仅记住它的左右两个子节点,还记住它的父节点

6.遍历二叉树:

对二叉树的遍历过程就是将非线性结构的二叉树中的节点排列在一个线性序列上的过程。

1).如果采用顺序结构来保存二叉树,直接遍历底层数组即可

2).如果采用链表来保存二叉树的节点,则有两类遍历方式:

a)深度优先遍历

这种遍历算法将先访问到树中最深层次的节点

如果L,D,R表示左子树,根,右子树。习惯上总是必须先遍历左子树,然后遍历右子树,根据遍历根节点的顺序不同,算法可以分为:

DLR:
先序遍历

根-左-右

LDR:
中序遍历

左-根-右

LRD:
后序遍历

左-右-根

因为二叉树的定义本身就有"递归性",所以深度优先遍历时能非常方便地利用递归来遍历每个节点:

一棵非空二叉树由树根,左子树,右子树组成,依次遍历这3部分,就可以遍历整个二叉树

b)广度优先遍历

这种遍历算法将逐层访问到每层的节点,先访问到根,然后访问第二层的节点...依此类推

也被称为 按层遍历

可以借助具有FIFO特征的列队来实现

package knowledge;

import java.util.ArrayDeque;

/**
 * 三叉链表存储二叉树
 * @author [email protected]
 * @param <E>
 */
public class ThreeLinkBinTree<E> {

	public static class TreeNode{

		Object data;
		TreeNode left;
		TreeNode right;
		TreeNode parent;

		public TreeNode(){

		}
		public TreeNode(Object data){
			this.data = data;
		}
		public TreeNode(Object data, TreeNode left, TreeNode right, TreeNode parent){
			this.data = data;
			this.left = left;
			this.right = right;
			this.parent = parent;
		}
	}

	//根节点
	private static TreeNode rootNode;

	//以默认的构造器创建二叉树
	public ThreeLinkBinTree(){
		this.rootNode = new TreeNode();
	}

	//指定根元素创建二叉树
	public ThreeLinkBinTree(E data){
		this.rootNode = new TreeNode(data);
	}

	/**
	 * 为指定节点添加子节点
	 * @param parent	需要添加子节点的父节点
	 * @param data		新的子节点数据
	 * @param isLeft	是否为左节点
	 * @return			新增节点
	 */
	public TreeNode addNote(TreeNode parent, E data, boolean isLeft){
		if(parent==null){
			throw new RuntimeException(parent + "节点为null,无法添加子节点");
		}
		if(isLeft && parent.left!=null){
			throw new RuntimeException(parent + "节点已有左子节点,无法添加左子节点");
		}
		if(!isLeft && parent.right!=null){
			throw new RuntimeException(parent + "节点已有右子节点,无法添加右子节点");
		}

		TreeNode newNode = new TreeNode(data);
		if(isLeft){
			parent.left = newNode;
		}else{
			parent.right = newNode;
		}
		newNode.parent = parent;
		return newNode;
	}

	//是否为空
	public boolean isEmpty(){
		return rootNode.data==null;
	}

	//返回根节点
	public TreeNode rootNode(){
		if(isEmpty()){
			throw new RuntimeException("树为空,无法访问根节点");
		}
		return rootNode;
	}

	//返回指定节点(非根节点)的父节点
	public E parent(TreeNode node){
		if(node==null){
			throw new RuntimeException("节点为null,无法访问其父节点");
		}
		return (E) node.parent.data;
	}

	//返回指定节点(非叶子)的左子节点
	public E leftChild(TreeNode parent){
		if(parent==null){
			throw new RuntimeException("节点为null, 无法添加子节点");
		}
		return (E) (parent.left==null? null : parent.left.data);
	}

	public E rightChild(TreeNode parent){
		if(parent==null){
			throw new RuntimeException("节点为null, 无法添加子节点");
		}
		return (E) (parent.right==null ? null : parent.right.data);
	}

	//返回二叉树的深度
	public int deep(){
		return deep(rootNode);
	}

	//每棵子树的深度为其所有子树的最大深度+1
	private int deep(TreeNode node){
		if(node==null){
			return 0;
		}
		if(node.left==null && node.right==null){
			return 1;
		}else{
			int leftDeep = deep(node.left);
			int rightDeep = deep(node.right);

			int max = leftDeep>rightDeep ? leftDeep : rightDeep;
			return max+1;
		}
	}

	//深度优先遍历-先序遍历
	public List<TreeNode> preIterator(){
		return preIterator(rootNode);
	}
	private List<TreeNode> preIterator(TreeNode node){
		List<TreeNode> list = new ArrayList<TreeNode>();
		list.add(node);
		if(node.left!=null){
			list.addAll(preIterator(node.left));
		}
		if(node.right!=null){
			list.addAll(preIterator(node.right));
		}
		return list;
	}

	//深度优先遍历-中序遍历
	public List<TreeNode> inIterator(){
		return inIterator(rootNode);
	}
	private List<TreeNode> inIterator(TreeNode node) {
		List<TreeNode> list = new ArrayList<TreeNode>();
		if(node.left!=null){
			list.addAll(inIterator(node.left));
		}
		list.add(node);
		if(node.right!=null){
			list.addAll(inIterator(node.right));
		}
		return list;
	}

	//深度优先遍历-后序遍历
	public List<TreeNode> postIterator(){
		return postIterator(rootNode);
	}
	private List<TreeNode> postIterator(TreeNode node){
		List<TreeNode> list = new ArrayList<TreeNode>();
		if(node.left!=null){
			list.addAll(postIterator(node.left));
		}
		if(node.right!=null){
			list.addAll(postIterator(node.right));
		}
		list.add(node);
		return list;
	}

	//广度优先遍历
	public List<TreeNode> breadthFirst(){
		Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
		List<TreeNode> list = new ArrayList<TreeNode>();
		//将根元素加入"列队"
		if(rootNode!=null){
			queue.offer(rootNode);
		}
		while(!queue.isEmpty()){
			//将该列队的队尾元素添加到list中
			list.add(queue.peek());
			TreeNode p = queue.poll();
			if(p.left!=null){
				queue.offer(p.left);
			}
			if(p.right!=null){
				queue.offer(p.right);
			}
		}
		return list;
	}

	public static void main(String[] args){
		Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
		List<TreeNode> list = new ArrayList<TreeNode>();
		//将根元素加入"列队"
		if(rootNode!=null){
			queue.offer(rootNode);
		}
		while(!queue.isEmpty()){
			//将该列队的队尾元素添加到list中
			list.add(queue.peek());
			TreeNode p = queue.poll();
			if(p.left!=null){
				queue.offer(p.left);
			}
			if(p.right!=null){
				queue.offer(p.right);
			}
		}
		System.out.println(list);

	}

}

7.哈夫曼树

也被称为
最优二叉树

是一类
带权路径最短的二叉树

哈夫曼树是二叉树的一种应用,在信息检索中很常用

 1)节点之间的路径长度:

从一个节点到另一个节点之间的分支数量,称为两个节点之间的路径长度

树的
路径长度:


根节点到树中
每一个节点的路径长度
之和

节点的
带权路径长度:


该节点

根节点
之间的
路径长度与节点上权
乘积

的带权路径长度:

树中所有叶子节点的带权路径长度
之和

 2)带权路径最小的二叉树被称为哈夫曼树和最优二叉树

3)对于具有n个叶子节点的哈夫曼树,一共需要(2*n-1)个节点

 4)哈夫曼编码:

解决
报文编码问题

假设需要把一个字符串"abcdabcaba"进行编码,将它转换成唯一的二进制码,但要求转换出来的二进制码的长度最小。

package knowledge;

import java.util.ArrayDeque;

/**
 * 哈夫曼树
 * @author [email protected]
 */
public class HuffmanTree {

	public static class Node<E>{

		E data;
		double weight;
		Node leftChild;
		Node rightChild;

		public Node(E data, double weight){
			this.data = data;
			this.weight = weight;
		}

		public String toString(){
			return "Node[data=" + data + ", weight=" + weight + "]";
		}
	}

	private static Node createTree(List<Node> nodes) {
		while(nodes.size()>1){
			quickSort(nodes);
			Node left = nodes.get(nodes.size()-1);
			Node right = nodes.get(nodes.size()-2);
			Node parent = new Node(null, left.weight + right.weight);
			parent.leftChild = left;
			parent.rightChild = right;
			nodes.remove(nodes.size()-1);
			nodes.remove(nodes.size()-1);
		}
		return nodes.get(0);
	}

	private static void quickSort(List<Node> nodes) {
		subSort(nodes, 0, nodes.size()-1);
	}

	private static void subSort(List<Node> nodes, int start, int end) {
		if(start<end){
			Node base = nodes.get(start);
			int i = start;
			int j = end+1;
			while(true){
				while(i<end && nodes.get(+i).weight>=base.weight);
				while(j>start && nodes.get(--j).weight<=base.weight);
				if(i<j){
					swap(nodes, i, j);
				}else{
					break;
				}
			}
			swap(nodes, start, j);
			subSort(nodes, start, j-1);
			subSort(nodes, j+1, end);
		}
	}

	private static void swap(List<Node> nodes, int i, int j) {
		Node tmp;
		tmp = nodes.get(i);
		nodes.set(i, nodes.get(i));
		nodes.set(j, tmp);
	}

	private static List<Node> breadthFirst(Node root) {
		Queue<Node> queue = new ArrayDeque<Node>();
		List<Node> list = new ArrayList<Node>();
		if(root!=null){
			queue.offer(root);
		}
		while(!queue.isEmpty()){
			list.add(queue.peek());
			Node p = queue.poll();
			if(p.leftChild!=null){
				queue.offer(p.leftChild);
			}
			if(p.rightChild!=null){
				queue.offer(p.rightChild);
			}
		}
		return list;
	}

	public static void main(String[] args){
		List<Node> nodes = new ArrayList<Node>();
		nodes.add(new Node("A", 40.0));
		nodes.add(new Node("B", 8.0));
		nodes.add(new Node("C", 10.0));
		nodes.add(new Node("D", 30.0));
		nodes.add(new Node("E", 10.0));
		nodes.add(new Node("F", 2.0));
		Node root = HuffmanTree.createTree(nodes);
		System.out.println(breadthFirst(root));
	}

}

8.排序二叉树

通过它可以非常方便地对树中所有节点进行排序和检索

排序二叉树要么是一棵空二叉树,要么是具有以下性质的二叉树

a)若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值

b)若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值

c)它的左/右子树也分别为排序二叉树

9.红黑树

它是一个更高效的检索二叉树,因此常常用来实现关联数组

JDK提供的集合类TreeMap,本身就是一个红黑树的实现

红黑树在原有的排序二叉树上增加了以下几个要求:

1)每个节点要么是红色,要么是黑色

2)根节点永远是黑色的

3)所有的叶节点都是空节点(null),并且是黑色的,被称为黑哨兵

4)每个红色节点的两个子节点都是黑色

5)从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点

树的黑色高度

从根节点到叶子节点的路径中,包含的黑色节点数

对于给定的黑色高度为N的红黑树,从根到叶子节点的最短路径长度为(N-1),最长路径长度为2*(N-1)

插入操作

a)以排序二叉树的方法插入新节点,并将它设为红色

b)进行颜色调换和树旋转(5种情形)

删除操作

a)以排序二叉树的方法删除指定节点

b)进行颜色调换和树旋转,使之满足红黑树特征

package knowledge;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;

/**
 * 红黑树
 * @author [email protected]
 */
public class RedBlackTree<T extends Comparable> {

	private static final boolean RED = false;
	private static final boolean BLACK = true;

	static class Node{

		Object data;
		Node parent;
		Node left;
		Node right;
		//默认节点颜色为黑色
		boolean color = BLACK;

		public Node(Object data, Node parent, Node left, Node right){
			this.data = data;
			this.parent = parent;
			this.left = left;
			this.right = right;
		}

		public String toString(){
			return "[data=" + data + ", color=" + color + "]";
		}

		public boolean equals(Object obj){
			if(this==obj){
				return true;
			}
			if(obj.getClass()==Node.class){
				Node target = (Node) obj;
				return data.equals(target.data)
						&& parent==target.parent
						&& left==target.left
						&& right==target.right
						&& color==target.color;
			}
			return false;
		}
	}

	private Node rootNode;

	//两个构造器用于创建排序二叉树
	public RedBlackTree(){
		rootNode = null;
	}
	public RedBlackTree(T element){
		rootNode = new Node(element, null, null, null);
	}

	//添加节点
	public void add(T element){

		if(rootNode==null){
			rootNode = new Node(element, null, null, null);
		}else{
			Node current = rootNode;
			Node parent = null;
			int cmp = 0;
			do{
				parent = current;
				cmp = element.compareTo(current.data);
				//如果新节点的值大于当前节点的值
				if(cmp>0){
					//以右节点作为当前节点
					current = current.right;
				}else{
					//如果新节点的值小于当前节点的值,以左节点作为当前节
					current = current.left;
				}
			}while(current!=null);

			//创建新节点
			Node newNode = new Node(element, parent, null, null);

			//如果新节点的值大于父节点的值
			if(cmp>0){
				//新节点作为父节点的右节点
				parent.right = newNode;
			}else{
				//如果新节的值小于父节点的值,新节点作为父节点的左节点
				parent.left = newNode;
			}
			//维护红黑树
			fixAfterInsertion(newNode);
		}
	}

	//插入节点后修复红黑树
	private void fixAfterInsertion(Node newNode) {
		newNode.color = RED;

		//循环直到newNode的父节点不是根,而且newNode的父节点不是红色
		while(newNode!=null && newNode!=rootNode && newNode.parent.color!=RED){

			//如果newNode的父节点是其父节点的左子节点
			if(parentOf(newNode)==leftOf(parentOf(parentOf(newNode)))){
				//获取newNode的父节点的兄弟节点
				Node bro = rightOf(parentOf(newNode));
				//如果newNode的父亲节点的兄弟节点是红色
				if(colorOf(bro)==RED){
					//将newNode的父节点设为黑色
					setColor(parentOf(newNode), BLACK);
					//将newNode的父节点的兄弟节点设为黑色
					setColor(bro, BLACK);
					//将newNode的父节点的父节点设为红色
					setColor(parentOf(parentOf(newNode)), RED);
					newNode = parentOf(parentOf(newNode));
				}else{//如果newNode的父节点的兄弟节点是黑色
					//如果newNode是其父节点的右子节点
					if(newNode==rightOf(parentOf(newNode))){
						newNode = parentOf(newNode);
						rotateLeft(newNode);
					}
					//把newNode的父节点设为黑色
					setColor(parentOf(newNode), BLACK);
					//把newNode的父节点的父节点设为红色
					setColor(parentOf(parentOf(newNode)), RED);
					rotateRight(parentOf(parentOf(newNode)));
				}

			}else{//如果newNode的父亲节点是其父节点的右子节点

				//获取newNode的父亲节点的父亲节点的兄弟节点
				Node bro = leftOf(parentOf(parentOf(newNode)));
				//如果newNode的父亲节点的兄弟节点是红色
				if(colorOf(bro)==RED){
					//将newNode的父节点设为黑色
					setColor(parentOf(newNode), BLACK);
					//将newNode的父节点的兄弟节点设为黑色
					setColor(bro, BLACK);
					//将newNode的父节点的父节点设为红色
					setColor(parentOf(parentOf(newNode)), RED);
					//将newNode设为newNode的父节点的节点
					newNode = parentOf(parentOf(newNode));
				}else{//如果newNode的父节点的兄弟节点是黑色
					//如果newNode是其父节点的左子节点
					if(newNode==leftOf(parentOf(newNode))){
						//将newNode的父节点设为newNode
						newNode = parentOf(newNode);
						rotateRight(newNode);
					}
					//把newNode的父节点设为黑色
					setColor(parentOf(newNode), BLACK);
					//把newNode的父节点的父节点设为红色
					setColor(parentOf(parentOf(newNode)), RED);
					rotateLeft(parentOf(parentOf(newNode)));
				}
			}
		}
		//将根节点设为黑色
		rootNode.color = BLACK;
	}

	private Node parentOf(Node node) {
		return node==null ? null : node.parent;
	}
	private Node leftOf(Node node){
		return node==null ? null : node.left;
	}
	private Node rightOf(Node node){
		return node==null ? null : node.right;
	}
	private boolean colorOf(Node node){
		return node==null? BLACK : RED;
	}
	private void setColor(Node node, boolean bv){
		if(node!=null){
			node.color = bv;
		}
	}

	/**
	 * 执行如下转换
	 * node			r
	 * 	  r  	node
	 * 	q			q
	 * @param node
	 */
	public void rotateLeft(Node node){

		if(node!=null){
			Node rn = node.right;
			Node q = rn.left;

			node.right = q;
			if(q!=null){
				q.parent = node;
			}

			rn.parent = node.parent;
			if(node.parent==null){
				rootNode = rn;
			}else if(node.parent.left==node){
				node.parent.left = rn;
			}else{
				node.parent.right = rn;
			}
			rn.left = node;
			node.parent = rn;
		}
	}

	/**
	 * 执行如下转换
	 * 		node	l
	 *  l				node
	 *  	q		q
	 * @param node
	 */
	public void rotateRight(Node node){

		if(node!=null){
			Node ln = node.left;
			Node q = ln.right;

			node.left = q;
			if(q!=null){
				q.parent = node;
			}

			ln.parent = node.parent;
			if(node.parent==null){
				rootNode = ln;
			}else if(node.parent.left==node){
				node.parent.left = ln;
			}else{
				node.parent.right = ln;
			}
			ln.right = node;
			node.parent = ln;

		}
	}

	//删除节点
	public void remove(T element){

		//获取要删除的节点
		Node target = getNode(element);
		//如果被删除的节点的左子树/右子树都不为空
		if(target.left!=null && target.right!=null){
			//找到target节点中序遍历的前一个节点
			//s用于保存target节点中的左子树中最大的节点
			Node s = target.left;
			//搜索target节点的左子树中最大的节点
			while(s.right!=null){
				s = s.right;
			}
			//用s节点来代替p节点
			target.data = s.data;
			target = s;
		}
		//开始修复它的替换节点,如果该替换节点不为null
		Node replacement = target.left!=null ? target.left : target.right;
		if(replacement!=null){
			//让replacement的parent指向target的parent
			replacement.parent = target.parent;
			//如果target的parent为null,表明target本身就是根节点
			if(target.parent==null){
				rootNode = replacement;
			}else if(target==target.parent.left){//如果target是其父节点的左子节点
				//让target的父节点left指向replacement
				target.parent.left = replacement;
			}else{
				//让target的父节点right指向replacement
				target.parent.right = replacement;
			}
			//彻底删除target节点
			target.left = target.right = target.parent = null;
			if(target.color = BLACK){
				fixAfterDeletion(replacement);
			}
		}else if(target.parent==null){
			rootNode = null;
		}else{
			//target没有子节点,把它当成虚的替换节点
			//修复红黑树
			if(target.color==BLACK){
				fixAfterDeletion(target);
			}
			if(target.parent!=null){
				//如果target是其父节点的左子节点
				if(target==target.parent.left){
					//
					target.parent.left = null;
				}else if(target==target.parent.right){
					target.parent.right = null;
				}
				target.parent = null;
			}
		}

	}

	//根据给定的值搜索节点
	private Node getNode(T element) {
		//从根节点开始搜索
		Node p = rootNode;
		while(p!=null){
			int cmp = element.compareTo(p.data);
			//如果搜索的值小于当前p节点的值
			if(cmp<0){
				//向左子树搜索
				p = p.left;
			}else if(cmp>0){
				//向右子树搜索
				p = p.right;
			}else{
				return p;
			}
		}
		return null;
	}

	//删除节点后修复红黑树
	private void fixAfterDeletion(Node node) {

		//直到node不是根节点,且node的颜色是黑色
		while(node!=rootNode && colorOf(node)==BLACK){
			//如果node是其父节点的左子节点
			if(node==leftOf(parentOf(node))){
				//获取node节点父节点的兄弟节点
				Node bro = rightOf(parentOf(node));
				//如果bro节点是红色
				if(colorOf(bro)==RED){
					//将bro节点设为黑色
					setColor(bro, BLACK);
					//将bro的父节点设为红色
					setColor(parentOf(node), RED);
					rotateLeft(parentOf(node));
					//再次将bro设为node的父节点的右子节点
					bro = rightOf(parentOf(node));
				}
				//如果node的两个子节点都是黑色
				if(colorOf(leftOf(node))==BLACK && colorOf(rightOf(bro))==BLACK){
					setColor(bro, RED);
					node = parentOf(node);
				}else{
					if(colorOf(rightOf(bro))==BLACK){
						setColor(leftOf(bro), BLACK);
						setColor(bro, RED);
						rotateRight(bro);
						bro = rightOf(parentOf(node));
					}
					setColor(bro, colorOf(parentOf(node)));
					setColor(parentOf(node), BLACK);
					setColor(rightOf(node), BLACK);
					rotateLeft(parentOf(node));
					node = rootNode;
				}
			}else{
				Node bro = leftOf(parentOf(node));
				if(colorOf(bro)==RED){
					setColor(bro, BLACK);
					setColor(parentOf(node), RED);
					rotateRight(parentOf(node));
					bro = leftOf(parentOf(node));
				}
				if(colorOf(rightOf(node))==BLACK && colorOf(leftOf(node))==BLACK){
					setColor(bro, RED);
					node = parentOf(node);
				}else{
					if(colorOf(leftOf(bro))==BLACK){
						setColor(rightOf(bro), BLACK);
						setColor(bro, RED);
						rotateLeft(bro);
						bro = leftOf(parentOf(node));
					}
					setColor(bro, colorOf(parentOf(node)));
					setColor(parentOf(node), BLACK);
					setColor(leftOf(bro), BLACK);
					rotateRight(parentOf(node));
					node = rootNode;
				}
			}
		}
		setColor(node, BLACK);
	}

	//实现中序遍历
	public List<Node> inIterator(){
		return inInterator(rootNode);
	}
	private List<Node> inInterator(Node rootNode) {
		List<Node> list = new ArrayList<Node>();
		//递归处理左子树
		if(rootNode.left!=null){
			list.addAll(inInterator(rootNode.left));
		}
		//处理根节点
		list.add(rootNode);
		//递归处理右子树
		if(rootNode.right!=null){
			list.addAll(inInterator(rootNode.right));
		}
		return list;
	}

	//广度优先遍历
	public List<Node> breadthFirst(){
		Queue<Node> queue = new ArrayDeque<Node>();
		List<Node> list = new ArrayList<Node>();
		if(rootNode!=null){
			queue.offer(rootNode);
		}
		while(!queue.isEmpty()){
			list.add(queue.peek());
			Node p = queue.poll();
			if(p.left!=null){
				queue.offer(p.left);
			}
			if(p.right!=null){
				queue.offer(p.right);
			}
		}
		return list;
	}

}
时间: 2024-08-04 09:13:13

树/二叉树(哈夫曼树/红黑树)笔记的相关文章

Huffman tree(赫夫曼树、霍夫曼树、哈夫曼树、最优二叉树)

flyfish 2015-8-1 Huffman tree因为翻译不同所以有其他的名字 赫夫曼树.霍夫曼树.哈夫曼树 定义引用自严蔚敏<数据结构> 路径 从树中一个结点到另一个结点之间的分支构成两个结点之间的路径. 路径长度 路径上的分支数目称作路径长度. 树的路径长度 树的路径长度就是从根节点到每一结点的路径长度之和. 结点的带权路径长度 结点的带权路径长度就是从该结点到根节点之间的路径长度与结点上权的乘积. 树的带权路径长度 树的带权路径长度就是树中所有叶子结点的带权路径长度之和,通常记做

《大话数据结构》笔记(6-3)--树:赫夫曼树

代码实现: 第六章    树:赫夫曼树 赫夫曼树定义与原理 从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称作路径长度. 树的路径长度就是从树根到每一结点的路径长度之和. 对于带权的结点,结点的带权路径长度为从该结点到树根之间的路径长度与结点上权的乘积. 树的带权路径长度为树中所有叶子结点的带权路径长度之和. 假设有n个权值{w1, w2, ..., wn},构造一棵有n个叶子结点的二叉树,每个叶子结点带权wk ,每个叶子的路径长度为lk,则其中带权路径长度WPL最

数据结构学习笔记04树(堆 哈夫曼树 并查集)

一.堆(heap) 优先队列(Priority Queue):特殊的“队列”,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序. 数组 : 插入 — 元素总是插入尾部 ~ O ( 1 ) 删除 — 查找最大(或最小)关键字 ~ O ( n ) 从数组中删去需要移动元素 ~ O( n ) 链表: 插入 — 元素总是插入链表的头部 ~ O ( 1 ) 删除 — 查找最大(或最小)关键字 ~ O ( n ) 删去结点 ~ O( 1 ) 有序数组: 插入 — 找到合适的位置

基础数据结构-二叉树-赫夫曼树的解码(详解)

本篇是上一篇赫夫曼树构建与编码的后续,稍微详细讲一下解码的算法. Huffman解码算法流程: 1.定义指针p指向赫夫曼树结点,实际是记录结点数组的下标: 2.定义指针i指向编码串,定义ch逐个取编码串的字符: 3.初始化:读入编码串,设置p指向根结点,i为0: 4.执行以下循环: a)取编码串的第i个字符放入ch: b)如果ch是字符0,表示往左孩子移动,则p跳转到右孩子: c)如果ch是字符1,表示往右孩子移动,则p跳转到右孩子: d)如果ch非0非1,表示编码串有错误,输出error表示解

数据结构与算法-树-二叉树与郝夫曼树

二叉树的遍历 二叉树的遍历指的是从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次. 二叉树的遍历方法: 前序遍历:规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,再前序遍历右子树. 1 void PreOrderTraverse(BiTree T) 2 { 3 if(T == NULL) 4 return; 5 printf("%c",T->data);/*显示结点数据,可以更改为其他对结点操作*/ 6 PreOr

数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉搜索树.红黑树.线索二叉树,它们在解决实际问题中有着非常重要的应用.本文主要从概念和一些基本操作上进行分类和总结. 一.概念总揽 (1) 堆 堆(heap order)是一种特殊的表,如果将它看做是一颗完全二叉树的层次序列,那么它具有如下的性质:每个节点的值都不大于其孩子的值,或每个节点的值都不小于其孩子的值

哈夫曼树;二叉树;二叉排序树(BST)

优先队列:priority_queue<Type, Container, Functional>Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式.Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list.STL里面默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大. 而在求哈夫曼树中,我们恰恰需要取得堆中最小的元素,

哈夫曼树(最优二叉树)及哈夫曼算法

哈夫曼树 在一般的数据结构的书中,树的那章后面,著者一般都会介绍一下哈夫曼(HUFFMAN)树和哈夫曼编码.哈夫曼编码是哈夫曼树的一个应用.哈夫曼编码应用广泛,如JPEG中就应用了哈夫曼编码. 首先介绍什么是哈夫曼树.哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树.所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数).树的带权路径长度记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln),N个权

哈夫曼树与哈夫曼编码

哈夫曼树与哈夫曼编码 术语: i)路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径. 路径中分支的数目称为路径长度.若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1. ii)结点的权及带权路径长度 若对树中的每个结点赋给一个有着某种含义的数值,则这个数值称为该结点的权. 结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积. iii)树的带权路径长度 树的带权路径长度:所有叶子结点的带权路径长度之和,记为WPL. 先了解一下