์ฝ์ค ์์ ์
ํํ๋ง ์ฝ๋ฉ์ ํ์ผ ์์ถ์ ๊ธฐ๋ณธ ์์ด๋์ด๋ฅผ ๊ณต์ํํ๋ ๋ฐ์ดํฐ ์์ถ ์๊ณ ๋ฆฌ์ฆ์ ๋๋ค. ์ด ๊ธฐ์ฌ์์๋ ๊ณ ์ ๋ฐ ๊ฐ๋ณ ๊ธธ์ด ์ธ์ฝ๋ฉ, ๊ณ ์ ํ๊ฒ ๋์ฝ๋ฉ ๊ฐ๋ฅํ ์ฝ๋, ์ ๋์ฌ ๊ท์น ๋ฐ Huffman ํธ๋ฆฌ ๊ตฌ์ถ์ ๋ํด ์ค๋ช ํฉ๋๋ค.
์ฐ๋ฆฌ๋ ๊ฐ ๋ฌธ์๊ฐ 0๊ณผ 1์ ์ํ์ค๋ก ์ ์ฅ๋๊ณ 8๋นํธ๋ฅผ ์ฐจ์งํ๋ค๋ ๊ฒ์ ์๊ณ ์์ต๋๋ค. ๊ฐ ๋ฌธ์๊ฐ ๋์ผํ ๊ณ ์ ๋นํธ ์๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ฅํ๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ๊ณ ์ ๊ธธ์ด ์ธ์ฝ๋ฉ์ด๋ผ๊ณ ํฉ๋๋ค.
ํ ์คํธ๊ฐ ์ฃผ์ด์ก๋ค๊ณ ๊ฐ์ ํด ๋ด ์๋ค. ๋จ์ผ ๋ฌธ์๋ฅผ ์ ์ฅํ๋ ๋ฐ ํ์ํ ๊ณต๊ฐ์ ์ด๋ป๊ฒ ์ค์ผ ์ ์์ต๋๊น?
์ฃผ์ ์์ด๋์ด๋ ๊ฐ๋ณ ๊ธธ์ด ์ธ์ฝ๋ฉ์
๋๋ค. ํ
์คํธ์ ์ผ๋ถ ๋ฌธ์๊ฐ ๋ค๋ฅธ ๋ฌธ์๋ณด๋ค ๋ ์์ฃผ ๋ฐ์ํ๋ค๋ ์ฌ์ค์ ์ฌ์ฉํ ์ ์์ต๋๋ค(
์ด๋ป๊ฒ ๋นํธ ์ํ์ค๋ฅผ ์๋ฉด ๋ช ํํ๊ฒ ๋์ฝ๋ฉํ ์ ์์ต๋๊น?
์ ์ ๊ณ ๋ คํ์ญ์์ค "์๋ฐ๋ต". 8์์ด๋ฉฐ ๊ณ ์ ๊ธธ์ด๋ฅผ ์ธ์ฝ๋ฉํ ๋ ์ ์ฅํ๋ ค๋ฉด 64๋นํธ๊ฐ ํ์ํฉ๋๋ค. ๊ธฐํธ ์ฃผํ์ "a", "b", "c" ะธ "NS" ๊ฐ๊ฐ 4, 2, 1, 1๊ณผ ๊ฐ์ต๋๋ค. ์์ํด ๋ด ์๋ค "์๋ฐ๋ต" ๋ ์ ์ ๋นํธ, ์ฌ์ค์ ์ฌ์ฉํ์ฌ "์" ๋ณด๋ค ์์ฃผ ๋ฐ์ "NS"๊ณผ "NS" ๋ณด๋ค ์์ฃผ ๋ฐ์ "์จ" ะธ "NS". ์ฝ๋ฉ๋ถํฐ ์์ํ์ "์" 0๊ณผ ๊ฐ์ XNUMX๋นํธ, "NS" 11๋นํธ ์ฝ๋ 100์ ํ ๋นํ๊ณ 011๋นํธ XNUMX๊ณผ XNUMX์ ์ฌ์ฉํ์ฌ ์ธ์ฝ๋ฉํฉ๋๋ค. "์จ" ะธ "NS".
๊ฒฐ๊ณผ์ ์ผ๋ก ๋ค์์ ์ป์ ์ ์์ต๋๋ค.
a
0
b
11
c
100
d
011
๊ทธ๋์ ๋ผ์ธ "์๋ฐ๋ต" ์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ด ์ธ์ฝ๋ฉํฉ๋๋ค 00110100011011 (0|0|11|0|100|011|0|11)์์ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ. ๊ทธ๋ฌ๋ ์ฃผ์ ๋ฌธ์ ๋ ๋์ฝ๋ฉ์ ์์ต๋๋ค. ๋ฌธ์์ด์ ํด๋ ํ๋ ค๊ณ ํ ๋ 00110100011011, ๋ค์๊ณผ ๊ฐ์ด ๋ํ๋ผ ์ ์์ผ๋ฏ๋ก ๋ชจํธํ ๊ฒฐ๊ณผ๋ฅผ ์ป์ต๋๋ค.
0|011|0|100|011|0|11 adacdab
0|0|11|0|100|0|11|011 aabacabd
0|011|0|100|0|11|0|11 adacabab
...
๊ธฐํ
์ด๋ฌํ ๋ชจํธ์ฑ์ ํผํ๊ธฐ ์ํด ์ธ์ฝ๋ฉ์ด ๋ค์๊ณผ ๊ฐ์ ๊ฐ๋ ์ ์ถฉ์กฑํ๋์ง ํ์ธํด์ผ ํฉ๋๋ค. ์ ๋์ฌ ๊ท์น, ์ด๋ ์ฝ๋๊ฐ ํ๋์ ๊ณ ์ ํ ๋ฐฉ์์ผ๋ก๋ง ๋์ฝ๋ฉ๋ ์ ์์์ ์๋ฏธํฉ๋๋ค. ์ ๋์ฌ ๊ท์น์ ์ด๋ค ์ฝ๋๋ ๋ค๋ฅธ ์ฝ๋์ ์ ๋์ฌ๊ฐ ๋์ง ์๋๋ก ํฉ๋๋ค. ์ฝ๋๋ ํน์ ๋ฌธ์๋ฅผ ๋ํ๋ด๋ ๋ฐ ์ฌ์ฉ๋๋ ๋นํธ๋ฅผ ์๋ฏธํฉ๋๋ค. ์์ ์์์ 0 ์ ๋์ฌ์ ๋๋ค 011, ์ ๋์ฌ ๊ท์น์ ์๋ฐํฉ๋๋ค. ๋ฐ๋ผ์ ์ฝ๋๊ฐ ์ ๋์ฌ ๊ท์น์ ์ถฉ์กฑํ๋ฉด ๊ณ ์ ํ๊ฒ ๋์ฝ๋ฉํ ์ ์์ต๋๋ค(๋ฐ๋์ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง).
์์ ์๋ฅผ ๋ค์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฒ์๋ ๊ธฐํธ์ ํ ๋นํฉ๋๋ค. "a", "b", "c" ะธ "NS" ์ ๋์ฌ ๊ท์น์ ๋ง์กฑํ๋ ์ฝ๋.
a
0
b
10
c
110
d
111
์ด ์ธ์ฝ๋ฉ์ ์ฌ์ฉํ๋ฉด ๋ฌธ์์ด "์๋ฐ๋ต" ๋ค์๊ณผ ๊ฐ์ด ์ธ์ฝ๋ฉ๋ฉ๋๋ค. 00100100011010 (0|0|10|0|100|011|0|10). ํ์ง๋ง, 00100100011010 ์ด๋ฏธ ๋ช ํํ๊ฒ ๋์ฝ๋ฉํ๊ณ ์๋ ๋ฌธ์์ด๋ก ๋์๊ฐ ์ ์์ต๋๋ค. "์๋ฐ๋ต".
ํํ๋ง ์ฝ๋ฉ
๊ฐ๋ณ ๊ธธ์ด ์ธ์ฝ๋ฉ ๋ฐ ์ ๋์ฌ ๊ท์น์ ๋ค๋ฃจ์์ผ๋ฏ๋ก ์ด์ Huffman ์ธ์ฝ๋ฉ์ ๋ํด ์ด์ผ๊ธฐํ๊ฒ ์ต๋๋ค.
์ด ๋ฐฉ๋ฒ์ ์ด์ง ํธ๋ฆฌ ์์ฑ์ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค. ์ฌ๊ธฐ์์ ๋ ธ๋๋ ์ต์ข ๋๋ ๋ด๋ถ์ผ ์ ์์ต๋๋ค. ์ฒ์์ ๋ชจ๋ ๋ ธ๋๋ ๊ธฐํธ ์์ฒด์ ํด๋น ๊ฐ์ค์น(์ฆ, ๋ฐ์ ๋น๋)๋ฅผ ๋ํ๋ด๋ ๋ฆฌํ(ํฐ๋ฏธ๋)๋ก ๊ฐ์ฃผ๋ฉ๋๋ค. ๋ด๋ถ ๋ ธ๋๋ ์บ๋ฆญํฐ์ ๊ฐ์ค์น๋ฅผ ํฌํจํ๋ฉฐ ๋ ๊ฐ์ ํ์ ๋ ธ๋๋ฅผ ์ฐธ์กฐํฉ๋๋ค. ์ผ๋ฐ ํฉ์์ ์ํด ๋นํธ ยซ0ยป ์ผ์ชฝ ๋ถ๊ธฐ ๋ค์์ ๋ํ๋ ๋๋ค. ยซ1ยป - ์ค๋ฅธ์ชฝ์ผ๋ก. ์ ์ฒด ํธ๋ฆฌ์์ N ๋๋ญ์๊ณผ N-1 ๋ด๋ถ ๋ ธ๋. ํํ๋ง ํธ๋ฆฌ๋ฅผ ๊ตฌ์ฑํ ๋ ์ต์ ์ ๊ธธ์ด ์ฝ๋๋ฅผ ์ป๊ธฐ ์ํด ์ฌ์ฉํ์ง ์๋ ๊ธฐํธ๋ฅผ ๋ฒ๋ฆฌ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์ฐ์ ์์ ๋๊ธฐ์ด์ ์ฌ์ฉํ์ฌ ์ฃผํ์๊ฐ ๊ฐ์ฅ ๋ฎ์ ๋ ธ๋์ ๊ฐ์ฅ ๋์ ์ฐ์ ์์๊ฐ ๋ถ์ฌ๋๋ Huffman ํธ๋ฆฌ๋ฅผ ๊ตฌ์ถํฉ๋๋ค. ๊ตฌ์ฑ ๋จ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ๊ฐ ์บ๋ฆญํฐ์ ๋ํ ๋ฆฌํ ๋ ธ๋๋ฅผ ์์ฑํ๊ณ ์ฐ์ ์์ ๋๊ธฐ์ด์ ์ถ๊ฐํฉ๋๋ค.
- ๋๊ธฐ์ด์ ์ํธ๊ฐ ๋ ๊ฐ ์ด์ ์๋ ๊ฒฝ์ฐ ๋ค์์ ์ํํฉ๋๋ค.
- ๋๊ธฐ์ด์์ ์ฐ์ ์์๊ฐ ๊ฐ์ฅ ๋์(๊ฐ์ฅ ๋ฎ์ ๋น๋) ๋ ๋ ธ๋๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
- ์ด ๋ ๋ ธ๋๊ฐ ์์์ด ๋ ์ ๋ด๋ถ ๋ ธ๋๋ฅผ ๋ง๋ค๊ณ ๋ฐ์ ๋น๋๋ ์ด ๋ ๋ ธ๋์ ๋น๋์ ํฉ๊ณผ ๊ฐ์ต๋๋ค.
- ์ฐ์ ์์ ๋๊ธฐ์ด์ ์ ๋ ธ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- ๋จ์ ์ ์ผํ ๋ ธ๋๋ ๋ฃจํธ๊ฐ ๋ ๊ฒ์ด๋ฉฐ ์ด๊ฒ์ผ๋ก ํธ๋ฆฌ ๊ตฌ์ฑ์ด ์๋ฃ๋ฉ๋๋ค.
๋ฌธ์๋ก๋ง ๊ตฌ์ฑ๋ ํ ์คํธ๊ฐ ์๋ค๊ณ ์์ํด๋ณด์ญ์์ค. "a", "b", "c", "d" ะธ "๊ณผ", ๋ฐ์ ๋น๋๋ ๊ฐ๊ฐ 15, 7, 6, 6 ๋ฐ 5์ ๋๋ค. ์๋๋ ์๊ณ ๋ฆฌ์ฆ์ ๋จ๊ณ๋ฅผ ๋ฐ์ํ๋ ๊ทธ๋ฆผ์ ๋๋ค.
๋ฃจํธ์์ ๋ ๋
ธ๋๊น์ง์ ๊ฒฝ๋ก๋ ํด๋น ๋ ๋
ธ๋์ ๊ด๋ จ๋ ๋ฌธ์์ ํด๋นํ๋ ์ต์ ์ ์ ๋์ฌ ์ฝ๋(ํํ๋ง ์ฝ๋๋ผ๊ณ ๋ ํจ)๋ฅผ ์ ์ฅํฉ๋๋ค.
ํํ๋ง ํธ๋ฆฌ
์๋์์ C++ ๋ฐ Java๋ก Huffman ์์ถ ์๊ณ ๋ฆฌ์ฆ์ ๊ตฌํํ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
#include <iostream>
#include <string>
#include <queue>
#include <unordered_map>
using namespace std;
// A Tree node
struct Node
{
char ch;
int freq;
Node *left, *right;
};
// Function to allocate a new tree node
Node* getNode(char ch, int freq, Node* left, Node* right)
{
Node* node = new Node();
node->ch = ch;
node->freq = freq;
node->left = left;
node->right = right;
return node;
}
// Comparison object to be used to order the heap
struct comp
{
bool operator()(Node* l, Node* r)
{
// highest priority item has lowest frequency
return l->freq > r->freq;
}
};
// traverse the Huffman Tree and store Huffman Codes
// in a map.
void encode(Node* root, string str,
unordered_map<char, string> &huffmanCode)
{
if (root == nullptr)
return;
// found a leaf node
if (!root->left && !root->right) {
huffmanCode[root->ch] = str;
}
encode(root->left, str + "0", huffmanCode);
encode(root->right, str + "1", huffmanCode);
}
// traverse the Huffman Tree and decode the encoded string
void decode(Node* root, int &index, string str)
{
if (root == nullptr) {
return;
}
// found a leaf node
if (!root->left && !root->right)
{
cout << root->ch;
return;
}
index++;
if (str[index] =='0')
decode(root->left, index, str);
else
decode(root->right, index, str);
}
// Builds Huffman Tree and decode given input text
void buildHuffmanTree(string text)
{
// count frequency of appearance of each character
// and store it in a map
unordered_map<char, int> freq;
for (char ch: text) {
freq[ch]++;
}
// Create a priority queue to store live nodes of
// Huffman tree;
priority_queue<Node*, vector<Node*>, comp> pq;
// Create a leaf node for each character and add it
// to the priority queue.
for (auto pair: freq) {
pq.push(getNode(pair.first, pair.second, nullptr, nullptr));
}
// do till there is more than one node in the queue
while (pq.size() != 1)
{
// Remove the two nodes of highest priority
// (lowest frequency) from the queue
Node *left = pq.top(); pq.pop();
Node *right = pq.top(); pq.pop();
// Create a new internal node with these two nodes
// as children and with frequency equal to the sum
// of the two nodes' frequencies. Add the new node
// to the priority queue.
int sum = left->freq + right->freq;
pq.push(getNode('', sum, left, right));
}
// root stores pointer to root of Huffman Tree
Node* root = pq.top();
// traverse the Huffman Tree and store Huffman Codes
// in a map. Also prints them
unordered_map<char, string> huffmanCode;
encode(root, "", huffmanCode);
cout << "Huffman Codes are :n" << 'n';
for (auto pair: huffmanCode) {
cout << pair.first << " " << pair.second << 'n';
}
cout << "nOriginal string was :n" << text << 'n';
// print encoded string
string str = "";
for (char ch: text) {
str += huffmanCode[ch];
}
cout << "nEncoded string is :n" << str << 'n';
// traverse the Huffman Tree again and this time
// decode the encoded string
int index = -1;
cout << "nDecoded string is: n";
while (index < (int)str.size() - 2) {
decode(root, index, str);
}
}
// Huffman coding algorithm
int main()
{
string text = "Huffman coding is a data compression algorithm.";
buildHuffmanTree(text);
return 0;
}
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;
// A Tree node
class Node
{
char ch;
int freq;
Node left = null, right = null;
Node(char ch, int freq)
{
this.ch = ch;
this.freq = freq;
}
public Node(char ch, int freq, Node left, Node right) {
this.ch = ch;
this.freq = freq;
this.left = left;
this.right = right;
}
};
class Huffman
{
// traverse the Huffman Tree and store Huffman Codes
// in a map.
public static void encode(Node root, String str,
Map<Character, String> huffmanCode)
{
if (root == null)
return;
// found a leaf node
if (root.left == null && root.right == null) {
huffmanCode.put(root.ch, str);
}
encode(root.left, str + "0", huffmanCode);
encode(root.right, str + "1", huffmanCode);
}
// traverse the Huffman Tree and decode the encoded string
public static int decode(Node root, int index, StringBuilder sb)
{
if (root == null)
return index;
// found a leaf node
if (root.left == null && root.right == null)
{
System.out.print(root.ch);
return index;
}
index++;
if (sb.charAt(index) == '0')
index = decode(root.left, index, sb);
else
index = decode(root.right, index, sb);
return index;
}
// Builds Huffman Tree and huffmanCode and decode given input text
public static void buildHuffmanTree(String text)
{
// count frequency of appearance of each character
// and store it in a map
Map<Character, Integer> freq = new HashMap<>();
for (int i = 0 ; i < text.length(); i++) {
if (!freq.containsKey(text.charAt(i))) {
freq.put(text.charAt(i), 0);
}
freq.put(text.charAt(i), freq.get(text.charAt(i)) + 1);
}
// Create a priority queue to store live nodes of Huffman tree
// Notice that highest priority item has lowest frequency
PriorityQueue<Node> pq = new PriorityQueue<>(
(l, r) -> l.freq - r.freq);
// Create a leaf node for each character and add it
// to the priority queue.
for (Map.Entry<Character, Integer> entry : freq.entrySet()) {
pq.add(new Node(entry.getKey(), entry.getValue()));
}
// do till there is more than one node in the queue
while (pq.size() != 1)
{
// Remove the two nodes of highest priority
// (lowest frequency) from the queue
Node left = pq.poll();
Node right = pq.poll();
// Create a new internal node with these two nodes as children
// and with frequency equal to the sum of the two nodes
// frequencies. Add the new node to the priority queue.
int sum = left.freq + right.freq;
pq.add(new Node('', sum, left, right));
}
// root stores pointer to root of Huffman Tree
Node root = pq.peek();
// traverse the Huffman tree and store the Huffman codes in a map
Map<Character, String> huffmanCode = new HashMap<>();
encode(root, "", huffmanCode);
// print the Huffman codes
System.out.println("Huffman Codes are :n");
for (Map.Entry<Character, String> entry : huffmanCode.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
System.out.println("nOriginal string was :n" + text);
// print encoded string
StringBuilder sb = new StringBuilder();
for (int i = 0 ; i < text.length(); i++) {
sb.append(huffmanCode.get(text.charAt(i)));
}
System.out.println("nEncoded string is :n" + sb);
// traverse the Huffman Tree again and this time
// decode the encoded string
int index = -1;
System.out.println("nDecoded string is: n");
while (index < sb.length() - 2) {
index = decode(root, index, sb);
}
}
public static void main(String[] args)
{
String text = "Huffman coding is a data compression algorithm.";
buildHuffmanTree(text);
}
}
์ฐธ๊ณ : ์ ๋ ฅ ๋ฌธ์์ด์ด ์ฌ์ฉํ๋ ๋ฉ๋ชจ๋ฆฌ๋ 47 * 8 = 376๋นํธ์ด๊ณ ์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด์ 194๋นํธ์ ๋๋ค. ๋ฐ์ดํฐ๋ ์ฝ 48% ์์ถ๋ฉ๋๋ค. ์์ C++ ํ๋ก๊ทธ๋จ์์ ๋ฌธ์์ด ํด๋์ค๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก๊ทธ๋จ์ ์ฝ์ ์ ์๋๋ก ์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด์ ์ ์ฅํฉ๋๋ค.
ํจ์จ์ ์ธ ์ฐ์ ์์ ํ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ ์ฝ์ ๋ง๋ค ํ์ํ๊ธฐ ๋๋ฌธ์ O(๋ก๊ทธ(N)) ํ์ง๋ง ์์ ํ ์ด์ง ํธ๋ฆฌ์์ N ์์ฌ๊ท 2N-1 ๋ ธ๋์ด๊ณ Huffman ํธ๋ฆฌ๋ ์์ ํ ์ด์ง ํธ๋ฆฌ์ด๋ฉฐ ์๊ณ ๋ฆฌ์ฆ์ ๋ค์์์ ์คํ๋ฉ๋๋ค. O(Nlog(N)) ์๊ฐ, ์ด๋์ N - ์บ๋ฆญํฐ.
์ถ์ฒ :
์ถ์ฒ : habr.com