huffman树和huffman编码

不知道为什么,我写的代码都是又臭又长。

直接上代码:

#include <iostream>
#include <cstdarg>
using namespace std;
class Node{
public:
    int weight;
    int parent, lChildren, rChildren;
    Node(int weight, int parent, int lChildren, int rChildren):
            weight(weight), parent(parent), lChildren(lChildren), rChildren(rChildren)
    {
    }
    
    void printNode(){
        cout<<"weight = "<<weight<<", ";
        cout<<"parent = "<<parent<<", ";
        cout<<"lChildren = "<<lChildren<<", ";
        cout<<"rChildren = "<<rChildren<<endl;
    }
};

class Tree{
    Node **nodes;
    char** huffmanCodec;
    int length,rPos;
    int mNum;
    /**给Tree实例增加Node。
      *
      **/
    void addNode(Node *node){
        if(!node){
            cout<<"addNode中,指针为NULL"<<endl;
            return;
        }
        for(int i = 0; i < length; i++){
            if(node == nodes[i])//如果存在了就不必加到里面了。。
                return;
        }
        nodes[length++] = node;
    }
    /**从数组array中找到最小的两个数值,赋给v1和v2
      *
      **/
    void findSmallest2ValueInArray(int *array, int length, int *v1, int *v2, int *v1Pos, int *v2Pos){
        int t = 0;
        for(int i = 0; i < length; i++){
            if(array[i] < 0)
                continue;
            ++t;
            if(t == 1){
                *v1 = array[i];
                *v1Pos = i;
            }else if (t == 2){
                *v2 = array[i];
                *v2Pos = i;
            }else{
                if(*v1 > array[i]){
                    if(*v1 < *v2){
                        *v2 = *v1;
                        *v2Pos = *v1Pos;
                    }
                    *v1 = array[i];
                    *v1Pos = i;
                }else if(*v2 > array[i]){
                    *v2 = array[i];
                    *v2Pos = i;
                }
            }
        }
    }
    
    /**
    *从当前Tree中找到给定node的下标。生成huffman编码用的。
    *
    **/
    int findNodePosViaNode(Node *node){
        for(int i = 0; i < length; i++){
            if(nodes[i] == node){
                return i;
            }
        }
        return -1;
    }
    
    /**
    *从当前Tree中找到给定Weight的node的下标, 并且该node没有parent。生成树结构用的。
    *
    **/
    int findNodePosViaWeight(int value, bool isForParent, bool isTheSameWeightNode){
        for(int i = 0; i < length; i++){
            if(nodes[i]->parent == -1 && nodes[i]->weight == value && !isForParent && !isTheSameWeightNode){
                return i;
            }
        }
        return -1;
    }
    /**
    *从头至尾找到叶子结点。
    *
    **/
    int findHuffmanNodePos(){
        static int mark;//默认初始化为0
        for(int i = mark; i < length; i++){
            if(nodes[i]->lChildren == -1 && nodes[i]->rChildren == -1){
                mark = i + 1;
                return i;
            }
        }
        return -1;
    }
    
    /**
    *初始化node
    *
    **/
    Node* getNode(Node *node, int value, int parent, int lChildren, int rChildren, bool isForParent, bool isTheSameWeightNode){//最后一个参数,解决这种情况,如果v1是20,
                                                                                                                               //并且v1已经在树中了,然后v2也是20.
                                                                                                                               //这时候要求v2要new一个新的节点。
        if(node){
            cout<<"getNode中,指针未初始化为NULL"<<endl;
            return NULL;
        }
        int pos = findNodePosViaWeight(value, isForParent, isTheSameWeightNode);
        if(pos != -1){
            node = nodes[pos];
        }else{
            node = new Node(value, parent, lChildren, rChildren);
        }
        return node;
    }
    
    /**
    *把一个数组初始化为全是-1的数组。
    *
    **/
    void initArray2Zero(int *array, int length){
        for(int i = 0; i < length; i++){
            array[i] = -1;
        }
    }
    
    /**
    *打印一个int数组
    */
    
    void printIntArray(int *array, int length){
        cout<<"[";
        for(int i = 0; i < length - 1; i++){
            cout<<array[i]<<", ";
        }
        cout<<array[length - 1]<<"]"<<endl;
    }
    
    /**
    *for debug
    */
    void debug(int i){
        cout<<"debug "<<i<<endl;
    }
    /**
    *根据huffman树生成huffman编码。
    */
    char** generateHuffmanCodec(int num){
        int topIndex = 0;
        huffmanCodec = new char*[num];//分配空间
        for(int i = 0; i < num; i++){
            int index = 0;
            char *data = new char[num + 1];//每一个节点的存储单位
            int thisPos = findHuffmanNodePos();
            Node *currentNode = nodes[thisPos];
            while(currentNode->parent != -1){
                Node *currentParent = nodes[currentNode->parent];
                if(thisPos == currentParent->lChildren){//0
                    data[index++] = '0';
                }else if(thisPos == currentParent->rChildren){//1
                    data[index++] = '1';
                }else{//X, never in.
                    data[index++] = 'X';
                }
                thisPos = currentNode->parent;
                currentNode = currentParent;
            }
            data[index] = '\0';
            huffmanCodec[topIndex++] = data;
        }
        return huffmanCodec;
    }
 
public:
   /**
    *创造一棵树。
    *
    **/
    void makeTree(int num, ...){
        int weightArray[num];
        initArray2Zero(weightArray, num);
        va_list list;
        va_start(list, num);
        for(int i = 0; i < num; i++){
            weightArray[i] = va_arg(list, int);
        }
        va_end(list);
        printIntArray(weightArray, num);//debug
        int debug_x = 100;
        while(true){
            int v1 = -1, v2 = -1, v1Pos = -1, v2Pos = -1;
            findSmallest2ValueInArray(weightArray, num, &v1, &v2, &v1Pos, &v2Pos);
            if(v1 == -1 || v2 == -1){
                cout<<"v1或v2至少有一个是-1, 没被赋值"<<endl;
                break;
            }
            
            Node *node1 = NULL;
            node1 = getNode(node1, v1, -1, -1, -1, false, false);
            addNode(node1);//如果已经存在就不必add。
            
            Node *node2 = NULL;
            node2 = getNode(node2, v2, -1, -1, -1, false, v1 == v2);//万一v1和v2相等,如果不加这个force,那么本来有2个权值相等的节点,就会少添加到树中一个。
            addNode(node2);
            
            Node *parent = NULL;
            parent = getNode(parent, v1 + v2, -1, -1, -1, true, false);//最后这个参数,在于判断是否是寻找的是parent。如果是parent,那么就算树中已经存在了相同节点,但是也要new一个新节点。
                                                                       //因为树中的节点不是已经有了孩子 就是叶子节点了。都不能做parent了,所以要重新生成。
            addNode(parent);
            
            node1->parent = findNodePosViaNode(parent);
            node2->parent = node1->parent;
            
            parent->lChildren = findNodePosViaNode(node1);
            parent->rChildren = findNodePosViaNode(node2);
            
            weightArray[v1Pos] = -1;
            weightArray[v2Pos] = v1 + v2;
            printIntArray(weightArray, num);//debug
        }
        mNum = num;
        generateHuffmanCodec(num);        
    }
    
    /**
    *打印huffman树
    *
    **/
    void printTree(){
        for(int i = 0; i < length; i++){
            cout<<"pos = "<<i<<", ";
            nodes[i]->printNode();
            //cout<<findHuffmanNodePos()<<endl;
        }
    }
    
    /**
    *打印哈夫曼编码
    */
    
    void printHuffman(){
        cout<<"------huffman codec begin-----\n";
        
        for(int i = 0; i < mNum; i++){
            cout<<huffmanCodec[i]<<endl;
        }
        cout<<"------huffman codec end-----\n";
    }
    
    /**
    *构造函数与析构函数
    */
    Tree(): nodes(new Node*[100]), huffmanCodec(NULL), length(0), rPos(-1), mNum(0){//为何是int呢?因为我想数组中存储的是Node*,是一个指针,指针应该可以用int来存储。
    }
    ~Tree(){
        cout<<"析构"<<endl;
        delete []nodes;
        if(huffmanCodec) 
            delete []huffmanCodec;
    }
};


int main(){
    Tree *tree = new Tree;
    tree->makeTree(8, 5, 29, 7, 8, 14, 23, 3, 11);
    
    tree->printTree();
    
    tree->printHuffman();
    delete tree;
}
书上的例子才30行代码,我写了300行,为什么会这样呢,挺奇怪的,估计还是修炼不够。得努力!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值