1. 程式人生 > >由二叉樹構造赫夫曼樹

由二叉樹構造赫夫曼樹

family 如果 csdn img log ret iss struct center

赫夫曼樹: 如果有n個權值{w1,w2,w3....},試構造一棵具有n個葉子節點的二叉樹,每一個葉子節點帶權為wi。則當中帶權路徑長度最小的二叉樹稱為最優二叉樹或者叫赫夫曼樹構造赫夫曼樹: 如果有n個權值,則構造出的赫夫曼樹有n個葉子節點,n個權值分別設置為w1,w2,....wn,則赫夫曼樹的構造規則為: 1.將w1,w2...看成是有n棵樹的森林; 2.在森林中選擇兩個根節點的權值最小的樹合並,作為一棵新樹的左右子樹,且新樹的根節點權值為其左右子樹根節點權值之和; 3.從森林中刪除選取的兩棵樹,並將新樹增加森林。 4.反復2、3步,直到森林中僅僅剩一棵樹為止。該樹即為所求得的赫夫曼樹。 技術分享

實現: 以數組形式存儲赫夫曼樹節點,節點形態: 技術分享
/**************************************************
構造赫夫曼樹
by Rowandjj
2014/6/2
**************************************************/
#include<IOSTREAM>
using namespace std;

#define UINT_MAX 0xffffffff

typedef struct _BITREE_//二叉樹
{
    int data;//存放節點的圈中
    struct _BITREE_ *lChild;
    struct _BITREE_ *rChild;
}Bitree,*pBitree;

typedef struct _HUFFMANTREE_//赫夫曼樹
{
    unsigned int weight;
    unsigned int parent;
    unsigned int lChild;
    unsigned int rChild;
}HuffmanTree,*pHuffmanTree;

int iCount = 0;//葉子節點數
int iIndex = 1;//索引

//-----------------------------------------

void CreateBiTree(pBitree* pBitreeTemp);//創建二叉樹
void CreatreArray(pHuffmanTree& pHuffmanTreeTemp,pBitree pBitreeTemp);//將二叉樹每一個節點的值作為權放進赫夫曼樹中
pHuffmanTree InitHuffmanTree();//初始化赫夫曼樹,
void CreateHuffmanTree(pHuffmanTree& pHuffmanTreeTemp);//創建赫夫曼樹
int GetNode(pHuffmanTree& pHuffmanTreeTemp,int i);//獲取赫夫曼樹中位置0-i中值最小的節點的索引
void SelectNode(pHuffmanTree& pHuffmanTreeTemp,int i,int *m,int *n);//選擇赫夫曼樹數組中值最小的兩個節點的索引(不包括已有父節點的節點)
void DestroyTree(pBitree* pBitreeTemp);
void DestroyHuffmanTree(pHuffmanTree& pHuffmanTreeTemp);
int main()
{
    int i;
    //創建二叉樹
    pBitree pBitreeTemp;
    CreateBiTree(&pBitreeTemp);
    //初始化赫夫曼樹
    pHuffmanTree pHuffmanTreeTemp = InitHuffmanTree();

    //初始化赫夫曼樹的葉子節點的權
    CreatreArray(pHuffmanTreeTemp,pBitreeTemp);
    for(i = 1; i <= iCount ; i++)
    {
        cout<<pHuffmanTreeTemp[i].weight<<" ";
    }
    cout<<endl;
    //創建赫夫曼樹
    CreateHuffmanTree(pHuffmanTreeTemp);
    for(i = 1; i <= 2*iCount-1 ; i++)
    {
        cout<<pHuffmanTreeTemp[i].weight<<" ";
    }
    cout<<endl;

    DestroyTree(&pBitreeTemp);
    DestroyHuffmanTree(pHuffmanTreeTemp);
    return 0;
}

void CreateBiTree(pBitree* pBitreeTemp)
{
    int data;
    cin>>data;
    if(data == -1)
    {
        return;
    }
    *pBitreeTemp = (pBitree)malloc(sizeof(Bitree));
    if(*pBitreeTemp == NULL)
    {
        return;
    }
    (*pBitreeTemp)->data = data;
    (*pBitreeTemp)->lChild = NULL;
    (*pBitreeTemp)->rChild = NULL;

    CreateBiTree(&(*pBitreeTemp)->lChild);
    CreateBiTree(&(*pBitreeTemp)->rChild);

    iCount++;
}
pHuffmanTree InitHuffmanTree()
{
    int num = 2*iCount - 1;//赫夫曼樹的節點總數為:葉子節點數*2-1
    pHuffmanTree pTemp = (pHuffmanTree)malloc(sizeof(HuffmanTree)*(num+1));//0位不存
    if(pTemp == NULL)
    {
        return NULL;
    }
    for(int i = 0; i <= num; i++)
    {
        pTemp[i].lChild = 0;
        pTemp[i].rChild = 0;
        pTemp[i].parent = 0;
        pTemp[i].weight = 0;
    }
    return pTemp;
}
void CreatreArray(pHuffmanTree& pHuffmanTreeTemp,pBitree pBitreeTemp)
{
    if(pBitreeTemp == NULL || pHuffmanTreeTemp == NULL)
    {
        return;
    }
    pHuffmanTreeTemp[iIndex].weight = pBitreeTemp->data;
    iIndex++;
    CreatreArray(pHuffmanTreeTemp,pBitreeTemp->lChild);
    CreatreArray(pHuffmanTreeTemp,pBitreeTemp->rChild);
}
int GetNode(pHuffmanTree& pHuffmanTreeTemp,int i)
{
    int min = UINT_MAX;
    int flag;
    for(int j = 1; j <= i; j++)
    {
        if(pHuffmanTreeTemp[j].weight < min && pHuffmanTreeTemp[j].parent == 0)//已有父節點的不算
        {
            min = pHuffmanTreeTemp[j].weight;
            flag = j;
        }
    }
    pHuffmanTreeTemp[flag].parent = 1;//防止兩次調用獲取的索引同樣
    return flag;
}
void SelectNode(pHuffmanTree& pHuffmanTreeTemp,int i,int *m,int *n)//m為序號小的那個
{
    *m = GetNode(pHuffmanTreeTemp,i);
    *n = GetNode(pHuffmanTreeTemp,i);

    int t;
    if(*m > *n)
    {
        t = *m;
        *m = *n;
        *n = t;
    }
}

void CreateHuffmanTree(pHuffmanTree& pHuffmanTreeTemp)
{
    if(pHuffmanTreeTemp == NULL)
    {
        return;
    }
    int m = 0,n = 0;
    for(int i = iCount+1;i <= 2*iCount-1; i++)
    {
        SelectNode(pHuffmanTreeTemp,i-1,&m,&n);
        pHuffmanTreeTemp[m].parent = pHuffmanTreeTemp[n].parent = i;
        //構造兩個最小權重的節點的父節點
        pHuffmanTreeTemp[i].lChild = m;
        pHuffmanTreeTemp[i].rChild = n;
        pHuffmanTreeTemp[i].weight = pHuffmanTreeTemp[m].weight+pHuffmanTreeTemp[n].weight;
    }

}

void DestroyTree(pBitree* pBitreeTemp)
{
    if(*pBitreeTemp == NULL)
    {
        return;
    }
    if((*pBitreeTemp)->lChild)
    {
        DestroyTree(&(*pBitreeTemp)->lChild);
    }
    if((*pBitreeTemp)->rChild)
    {
        DestroyTree(&(*pBitreeTemp)->rChild);
    }
    free(*pBitreeTemp);
    *pBitreeTemp = NULL;
}

void DestroyHuffmanTree(pHuffmanTree& pHuffmanTreeTemp)
{
    if(pHuffmanTreeTemp)
    {
        free(pHuffmanTreeTemp);
    }
    pHuffmanTreeTemp = NULL;
}
測試: 技術分享 圖解構造過程: 1.首先將二叉樹中的節點所有存到代表赫夫曼樹的數組中。其余位置為0: 技術分享
2.循環遍歷該數組。每次找到最小權重的兩個節點。之和作為其父節點的權重
技術分享
3.循環一遍後。便得到赫夫曼樹:
技術分享




由二叉樹構造赫夫曼樹