數據結構與算法-樹-哈夫曼樹
概述
給定n個權值作爲n個葉子結點,構造一棵二叉樹,若帶權路徑長度達到最小,稱這樣的二叉樹爲最優二叉樹,也稱爲哈夫曼樹(Huffman Tree)。哈夫曼樹是帶權路徑長度最短的樹,權值較大的結點離根較近。
特性
- 對於同一組權值,所能得到的赫夫曼樹不一定是唯一的。
- 赫夫曼樹的左右子樹可以互換,因爲這並不影響樹的帶權路徑長度。
- 帶權值的節點都是葉子節點,不帶權值的節點都是某棵子二叉樹的根節點。
- 權值越大的節點越靠近赫夫曼樹的根節點,權值越小的節點越遠離赫夫曼樹的根節點。
- 赫夫曼樹中只有葉子節點和度爲2的節點,沒有度爲1的節點。一棵有n個葉子節點的赫夫曼樹共有2n-1個節點。
Huffman Tree的構建
赫夫曼樹的構建步驟如下:
- 將給定的n個權值看做n棵只有根節點(無左右孩子)的二叉樹,組成一個集合HT,每棵樹的權值爲該節點的權值。
- 從集合HT中選出2棵權值最小的二叉樹,組成一棵新的二叉樹,其權值爲這2棵二叉樹的權值之和。
- 將步驟2中選出的2棵二叉樹從集合HT中刪去,同時將步驟2中新得到的二叉樹加入到集合HT中。
- 重複步驟2和步驟3,直到集合HT中只含一棵樹,這棵樹便是赫夫曼樹。
創建
圖解
https://mp.weixin.qq.com/s/nx0OovSwYTeF8ebmzi_-VA
實現代碼
class TreeNode{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val) {
this.val=val;
}
}
protected TreeNode root;
/**
*vals 是升序序列
*/
public void create(List<Integer> vals) {
Queue<Integer> q1 = new LinkedList<>(vals);
Queue<TreeNode> q2 = new LinkedList<>();
TreeNode n1 = null;
while(!q1.isEmpty()||!q2.isEmpty()) {
TreeNode n2 = null;
if(q1.isEmpty()) {
n2 = q2.poll();
}else if(q2.isEmpty()) {
n2 = new TreeNode(q1.poll());
}else {
if(q1.peek()>=q2.peek().val) {
n2=q2.poll();
}else {
n2=new TreeNode(q1.poll());
}
}
if(n1==null) {
n1=n2;
}else {
TreeNode nNode = new TreeNode(n1.val+n2.val);
nNode.left=n1;
nNode.right=n2;
q2.add(nNode);
n1=null;
}
}
//有頭結點,可以根據需求是否添加頭結點
root = new TreeNode(0);
root.right=n1;
size = vals.size();
}
帶權路徑長度
WPL = 所有葉子節點的權值與深度-1的乘積之4和
public int getWPL() {
Queue<TreeNode> queue = new LinkedList<>();
if(root.right==null) {
return 0;
}
queue.add(root.right);
int cnt = 1;
int depth = 0;
int result = 0;
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
if(node.left!=null) {
queue.add(node.left);
}
if(node.right!=null) {
queue.add(node.right);
}
if(node.right==null&&node.left==null) {
result+=node.val*depth;
}
cnt--;
if(cnt==0) {
depth+=1;
cnt=queue.size();
}
}
return result;
}
畫圖解釋太麻煩了,就給個鏈接吧
https://mp.weixin.qq.com/s/dMOS7-cTfnhKHs61cUsMpw