简体   繁体   English

Huffman编码器-递归,编码功能失败

[英]Huffman Encoder - Recursive, coding function fail

I'm working on a Huffman code generator. 我正在研究霍夫曼代码生成器。 Below is my function to make up the tree. 下面是我组成树的功能。 The tree is based off a vector of object pointers. 该树基于对象指针的向量。 I have checked and it seems to be working properly. 我已经检查过了,看来工作正常。 I would now like to pass the pointer at position pointerVect[0] which should be the root of the tree to my Huffman encoding recursive function below, but for some reason it isn't working properly, as when i try to print the contents of the map where the codes are stored nothing prints out. 我现在想将指针传递到位置pointerVect [0],该位置应该是下面的霍夫曼编码递归函数的树的根,但是由于某些原因,它无法正常工作,例如当我尝试打印的内容时存储代码的地图不会打印任何内容。

class asciiChar  //Individual character module >>> Base Class
{

public:

    void setCharValue (char letter)
    {
        charValue = letter;
    }

    char getCharValue ()
    {
        return charValue;
    }

    void incrementCharCount ()
    {
        charCount++;
    }

    int getCharCount()
    {
        return charCount;
    }

    virtual asciiChar * getLeft()
    {
        return left;
    }

    virtual asciiChar * getRight()
    {
        return right;
    }


    asciiChar(char c, int f)  //Constructor
    {
        charValue = c;
        charCount = f;
    }


    asciiChar & operator= (const asciiChar & other)  //Overloaded assignment operator
    {
        charValue = other.charValue;
        charCount = other.charCount;

        return *this;
    }


    char charValue;
    int charCount = 0;
    asciiChar * left = NULL;
    asciiChar * right = NULL;
};


class parentNode : public asciiChar  //Connector node
{

public:

    parentNode(asciiChar c0, asciiChar c1) : asciiChar(NULL, c0.getCharCount() + c1.getCharCount())
    {
        left = &c0;
        right = &c1;

    }

    ~parentNode()
    {
        if (left) delete left;
        if (right) delete right;
    }

};


asciiChar* createTree (vector<asciiChar> sortedVector)
{
    vector<asciiChar*> pointerVect;
    pointerVect.reserve(sortedVector.size());

    for(int i=0; i < sortedVector.size(); i++)
    {
        pointerVect.push_back(new asciiChar(sortedVector[i].getCharValue(), sortedVector[i].getCharCount()));

    }

    while (pointerVect.size() > 1)
    {
        asciiChar * newL = pointerVect.back();
        pointerVect.pop_back();

        asciiChar * newR = pointerVect.back();
        pointerVect.pop_back();

        asciiChar * parent = new parentNode(* newL, * newR);
        pointerVect.push_back(parent);

        vectSort2 (pointerVect);

    }

    return pointerVect[0]; //Returns pointer at very top (The root of the tree)
}

My suspicion is with your first function 'createTree' 我怀疑您的第一个函数'createTree'

As my initial comment indicates, you should consider using a priority queue for various reasons. 正如我最初的评论所指出的,出于各种原因,您应该考虑使用优先级队列。 Here is a quick list of problems I am noticing 这是我注意到的问题的快速列表

  • You are sorting a vector of pointers. 您正在对指针向量进行排序。 So the pointers will be sorted based on their address values and not the objects they point too. 因此,将根据指针的地址值而不是指针指向的对象对指针进行排序。 However, it is possible you are supplying a comparator. 但是,有可能您提供了一个比较器。 If this is the case, ignore this bullet. 如果是这种情况,请忽略此项目符号。
  • Resorting the vector each while loop iteration is O(nLog(n)) where inserting into a priority queue and maintaining sorted order is O(Log(n)) 每个while循环迭代对向量进行重新排序是O(nLog(n)),其中插入优先级队列并保持排序顺序是O(Log(n))
  • Since you are sorting on pointers, the index of 0 for the vector isn't guaranteed to be the root of the tree. 由于您要对指针进行排序,因此不能保证向量的索引0为树的根。

Consider using a priority queue instead: In the header file 考虑改用优先级队列:在头文件中

 #include <queue>

// Comparator for priority queue. Use this so it compared what the pointers point too  and not the pointers themselves. This way the frequencies are used for the
// comparisons. This forces the priority queue to order from lowest freq
// to the highest frequency
struct CompareHuffChars : public binary_function<asciiChar*, asciiChar*, bool>
{
    bool operator()(const asciiChar* left, const asciiChar* right) const
    {
        // Be sure to add functionality to get frequency for each asciiChar object
        return left->getFrequency() > right->getFrequency();
    }
}; // end struct

priority_queue<asciiChar*,vector<asciiChar*>,CompareHuffChars > * bytePriorityQueue;
asciiChar * huffmanTree; // Pointer to assign to root node of tree when found

In the implementation file.... 在执行文件中...

while (!(this->bytePriorityQueue->empty())) {
    asciiChar * qtop = this->bytePriorityQueue->top();
    this->bytePriorityQueue->pop();
if (this->bytePriorityQueue->empty()) {
        // Found the root asciiChar node
        this->huffmanTree = qtop; // huffManTree = asciiChar *
    } else {
        // There are more asciiChar nodes so we need to grab the 2nd from top
        // and combine their frequencies into a new asciiChar node and insert it
        // back into the priority queue

        asciiChar * newNode;
        asciiCharChar * qtopSecond = this->bytePriorityQueue->top();

        // Remove it from the queue
        this->bytePriorityQueue->pop();

        // Now create a new asciiChar node with the added frequences
        // qtopSecond should always be > or = qtop
        // which will adhere to the binary tree structure

        // This assumes asciiChar adds the frequencies of qtop and qtopSecond in constructor
        newNode = new asciiChar(qtop,qtopSecond);

        // Push the new node into the p queue
        // Stays sorted with Log(n) insertion
        this->bytePriorityQueue->push(newNode);

        // Now repeat this until the tree is formed (1 node left in queue)

    } // end if

} // end while

//The p queue should now be completely empty (len =0)

}

Now my version would require a little refactoring of asciiChar. 现在,我的版本需要对asciiChar进行一些重构。 But, this method should work better than the one posted and resolve your error. 但是,此方法应该比发布的方法更好,并且可以解决您的错误。

EDIT 编辑

Okay I 'think' I have found your error. 好的,我“认为”我已找到您的错误。 In your header file for asciiChar, getLeft and getRight functions are non virtual. 在asciiChar的头文件中,getLeft和getRight函数是非虚拟的。 This means when you have a base pointer of type asciiChar * pointing to an object of type parentNode (child class) it will be invoking the parent's (asciiChar) getLeft and getRight function which will always return NULL. 这意味着,当您拥有类型为asciiChar *的基本指针指向类型为parentNode(子类)的对象时,它将调用父级的(asciiChar)getLeft和getRight函数,该函数始终返回NULL。 You re declared a left and right in your child class (parentNode) which you don't need to do since these member variables were public in your parent class. 您无需在子类(parentNode)中声明左右,因为这些成员变量在父类中是公共的,因此无需声明。 Make the getLeft and getRight functions virtual and remove the declarations for left and right in the parentNode class along with their respective getter functions. 使getLeft和getRight函数成为虚拟函数,并删除parentNode类中关于left和right的声明以及它们各自的getter函数。

// In aschiiChar
virtual asciiChar * getLeft()
{
    return left;
}

virtual asciiChar * getRight()
{
    return right;
}

Side Note: You should check in your destructors if pointers are NULL before deleting. 注意:在删除之前,您应该检查析构函数的指针是否为NULL。

if (left) delete left;
if (right) delete right;

Final Edit 最终编辑

Thanks for posting more information. 感谢您发布更多信息。 Okay your problem boiled down to the following: 好的,您的问题归结为以下几点:

// This is your parentNode constructor
parentNode(asciiChar c0, asciiChar c1) : asciiChar(NULL, c0.getCharCount() + c1.getCharCount())
{
    left = &c0;
    right = &c1;

}

// This is what the parentNode constructor should look like
parentNode(asciiChar * c0, asciiChar * c1) : asciiChar(NULL, c0->getCharCount() + c1->getCharCount())
{
    left = c0;
    right = c1;

}

and lastly... 最后...

asciiChar* createTree (vector<asciiChar> sortedVector)
{
vector<asciiChar*> pointerVect;
pointerVect.reserve(sortedVector.size());

for(int i=0; i < sortedVector.size(); i++)
{
    pointerVect.push_back(new asciiChar(sortedVector[i].getCharValue(), sortedVector[i].getCharCount()));

}

while (pointerVect.size() > 1)
{
    asciiChar * newL = pointerVect.back();
    pointerVect.pop_back();

    asciiChar * newR = pointerVect.back();
    pointerVect.pop_back();

    // CHANGE HERE
    // Don't dereference the pointers. If you dereference them you are passing by value
    // and creating copies in the constructor which are destroyed upon exit of the constructor
    asciiChar * parent = new parentNode( newL,  newR);
    pointerVect.push_back(parent);

    vectSort2 (pointerVect);

}

return pointerVect[0]; //Returns pointer at very top (The root of the tree)
}

Your problem boiled down you were passing by value and assigning the address of the local copies to member variable pointers of parentNode. 您的问题归结为您通过值传递并将本地副本的地址分配给parentNode的成员变量指针。 These pointers in parentNode were then pointing to non existent memory or memory that didn't belong to them. 然后,parentNode中的这些指针指向不存在的内存或不属于它们的内存。

Hope this helped... 希望这可以帮助...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM