考古一下,大一用C++写的哈夫曼树,环境VS2017。
main函数里改一下文件路径即可运行,输入的是txt文件,文件里最好不要有中文,不然会显示一堆问号;输出哈弗曼编码之后的结果。
但是代码还是有很多问题,当年为了图方便把一些变量和对象搞成了全局的,直接在函数里操作了,这样显然还是不够,还可以改进。
#include
#include
#include
using namespace std;
template<typename E> void swap(E *temp1, E *temp2) //用于排序的交换函数
{
E temp = *temp1;
*temp1 = *temp2;
*temp2 = temp;
}
int SIZE; //总结点个数
int sum; //总权值
template<typename E> class HaffmanNode { //Haffman结点类
public:
E element;
int weight;
HaffmanNode<E>*left;
HaffmanNode<E>*right;
bool isLeaf;
int parent;
HaffmanNode() {} //构造函数
HaffmanNode(const E&Elem, int wgt,HaffmanNode<E>*le = NULL, HaffmanNode<E>*ri = NULL) {
element = Elem;
weight = wgt;
left = le;
right = ri;
isLeaf = true;
}
HaffmanNode(int wgt, HaffmanNode<E>*le, HaffmanNode<E>*ri) {
weight = wgt;
left = le;
right = ri;
isLeaf = false;
}
void operator =(HaffmanNode<E> temp) { //重载=号
element = temp.element;
weight = temp.weight;
left = temp.left;
right = temp.right;
isLeaf = temp.isLeaf;
}
};
int n = 0; //仅第一次输出“根结点”,这是一个开关
template<typename E> void preorder(HaffmanNode<E>*root) { //前序遍历
if (root == NULL) { return;}
if (root->isLeaf) cout << " 叶子结点 元素:" << root->element << " " << "权值:" << root->weight <<" ";
if (!root->isLeaf) {
if (!n) {
cout << "逐层打印Haffman树:" << endl << endl;
cout << "根结点:权值" << root->weight << " "; n=1;
}
else
cout << "分支结点:权值" << root->weight << " ";
cout << "(左结点是";
if (root->left->isLeaf)
cout << "叶子结点【" << root->left->element<<","<< root->left->weight << "】 ";
else
cout << "分支结点 权值:" << root->left->weight << " ";
cout << "右结点是";
if (root->right->isLeaf)
cout << "叶子结点 【" << root->right->element << "," << root->right->weight << "】) ";
else
cout << "分支结点 权值:" << root->right->weight << " ) ";
cout << endl;
}
preorder(root->left);
preorder(root->right);
}
template<typename E> class NODE { //队列结点类
public:
HaffmanNode<E>*element;
NODE *next;
NODE( HaffmanNode<E>* elemval, NODE*nextval = NULL) { //有初始化元素值结点构造函数
element = elemval;
next = nextval;
}
NODE(NODE*nextval = NULL) { //无初始化元素值结点构造函数
next = nextval;
}
};
template <typename E> class Queue :public NODE<E> { //队列实现
private:
NODE<E>*front;
NODE<E>*rear;
int Size;
public:
Queue() {
front = rear = new NODE<E>();
Size = 0;
}
~Queue() {
while (front->next != NULL) {
rear = front;
delete rear;
}
rear = front;
delete front;
Size = 0;
}
void InQueue( HaffmanNode<E>*it) { //入队函数
rear->next = new NODE<E>(it, NULL);
rear = rear->next;
Size++;
}
void OutQueue() { //出队函数
NODE<E>*temp = front->next;
front->next = temp->next;
if (temp == rear)
rear = front;
delete temp;
Size--;
}
int length() { //长度函数
return Size;
}
HaffmanNode<E>* frontvalue() { //队首元素
return front->next->element;
}
HaffmanNode<E>* rearvalue() { //队尾元素
return rear->element;
}
NODE<E>* frontnode() { // 队首结点
return front->next;
}
NODE<E>* rearnode() { // 队尾结点
return rear;
}
void display() { //显示队列函数
if (Size == 0) {
cout << "空队列!" << endl;
return;
}
NODE<E>*p = front;
do {
p = p->next;
if (p->element->isLeaf)
cout << "叶子结点 元素:" << p->element->element << " " << "权值:" << p->element->weight << endl;
else {
cout << "分支结点:(总权值"<<p->element->weight<<")";
cout << " 左结点是";
if (p->element->left->isLeaf)
cout << "叶子结点 元素:" << p->element->left->element << " " << "权值:" << p->element->left->weight <<" ";
else
cout << "分支结点 权值:" << p->element->left->weight<<" ";
cout << "右结点是";
if (p->element->right->isLeaf)
cout << "叶子结点 元素:" << p->element->right->element << " " << "权值:" << p->element->right->weight << " ";
else
cout << "分支结点 权值:" << p->element->right->weight<<" ";
cout << endl;
}
} while (p->next != NULL);
cout << endl;
}
int x; //统计排序次数的变量
void sort() { //排序函数
NODE<E>*p = NULL;
NODE<E>*q = NULL;
p = front->next;
for (int i = 1; i < SIZE; i++) {
if (p->next == NULL) break;
q = p->next;
for (int j = 0; j < SIZE - i; j++) {
if (q == NULL) break;
if ((p->element->weight) >(q->element->weight))
swap(p->element, q->element);
q = q->next;
}
p = p->next;
}
p = front->next; //重复元素位置交换
for (int i = 1; i < SIZE; i++) {
if (p->next == NULL) break;
q = p->next;
for (int j = 0; j < SIZE - i; j++) {
if (q == NULL) break;
if ((p->element->weight) == (q->element->weight))
swap(p->element, q->element);
q = q->next;
}
p = p->next;
}
x++;
cout << "第"<<x<<"次:"<<endl;
display();
}
};
template<typename E>class Link //链表的结点类
{
public:
E element;
Link<E>*next;
Link(const E&elemval, Link<E>* nextval = NULL)
{
element = elemval;
next = nextval;
}
Link(Link<E>* nextval = NULL)
{
next = nextval;
}
};
template<typename E>class Linklist :public Link<E> //链表实现
{
private:
Link<E> *head;
Link<E> *tail;
Link<E> *curr;
int count;
public:
Linklist() {
curr = tail = head = new Link<E>;
count = 0;
}
~Linklist() {
while (head != NULL) {
curr = head;
head = head->next;
delete curr;
}
}
void display()
{
for (curr = head; curr->next != NULL; curr = curr->next)
cout << curr->next->element;
cout << endl;
}
void append(const E &it)
{
tail = tail->next = new Link<E>(it, NULL);
count++;
}
void LastFront() //curr移至最后一个节点前
{
curr = head;
if (curr->next == NULL)
return;
while (curr->next != tail)
{
curr = curr->next;
}
}
void DeleteLast() { //删除尾结点
if (head->next == NULL) {
return;
}
LastFront();
Link<E>*temp = tail;
tail = curr;
tail->next = NULL;
delete temp;
count--;
}
};
int k = 1;
Linklist<int> Llist;
void Code(HaffmanNode<char>*root) { //编码
if (k) {
cout << endl<<endl;
cout << "编码:" << endl;
k = 0;
}
if (root == NULL)return;
if (root->element != '\0') {
cout << root->element<<":";
Llist.display();
return;
}
Llist.append(0);
Code(root->left);
Llist.DeleteLast();
Llist.append(1);
Code(root->right);
Llist.DeleteLast(); //递归
}
HaffmanNode<char> *hfm[128];
Queue<char> Q;
void InFILE(string s) //读文件,建立队列
{
string str = "";
fstream File;
char c;
File.open(s, ios::in);
do {
File >> c;
str += c;
} while (!File.eof());
int X = str.length();
str.erase(X - 1, 1);
cout << "读出文件:" << endl;
cout << str << endl;
File.close();
int x = str.length();
char *jd = new char[x]; //结点
int *qz = new int[x]; //权值
for (int i = 1; i < x; i++) { qz[i] = 0; jd[i] = '\0'; }
jd[0] = str[0]; qz[0] = 1; int size = 1; int k = 0;
for (int i = 1; i < x; i++) { //开始统计
for (k = 0; k <size; k++) {
if (jd[k] == str[i]) {
qz[k]++;
goto L;
}
else
{
continue;
}
}
jd[k] = str[i];
qz[k]++;
size++;
L:
continue;
}
cout <<endl<< "统计所有元素及其权值,排序如下:" << endl;
for (int m = 1; m<size; m++) //排序
for (int n = m; n > 0; n--)
{
if (qz[n] < qz[n - 1]) {
swap(qz[n], qz[n - 1]);
swap(jd[n], jd[n - 1]);
}
}
for (int i = 0; i < size; i++) {
sum += qz[i];
cout << jd[i] << " " << qz[i] << endl;
}
cout << endl;
SIZE = size;
for (int i = 0; i < SIZE; i++)
{
hfm[i] = new HaffmanNode<char>(jd[i], qz[i]); //封装
Q.InQueue(hfm[i]); //建队列
}
cout << "创建队列 :" << endl;
Q.display();
cout << endl << "队列创建完成!" << endl;
}
void buildTree() { //建立哈夫曼树
cout << "开始建立Haffman树:" << endl;
while (Q.rearvalue()->weight < sum) {
int we = Q.frontvalue()->weight + Q.frontnode()->next->element->weight;
HaffmanNode<char>*temp1 = Q.frontvalue();
Q.OutQueue();
HaffmanNode<char>*temp2 = Q.frontvalue();
Q.OutQueue();
HaffmanNode<char>*temp = new HaffmanNode<char>(we, temp1, temp2);
Q.InQueue(temp);
Q.sort();
};
cout << "Haffman树建立成功!" << endl << endl;
}
int main() {
InFILE("d:\\code.txt"); //数据的统计与预处理
buildTree(); //建树
HaffmanNode<char>*temp = Q.rearvalue();
preorder(temp); //前序遍历,打印
Code(temp); //编码并输出
system("pause");
return 0;
}