huffman编码,本程序思路完全是原创,与金典相比可能效率有差距,但毕竟是自己写出的,很有必要记下自己的第一思路
首先huffman编码用笔写写,一会就发现就是:所有节点按照权值由小到大排序,然后取出最小的两个节点,将权值最小的两个做二叉树的叶子节点,然后生成父节点,再把父节点存进去,以此循环直至只剩下一个节点,当然不用想了,这个节点就是head节点了。
于是立马想到queue来解决,由于涉及到排序,还是自己写个queue。
//定义队列中节点和queue基本操作
class Node
{
public:
char data = '0';
int i;//表示权值
//为每个节点增加父节点,左0右1权值使用便能唯一确定二叉树
int weight = -1;
Node *parent = 0;
Node *next = 0;
//huffman树中的左右节点
Node *l_son = 0, *r_son = 0;
Node(int k) :i(k){ };
Node(char c, int k) :data(c), i(k){};
};
//链表x形式实现队列
class My_queue
{
public:
Node *head, *rear;
int count = 0;
My_queue()
{
head = 0;
rear = 0;
}
//插入
void push(Node *node);
//取头结点,并且删除头结点
Node* front()
{
Node *p = head;
if (head->next != 0)
{
head = head->next;
}
else
head = 0;
count--;
return p;
}
//删除队首元素
void pop()
{
count--;
Node *p = head;
head = head->next;
delete p;
}
int size()
{
return count;
}
};
void My_queue::push(Node *node)
{
count++;
if (head == 0)//如果myqueue为空
{
head = node;
rear = node;
return;
}
//顺序插入
Node *p, *q;//当前节点
p = head;
q = head->next;
while (1)
{
//插在头部
if (node->i <= head->i)
{
head = node;
head->next = p;
q = 0;
p = 0;
return;
}
//插在尾部
if (node->i > rear->i)
{
rear->next = node;
rear = node;
p = 0;
q = 0;
return;
}
if (node->i > p->i&&node->i <= q->i)
{
p->next = node;
node->next = q;
return;
}
p = p->next;
q = q->next;
}
}
// huffman.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include"My_queue.hpp"
using namespace std;
//前序遍历
void pre_order(Node *n)
{
int c_weight[8];
memset(c_weight, -1,8*sizeof(int));
if (n != 0)
{
if (n->data != '0')//n为所要寻找的编码码字
{
cout << n->data << ":";
for (int i = 0; i < 8; i++)
{
if (n->weight == -1)
break;
c_weight[i] = n->weight;
n = n->parent;
}
for (int i= 7; i >= 0; i--)
{
if (c_weight[i] != -1)
cout << c_weight[i];
}
cout << endl;
return;
}
pre_order(n->l_son);
pre_order(n->r_son);
}
}
int main()
{
//建立huffman tree,不同与二叉树,其是由下向上建立
My_queue my_queue;
for (int i = 0; i < 8; i++)
{
cout << "please enter the char of node\n";
char c;
cin >> c;
cout << "please enter the value of this node\n";
int k;
cin >> k;
Node *node = new Node(c,k);
my_queue.push(node);
}
//Node* n1 = my_queue.front();
//cout << n1->data << "\t" << n1->i << endl;
//只剩最后一个元素时退出循环
Node *n1 = 0, *n2 = 0;
while (my_queue.size() > 1)
{
//从队列中取出最小的两个元素
n1= my_queue.front();
n1->weight = 0;
n2 = my_queue.front();
n2->weight = 1;
//new 一个新节点,作为做小的两个节点的父节点,其权值为两个之和
Node *n = new Node((n1->i)+(n2->i));
//双向二叉树,子节点能访问父节点,父节点能访问子节点
n1->parent = n;
n2->parent = n;
n->l_son = n1;
n->r_son = n2;
//将新节点再次插入到队列中去
my_queue.push(n);
}
Node *head = my_queue.front();
//前序遍历寻找到节点
pre_order(head);
return 0;
}
// huffman.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include"My_queue.hpp"
using namespace std;
//前序遍历
void pre_order(Node *n)
{
int c_weight[8];
memset(c_weight, -1,8*sizeof(int));
if (n != 0)
{
if (n->data != '0')//n为所要寻找的编码码字
{
cout << n->data << ":";
for (int i = 0; i < 8; i++)
{
if (n->weight == -1)
break;
c_weight[i] = n->weight;
n = n->parent;
}
for (int i= 7; i >= 0; i--)
{
if (c_weight[i] != -1)
cout << c_weight[i];
}
cout << endl;
return;
}
pre_order(n->l_son);
pre_order(n->r_son);
}
}
int main()
{
//建立huffman tree,不同与二叉树,其是由下向上建立
My_queue my_queue;
for (int i = 0; i < 8; i++)
{
cout << "please enter the char of node\n";
char c;
cin >> c;
cout << "please enter the value of this node\n";
int k;
cin >> k;
Node *node = new Node(c,k);
my_queue.push(node);
}
//Node* n1 = my_queue.front();
//cout << n1->data << "\t" << n1->i << endl;
//只剩最后一个元素时退出循环
Node *n1 = 0, *n2 = 0;
while (my_queue.size() > 1)
{
//从队列中取出最小的两个元素
n1= my_queue.front();
n1->weight = 0;
n2 = my_queue.front();
n2->weight = 1;
//new 一个新节点,作为做小的两个节点的父节点,其权值为两个之和
Node *n = new Node((n1->i)+(n2->i));
//双向二叉树,子节点能访问父节点,父节点能访问子节点
n1->parent = n;
n2->parent = n;
n->l_son = n1;
n->r_son = n2;
//将新节点再次插入到队列中去
my_queue.push(n);
}
Node *head = my_queue.front();
//前序遍历寻找到节点
pre_order(head);
return 0;
}
//其实huffman树写出来并不难,但是这个编码问题真是想了半天,本来一直想从head节点向下递归进行编码,但是路径太复杂,所以就放弃了,最后想到何不从下往上访问父节点,最后找到head节点,这可是唯一路径,所以立马转变思路,最后终于弄出来,其中仍然存在很多问题,比如指针的删除,后续逐步优化。