本文转载http://blog.youkuaiyun.com/feixiaoxing/article/details/6960990 http://blog.youkuaiyun.com/feixiaoxing/article/details/6963136
在数据传输的过程当中,我们总是希望用尽可能少的带宽传输更多的数据,哈夫曼就是其中的一种较少带宽传输的方法。哈夫曼的基本思想不复杂,那就是对于出现频率高的数据用短字节表示,对于频率比较低得数据用长字节表示。
比如说,现在有4个数据需要传输,分别为A、B、C、D,所以一般来说,如果此时没有考虑四个数据出现的概率,那么我们完全可以这么分配,平均长度为2,
- /*
- * A - 00 B - 01
- * C - 10 D - 11
- */
第一步,首先合并A和B,因为A和B是概率最小的
- /*
- *
- * total_1(0.3) C (0.3) D(0.4)
- * / \
- * A(0.1) B(0.2)
- */
- /*
- * total_2 (0.6)
- * / \
- * total_1(0.3) C (0.3) D(0.4)
- * / \
- * A(0.1) B(0.2)
- */
- /*
- * final (1.0)
- * / \
- * D (0.4) total_2 (0.6)
- * / \
- * total_1(0.3) C (0.3)
- * / \
- * A(0.1) B(0.2)
- */
- /*
- * A - 011 B - 010
- * C - 00 D - 1
- */
为了完成整个哈夫曼树的创建,我们还需要定义一个数据结构:
- typedef struct _HUFFMAN_NODE
- {
- char str;
- double frequence;
- int symbol;
- struct _HUFFMAN_NODE* left;
- struct _HUFFMAN_NODE* right;
- struct _HUFFMAN_NODE* parent;
- }HUFFMAN_NODE;
- HUFFMAN_NODE* create_new_node(char str, double frq)
- {
- HUFFMAN_NODE* pNode = (HUFFMAN_NODE*)malloc(sizeof(HUFFMAN_NODE));
- assert(NULL != pNode);
- pNode->str = str;
- pNode->frequence = frq;
- pNode->symbol = -1;
- pNode->left = NULL;
- pNode->right = NULL;
- pNode->parent = NULL;
- return pNode;
- }
前面说到了哈夫曼树的创建,那下面一个重要的环节就是哈夫曼树的排序问题。但是由于排序的内容是数据结构,因此形式上说,我们需要采用通用数据排序算法,这在我之前的博客里面已经涉及到了(通用算法设计)。所以,我们所要做的就是编写compare和swap两个函数。通用冒泡代码如下所示,
- void bubble_sort(void* array[], int length, int (*compare)(void*, void*), void(*swap)(void**, void**))
- {
- int outer;
- int inner;
- for(outer = length -1; outer >0; outer --){
- for(inner = 0; inner < outer; inner ++){
- if(compare(array[inner], array[inner + 1]))
- swap(&array[inner], &array[inner + 1]);
- }
- }
- return;
- }
compare和swap代码如下所示,
- int compare (void* a, void* b)
- {
- HUFFMAN_NODE* node1 = (HUFFMAN_NODE*)a;
- HUFFMAN_NODE* node2 = (HUFFMAN_NODE*)b;
- return node1->frequence > node2->frequence ? 1 : 0;
- }
- void swap(void** a, void** b)
- {
- HUFFMAN_NODE* median;
- HUFFMAN_NODE** node1 = (HUFFMAN_NODE**)a;
- HUFFMAN_NODE** node2 = (HUFFMAN_NODE**)b;
- median = *node1;
- *node1 = *node2;
- *node2 = median;
- }
有了创建函数和排序函数,那么哈夫曼树就可以创建了,
- HUFFMAN_NODE* create_huffman_tree(HUFFMAN_NODE* huffmanNode[], int length)
- {
- HUFFMAN_NODE* head = NULL;
- if(NULL == huffmanNode || length <= 1)
- return NULL;
- while(length > 1){
- bubble_sort((void**)huffmanNode, length, compare, swap);
- head = create_new_node('\0', huffmanNode[0]->frequence + huffmanNode[1]->frequence);
- assert(NULL != head);
- head->left = huffmanNode[0];
- head->right = huffmanNode[1];
- huffmanNode[0]->parent = head;
- huffmanNode[0]->symbol = 1;
- huffmanNode[1]->parent = head;
- huffmanNode[1]->symbol = 0;
- memmove(&huffmanNode[0], &huffmanNode[2], sizeof(HUFFMAN_NODE*) * (length -2));
- huffmanNode[length -2] = head;
- length --;
- }
- return head;
- }
- void print_code_for_str(HUFFMAN_NODE* pNode, HUFFMAN_NODE* head)
- {
- if(NULL == pNode || NULL == head)
- return;
- while(head != pNode){
- printf("%d", pNode->symbol);
- pNode = pNode->parent;
- }
- return;
- }
如果对代码本身还有怀疑,可以编译一个测试用例验证一下,
- void test()
- {
- HUFFMAN_NODE* node1 = NULL;
- HUFFMAN_NODE* node2 = NULL;
- HUFFMAN_NODE* node3 = NULL;
- HUFFMAN_NODE* node4 = NULL;
- HUFFMAN_NODE* test[] = {node1 = create_new_node('a', 0.1),
- node2 = create_new_node('b', 0.2),
- node3 = create_new_node('c', 0.3),
- node4 = create_new_node('d', 0.4),
- };
- HUFFMAN_NODE* head = create_huffman_tree(test, sizeof(test)/sizeof(HUFFMAN_NODE*));
- print_code_for_str(node1, head);
- print_code_for_str(node2, head);
- print_code_for_str(node3, head);
- print_code_for_str(node4, head);
- }
总结:
(1)哈夫曼树不复杂,如果手算可以成功,那么编程应该也没有什么问题
(2)复杂算法都是由小算法搭积木而成的,朋友们应该在基本算法上打下坚实的基础
(3)算法注意复用,这里就用到了原来讲到的通用算法内容