哈夫曼樹(代碼實現(xiàn))

前面我們介紹了哈夫曼樹的理論實現(xiàn),現(xiàn)在介紹一下具體代碼實現(xiàn)。

我們先定義哈夫曼樹節(jié)點的數(shù)據(jù)結(jié)構(gòu)。

struct haffManTreeNode // 哈夫曼樹的節(jié)點
{
    char symbol;          //存儲的符號
    int weight;        //權(quán)重
    haffManTreeNode* lChild;
    haffManTreeNode* rChild;
};

struct haffManTreeRoot  //為了方便,特別定義一個根節(jié)點
{
    haffManTreeNode* next;
};

haffManTreeNode* initHaffManTreeNode(char symbol,int weight)
{
//初始化一個樹節(jié)點
    haffManTreeNode* tree = new haffManTreeNode;
    tree->lChild = NULL;
    tree->rChild = NULL;
    tree->symbol = symbol;
    tree->weight = weight;
    return tree;
}

在有了樹節(jié)點之后,我們需要一個鏈表結(jié)構(gòu)來存儲不同節(jié)點的權(quán)值,并將他們排序,用這些節(jié)點來構(gòu)成我們的哈夫曼樹。

struct haffManQueue  //定義的鏈表結(jié)構(gòu)
{
    haffManTreeNode* tree;   //存儲哈夫曼樹的節(jié)點
    int weight;               //節(jié)點的權(quán)重
    haffManQueue* next;
};

struct haffManQueueHead  //為了方便,定義一個頭鏈表,存儲鏈表大小
{
    int size;
    haffManQueue* next;
};

haffManQueue* initQueue()
{
//初始化鏈表節(jié)點
    haffManQueue* queue = new haffManQueue;
    queue->weight = 0;
    queue->tree = NULL;
    queue->next = NULL;
    return queue;
}

在定義完了最基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)后,我們需要獲得一個數(shù)組,用來存儲一段文本的單個字符出現(xiàn)次數(shù)(權(quán)重),這里,我們利用數(shù)組下標(biāo)實現(xiàn)這個功能。

void getWeight(string& str,int (&weight)[256])
{
//在這里,我們傳入一個數(shù)組,與文本字符串
//注:(1)我們需要傳入數(shù)組的引用,因為我們需要用形參影響實參
//(2)我們傳入的數(shù)組大小為256位,正好是全部字符的個數(shù)
    for(int i=0;i <= 255;i++)
    {
//初始化數(shù)組
        weight[i] = 0;
    }
    int count = str.length();
    for(int i=0;i < count;i++)
    {
//利用ascii碼唯一對應(yīng)的數(shù)字來標(biāo)注
        weight[ (char)str[i] ]++;
    }
}

接下來,我們擁有了這個權(quán)重數(shù)組,那么我們需要的就是按照哈夫曼樹的建立過程實現(xiàn)代碼。

//先定義插入函數(shù),可以更加簡單。。。這里寫的有些復(fù)雜
//注:同樣,我們需要傳入head的引用,因為我們需要在函數(shù)中改變其中指針的值
void insertQueue(haffManQueueHead* (&head),haffManQueue* (&inserter),haffManQueue* (&address))
{
    //在address指針后面插入inserter指針,若address為NULL,則表示在表頭后插入
    if(address == NULL)
    {
        inserter->next = head->next;
        head->next = inserter;
    }
    else if(address->next == NULL)
    {
        address->next = inserter;
    }
    else
    {
        inserter->next = address->next;
        address->next = inserter;
    }
}

//定義取值函數(shù),取出當(dāng)前鏈表中權(quán)重最小的節(jié)點
haffManQueue* getQueueItem(haffManQueueHead* (&head))
{
    if(head->size == 0)
    {
        return NULL;
    }
    haffManQueue* temp = head->next;
    head->next = head->next->next;
    head->size--;
    return temp;
}

//由權(quán)重數(shù)組,得到哈夫曼隊列
haffManQueueHead* initHaffManQueue(int (&weight)[256])
{
//建立表頭
    haffManQueueHead* head = new haffManQueueHead;
    head->next = NULL;
    head->size = 0;

    for(int i=0;i <= 255;i++)
    {
        if(weight[i] != 0)
        {
            if(head->size == 0)
            {
//如果整個鏈表沒有元素,直接插入為第一個
                haffManQueue* queue = initQueue();
                queue->tree = initHaffManTreeNode((char)i,weight[i]);
                queue->weight = queue->tree->weight;

                head->next = queue;
                head->size++;
            }
            else
            {
                haffManQueue* queue = initQueue();
                queue->tree = initHaffManTreeNode((char)i,weight[i]);
                queue->weight = queue->tree->weight;

//定義兩個指針,用來插入節(jié)點
                haffManQueue* temp = head->next;
//指向當(dāng)前節(jié)點的前一個元素,因為是單向鏈表,無法知道之前的元素地址
                haffManQueue* preNode = NULL;   

                while(queue->weight > temp->weight && temp != NULL)
                {
                    preNode = temp;
                    temp = temp->next;
                }
                insertQueue(head,queue,preNode);
                head->size++;
            }
        }
    }
    return head;
}

//在得到哈夫曼隊列之后,我們便可以建立我們的哈夫曼樹了
haffManTreeRoot* creataHaffManTree(haffManQueueHead* (&head))
{
//初始化哈夫曼樹的根節(jié)點
    haffManTreeRoot* root = new haffManTreeRoot;
    root->next = NULL;
    if(head->size == 0)
    {
        return root;
    }
    else
    {
        while(head->size != 1)
        {
//當(dāng)鏈表大小為一時,退出循環(huán)
            haffManQueue* lChild = getQueueItem(head);
            haffManQueue* rChild = getQueueItem(head);

            haffManQueue* newNode = initQueue();
//用'\0',來填充新節(jié)點的符號位,權(quán)重為兩個子樹權(quán)重之和
            newNode->tree = initHaffManTree('\0',lChild->weight+rChild->weight);
//將兩個節(jié)點作為新節(jié)點的子樹
            newNode->tree->lChild = lChild->tree;
            newNode->tree->rChild = rChild->tree;
            newNode->weight = newNode->tree->weight;

//重新插入回鏈表,排序
            if(head->size == 0)
            {
                head->next = newNode;
                head->size++;
            }
            else
            {
                haffManQueue* temp = head->next;
                haffManQueue* preNode = NULL;

                while(newNode->weight > temp->weight && temp != NULL)
                {
                    preNode = temp;
                    temp = temp->next;
                }
                insertQueue(head,newNode,preNode);
                head->size++;
            }
        }
    }
    root->next = head->next->tree;
    return root;
}

這就是我個人關(guān)于哈夫曼樹的實現(xiàn)過程。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 樹的概述 樹是一種非常常用的數(shù)據(jù)結(jié)構(gòu),樹與前面介紹的線性表,棧,隊列等線性結(jié)構(gòu)不同,樹是一種非線性結(jié)構(gòu) 1.樹的定...
    Jack921閱讀 4,489評論 1 31
  • 百度百科定義 給定n個權(quán)值作為n個葉子結(jié)點,構(gòu)造一棵二叉樹,若帶權(quán)路徑長度達(dá)到最小,稱這樣的二叉樹為最優(yōu)二叉樹,也...
    scarerow閱讀 1,448評論 0 2
  • 簡介 哈夫曼樹是一種帶權(quán)路徑長度最短的二叉樹,也稱為最優(yōu)二叉樹。 定義:給定 n 個權(quán)值作為 n 個葉子節(jié)點,構(gòu)造...
    隨時學(xué)丫閱讀 3,249評論 0 1
  • 定義指針變量,如果不賦給它地址,系統(tǒng)會隨機給它分配一個地址。 C++標(biāo)準(zhǔn)庫 C++ Standard Librar...
    縱我不往矣閱讀 304評論 0 1
  • 應(yīng)該要把swift提上緊急日程了。 來自一線開發(fā)者的Swift學(xué)習(xí)資源推薦 2016年關(guān)于swift大牛的文章 猿...
    Funnyer閱讀 247評論 0 0