亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

圖文詳解JAVA實(shí)現(xiàn)哈夫曼樹(shù)

 更新時(shí)間:2016年08月18日 09:41:45   投稿:daisy  
所謂哈夫曼樹(shù)就是要求最小加權(quán)路徑長(zhǎng)度,這是什么意思呢?簡(jiǎn)而言之,就是要所有的節(jié)點(diǎn)對(duì)應(yīng)的路徑長(zhǎng)度(高度-1)乘以該節(jié)點(diǎn)的權(quán)值,然后保證這些結(jié)果之和最小。下面這篇文章就給大家詳細(xì)介紹

前言 

我想學(xué)過(guò)數(shù)據(jù)結(jié)構(gòu)的小伙伴一定都認(rèn)識(shí)哈夫曼,這位大神發(fā)明了大名鼎鼎的“最優(yōu)二叉樹(shù)”,為了紀(jì)念他呢,我們稱之為“哈夫曼樹(shù)”。哈夫曼樹(shù)可以用于哈夫曼編碼,編碼的話學(xué)問(wèn)可就大了,比如用于壓縮,用于密碼學(xué)等。今天一起來(lái)看看哈夫曼樹(shù)到底是什么東東。 

概念

當(dāng)然,套路之一,首先我們要了解一些基本概念。 

      1、路徑長(zhǎng)度:從樹(shù)中的一個(gè)結(jié)點(diǎn)到另一個(gè)結(jié)點(diǎn)之間的分支構(gòu)成這兩個(gè)結(jié)點(diǎn)的路徑,路徑上的分支數(shù)目稱為路徑長(zhǎng)度。

      2、樹(shù)的路徑長(zhǎng)度:從樹(shù)根到每一個(gè)結(jié)點(diǎn)的路徑長(zhǎng)度之和,我們所說(shuō)的完全二叉樹(shù)就是這種路徑長(zhǎng)度最短的二叉樹(shù)。

      3、樹(shù)的帶權(quán)路徑長(zhǎng)度:如果在樹(shù)的每一個(gè)葉子結(jié)點(diǎn)上賦上一個(gè)權(quán)值,那么樹(shù)的帶權(quán)路徑長(zhǎng)度就等于根結(jié)點(diǎn)到所有葉子結(jié)點(diǎn)的路徑長(zhǎng)度與葉子結(jié)點(diǎn)權(quán)值乘積的總和。 

那么我們?cè)趺磁袛嘁豢脴?shù)是否為最優(yōu)二叉樹(shù)呢,先看看下面幾棵樹(shù):

 

他們的帶權(quán)長(zhǎng)度分別為:

     WPL1:7*2+5*2+2*2+4*2=36

     WPL2:7*3+5*3+2*1+4*2=46

     WPL3:7*1+5*2+2*3+4*3=35

很明顯,第三棵樹(shù)的帶權(quán)路徑最短(不信的小伙伴可以試一試,要是能找到更短的,估計(jì)能拿圖靈獎(jiǎng)了),這就是我們所說(shuō)的“最優(yōu)二叉樹(shù)(哈夫曼樹(shù))”,它的構(gòu)建方法很簡(jiǎn)單,依次選取權(quán)值最小的結(jié)點(diǎn)放在樹(shù)的底部,將最小的兩個(gè)連接構(gòu)成一個(gè)新結(jié)點(diǎn),需要注意的是構(gòu)成的新結(jié)點(diǎn)的權(quán)值應(yīng)該等于這兩個(gè)結(jié)點(diǎn)的權(quán)值之和,然后要把這個(gè)新結(jié)點(diǎn)放回我們需要構(gòu)成樹(shù)的結(jié)點(diǎn)中繼續(xù)進(jìn)行排序,這樣構(gòu)成的哈夫曼樹(shù),所有的存儲(chǔ)有信息的結(jié)點(diǎn)都在葉子結(jié)點(diǎn)上。

概念講完,可能有點(diǎn)小伙伴還是“不明覺(jué)厲”。

下面舉個(gè)例子構(gòu)建一下就清楚了。

有一個(gè)字符串:aaaaaaaaaabbbbbaaaaaccccccccddddddfff

第一步,我們先統(tǒng)計(jì)各個(gè)字符出現(xiàn)的次數(shù),稱之為該字符的權(quán)值。a 15 ,b 5, c 8, d 6, f 3。

第二步,找去這里面權(quán)值最小的兩個(gè)字符,b5和f3,構(gòu)建節(jié)點(diǎn)。

 

然后將f3和b5去掉,現(xiàn)在是a15,c8,d6,fb8。

第三步,重復(fù)第二步,直到構(gòu)建出只剩一個(gè)節(jié)點(diǎn)。

  

現(xiàn)在是dfb14,a15,c8。

 

最后,

 

ok,這樣我們的哈夫曼樹(shù)就構(gòu)造完成了。 

構(gòu)建的步驟 

按照上面的邏輯,總結(jié)起來(lái),就是一下幾個(gè)步驟:

     1.統(tǒng)計(jì)字符串中字符以及字符的出現(xiàn)次數(shù);

     2.根據(jù)第一步的結(jié)構(gòu),創(chuàng)建節(jié)點(diǎn);

     3.對(duì)節(jié)點(diǎn)權(quán)值升序排序;

     4.取出權(quán)值最小的兩個(gè)節(jié)點(diǎn),生成一個(gè)新的父節(jié)點(diǎn);

     5.刪除權(quán)值最小的兩個(gè)節(jié)點(diǎn),將父節(jié)點(diǎn)存放到列表中;

     6.重復(fù)第四五步,直到剩下一個(gè)節(jié)點(diǎn);

     7.將最后的一個(gè)節(jié)點(diǎn)賦給根節(jié)點(diǎn)。 

java代碼

原理說(shuō)完了,接下來(lái)是代碼實(shí)現(xiàn)了。

首先需要有個(gè)節(jié)點(diǎn)類來(lái)存放數(shù)據(jù)。

package huffman;
/**
 * 節(jié)點(diǎn)類
 * @author yuxiu
 *
 */
public class Node {
 public String code;// 節(jié)點(diǎn)的哈夫曼編碼
 public int codeSize;// 節(jié)點(diǎn)哈夫曼編碼的長(zhǎng)度
 public String data;// 節(jié)點(diǎn)的數(shù)據(jù)
 public int count;// 節(jié)點(diǎn)的權(quán)值
 public Node lChild;
 public Node rChild;

 public Node() {
 }

 public Node(String data, int count) {
  this.data = data;
  this.count = count;
 }

 public Node(int count, Node lChild, Node rChild) {
  this.count = count;
  this.lChild = lChild;
  this.rChild = rChild;
 }

 public Node(String data, int count, Node lChild, Node rChild) {
  this.data = data;
  this.count = count;
  this.lChild = lChild;
  this.rChild = rChild;
 }
}

然后就是實(shí)現(xiàn)的過(guò)程了。

package huffman;

import java.io.*;
import java.util.*;

public class Huffman {
 private String str;// 最初用于壓縮的字符串
 private String newStr = "";// 哈夫曼編碼連接成的字符串 
 private Node root;// 哈夫曼二叉樹(shù)的根節(jié)點(diǎn)
 private boolean flag;// 最新的字符是否已經(jīng)存在的標(biāo)簽
 private ArrayList<String> charList;// 存儲(chǔ)不同字符的隊(duì)列 相同字符存在同一位置
 private ArrayList<Node> NodeList;// 存儲(chǔ)節(jié)點(diǎn)的隊(duì)列
 
  15  16  /**
  * 構(gòu)建哈夫曼樹(shù)
  * 
  * @param str
  */
 public void creatHfmTree(String str) {
  this.str = str;
  charList = new ArrayList<String>();
  NodeList = new ArrayList<Node>();
  // 1.統(tǒng)計(jì)字符串中字符以及字符的出現(xiàn)次數(shù)
  // 基本思想是將一段無(wú)序的字符串如ababccdebed放到charList里,分別為aa,bbb,cc,dd,ee
  // 并且列表中字符串的長(zhǎng)度就是對(duì)應(yīng)的權(quán)值
  for (int i = 0; i < str.length(); i++) {
   char ch = str.charAt(i); // 從給定的字符串中取出字符
   flag = true;
   for (int j = 0; j < charList.size(); j++) {
    if (charList.get(j).charAt(0) == ch) {// 如果找到了同一字符
     String s = charList.get(j) + ch;
     charList.set(j, s);
     flag = false;
     break;
    }
   }
   if (flag) {
    charList.add(charList.size(), ch + "");
   }
  }
  // 2.根據(jù)第一步的結(jié)構(gòu),創(chuàng)建節(jié)點(diǎn)
  for (int i = 0; i < charList.size(); i++) {
   String data = charList.get(i).charAt(0) + ""; // 獲取charList中每段字符串的首個(gè)字符
   int count = charList.get(i).length(); // 列表中字符串的長(zhǎng)度就是對(duì)應(yīng)的權(quán)值
   Node node = new Node(data, count); // 創(chuàng)建節(jié)點(diǎn)對(duì)象
   NodeList.add(i, node); // 加入到節(jié)點(diǎn)隊(duì)列
  }

  // 3.對(duì)節(jié)點(diǎn)權(quán)值升序排序
  Sort(NodeList);
  while (NodeList.size() > 1) {// 當(dāng)節(jié)點(diǎn)數(shù)目大于一時(shí)
   // 4.取出權(quán)值最小的兩個(gè)節(jié)點(diǎn),生成一個(gè)新的父節(jié)點(diǎn)
   // 5.刪除權(quán)值最小的兩個(gè)節(jié)點(diǎn),將父節(jié)點(diǎn)存放到列表中
   Node left = NodeList.remove(0);
   Node right = NodeList.remove(0);
   int parentWeight = left.count + right.count;// 父節(jié)點(diǎn)權(quán)值等于子節(jié)點(diǎn)權(quán)值之和
   Node parent = new Node(parentWeight, left, right);
   NodeList.add(0, parent); // 將父節(jié)點(diǎn)置于首位

  }
  // 6.重復(fù)第四五步,就是那個(gè)while循環(huán)
  // 7.將最后的一個(gè)節(jié)點(diǎn)賦給根節(jié)點(diǎn)
  root = NodeList.get(0);
 }
 /**
  * 升序排序
  * 
  * @param nodelist
  */
 public void Sort(ArrayList<Node> nodelist) {
  for (int i = 0; i < nodelist.size() - 1; i++) {
   for (int j = i + 1; j < nodelist.size(); j++) {
    Node temp;
    if (nodelist.get(i).count > nodelist.get(j).count) {
     temp = nodelist.get(i);
     nodelist.set(i, nodelist.get(j));
     nodelist.set(j, temp);
    }

   }
  }

 }

 /**
  * 遍歷
  * 
  * @param node
  *   節(jié)點(diǎn)
  */
 public void output(Node node) {
  if (node.lChild != null) {
   output(node.lChild);
  }
  System.out.print(node.count + " "); // 中序遍歷
  if (node.rChild != null) {
   output(node.rChild);
  }
 }

 public void output() {
  output(root);
 }
/**
  * 主方法
  * 
  * @param args
  */
 public static void main(String[] args) {
  Huffman huff = new Huffman();//創(chuàng)建哈弗曼對(duì)象
  huff.creatHfmTree("sdfassvvdfgsfdfsdfs");//構(gòu)造樹(shù)
 }

總結(jié)

以上就是基于JAVA實(shí)現(xiàn)哈夫曼樹(shù)的全部?jī)?nèi)容,希望這篇文章對(duì)大家學(xué)習(xí)使用JAVA能有所幫助。如果有疑問(wèn)可以留言討論。

相關(guān)文章

  • Java接口DAO模式代碼原理及應(yīng)用詳解

    Java接口DAO模式代碼原理及應(yīng)用詳解

    這篇文章主要介紹了Java接口DAO模式代碼原理及應(yīng)用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Java?int類型如何獲取高低位

    Java?int類型如何獲取高低位

    這篇文章主要介紹了Java?int類型如何獲取高低位,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 利用MyBatis實(shí)現(xiàn)條件查詢的方法匯總

    利用MyBatis實(shí)現(xiàn)條件查詢的方法匯總

    這篇文章主要給大家介紹了關(guān)于利用MyBatis實(shí)現(xiàn)條件查詢的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用MyBatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 關(guān)于Java中代碼塊的執(zhí)行順序

    關(guān)于Java中代碼塊的執(zhí)行順序

    這篇文章主要介紹了關(guān)于Java中代碼塊的執(zhí)行順序,構(gòu)造代碼塊是給所有對(duì)象進(jìn)行統(tǒng)一初始化,而構(gòu)造函數(shù)是給對(duì)應(yīng)的對(duì)象初始化,因?yàn)闃?gòu)造函數(shù)是可以多個(gè)的,運(yùn)行哪個(gè)構(gòu)造函數(shù)就會(huì)建立什么樣的對(duì)象,但無(wú)論建立哪個(gè)對(duì)象,都會(huì)先執(zhí)行相同的構(gòu)造代碼塊,需要的朋友可以參考下
    2023-08-08
  • SpringMVC基于注解方式實(shí)現(xiàn)上傳下載

    SpringMVC基于注解方式實(shí)現(xiàn)上傳下載

    本文主要介紹了SpringMVC基于注解方式實(shí)現(xiàn)上傳下載,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Mybatis模糊查詢之三種定義參數(shù)方法和聚合查詢、主鍵回填實(shí)現(xiàn)方法

    Mybatis模糊查詢之三種定義參數(shù)方法和聚合查詢、主鍵回填實(shí)現(xiàn)方法

    這篇文章主要介紹了Mybatis模糊查詢之三種定義參數(shù)方法和聚合查詢、主鍵回填實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • 關(guān)于Netty--Http請(qǐng)求處理方式

    關(guān)于Netty--Http請(qǐng)求處理方式

    這篇文章主要介紹了關(guān)于Netty--Http請(qǐng)求處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • springboot跨域如何設(shè)置SameSite的實(shí)現(xiàn)

    springboot跨域如何設(shè)置SameSite的實(shí)現(xiàn)

    這篇文章主要介紹了springboot跨域如何設(shè)置SameSite的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • JAVA設(shè)計(jì)模式中的策略模式你了解嗎

    JAVA設(shè)計(jì)模式中的策略模式你了解嗎

    這篇文章主要為大家詳細(xì)介紹了JAVA設(shè)計(jì)模式中的策略模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • Mybatis-Plus實(shí)現(xiàn)用戶ID自增出現(xiàn)的問(wèn)題解決

    Mybatis-Plus實(shí)現(xiàn)用戶ID自增出現(xiàn)的問(wèn)題解決

    項(xiàng)目基于 SpringBoot + MybatisPlus 3.5.2 使用數(shù)據(jù)庫(kù)自增ID時(shí), 出現(xiàn)重復(fù)鍵的問(wèn)題,本文就來(lái)介紹一下解決方法,感興趣的可以了解一下
    2023-09-09

最新評(píng)論