簡體   English   中英

從頭開始構建順序霍夫曼樹

[英]Constructing sequential Huffman Tree From Scratch

給定一些文本文件,我需要讀取每個字母數字字符並使用霍夫曼算法對它們進行編碼

解決了讀取字符、存儲概率和創建節點以及使用指針創建 Huffman 樹的問題。

但是,我需要使用二叉樹的順序表示來創建和初始化霍夫曼樹,而不需要任何指針。

這可以通過使用指針創建常規樹然后將其讀入數組來完成,但我的目標是直接用節點填充數組。

我考慮過創建較小的樹並將它們合並在一起,但選擇了矩陣表示,我將從二進制堆中收集概率最小的元素並將它們存儲到矩陣的行中,矩陣的行將表示節點所在的級別應該在二叉樹中,以相反的順序。

E.g. Given characters and their probabilities as char[int] pairs.

a[1], b[1], c[2], d[1], e[3], f[11], g[2]

I aim to create matrix that looks like 
____________________________________
    a   |    b   |    d   |    g   |
____________________________________
   ab   |    c   |   dg   |    e   |
____________________________________
   abc  |   deg  |        |        |
____________________________________ 
 abcdeg |    f   |        |        |  
____________________________________
abcdefg |        |        |        |
____________________________________

Where levels of a, b, c, d, e & f would be rows of a matrix.

目前,我被困在如何在元素的“父”移動時遞歸遞增元素的級別(如果我將來自不同級別 ['ab' 和 'c'] 的兩個節點組合在一起,我很容易將 c 的級別與 ab 相等並解決問題,但如果例如'c'和'd'都在第二行)以及如何創建只有終端級別的完整二叉樹(如果它有左子樹,它需要有正確的一個)節點。

事先,我知道這個問題不是很具體,如果有另一種方法來解決這個問題,而不是僅僅解決提到的方法,我將不勝感激。

這是家庭作業的人為問題嗎? 我問是因為不使用鏈接的樹的表示需要 O(2^h) 空間來存儲高度為 h 的樹。 這是因為他們假設樹是完整的,允許索引計算來替換指針。 由於對於大小為 m 的字母表,霍夫曼樹的高度可以為 h=m-1,因此最壞情況數組的大小可能非常大。 大部分將不會被使用。

但是,如果您放棄鏈接必須是指針並允許它是數組索引的想法,那么您就可以了。 很久以前——在動態內存分配器變得普遍之前——這是標准的。 這個問題對這個方法特別好,因為你總是提前知道樹中的節點數:一個小於字母表大小的兩倍。 在 C 中你可能會做這樣的事情

typedef struct {
  char ch;
  int f;
  int left, right; // Indices of children. If both -1, this is leaf for char ch.
} NODE;

#define ALPHABET_SIZE 7
NODE nodes[2 * ALPHABET_SIZE - 1] = {
  { 'a', 1, , -1, -1}, 
  { 'b', 1, -1, -1 }, 
  { 'c', 2, -1, -1 }, 
  { 'd', 1, -1, -1 }, 
  { 'e', 3, -1, -1 },
  { 'f', 11, -1, -1 }, 
  { 'g', 2, -1, -1 },
  // Rest of array for internal nodes
};
int n_nodes = ALPHABET_SIZE;

int add_internal_node(int f, int left, int right) {
  // Allocate a new node in the array and fill in its values.
  int i = n_nodes++;
  nodes[i] = (NODE) { .f = f, .left = left, .right = right };
  return i;
}

現在您將使用標准的樹構建算法,如下所示:

int build_huffman_tree(void) {
  // Add the indices of the leaf nodes to the priority queue.
  for (int i = 0; i < ALPHABET_SIZE; ++i)
    add_to_frequency_priority_queue(i);
  while (priority_queue_size() > 1) {
    int a = remove_min_frequency(); // Removes index of lowest freq node from the queue.
    int b = remove_min_frequency();
    int p = add_internal_node(nodes[a].f + nodes[b].f, a, b);
    add_to_frequency_priority_queue(p);
  }
  // Last node is huffman tree root.
  return remove_min_frequency();
}

解碼算法將像這樣使用根的索引:

char decode(BIT bits[], int huffman_tree_root_index) {
  int i = 0, p = huffman_tree_root_index;
  while (node[p].left != -1 || node[p].right != -1) // while not a leaf
    p = bits[i++] ? nodes[p].right : nodes[p].left;
  return nodes[p].ch;
}

當然,這不會返回消耗了多少位,這是真正的解碼器需要做的。 真正的解碼器也沒有在數組中獲取其位。 最后,對於編碼,除了子項之外,您還需要父索引。 解決這些問題應該很有趣。 祝你好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM