最小堆建立哈夫曼樹及各種操作


數據結構與算法實驗報告               姓名:孫瑞霜 

 

一、實驗目的

1、復習Huffman樹及其創建等基本操作; 

2、掌握最小堆的定義及其建立、插入刪除等操作的實現。

3、掌握Huffman編碼的方法。

二、實驗要求

1. 認真閱讀和掌握教材上和本實驗相關內容和算法。

2. 上機將相關算法實現。

3實現上面實驗目的要求的功能,並能進行簡單的驗證

、實驗內容

1、 必做內容:Huffman樹的創建

按照課本上最小堆(代碼4.26,改成最小堆)及建立Huffman樹的算法(代碼4.27),編程實現Huffman樹的建立。要求能夠進行簡單的輸入輸出驗證,輸出建好后的Huffman樹的形態,比如輸出其先序和中序遍歷序列。 

typedef struct TreeNode *HuffmanTree;

struct TreeNode{

int Weight;

HuffmanTree Left;

HuffmanTree Right;

};

2、 選做內容:實現Huffman編碼,並進行簡單輸入輸出驗證,比如輸入一些字符及其權值,輸出每種字符的Huffman編碼。可以查閱資料,結合程序進行分析,其存儲結構及其操作上和建立Huffman樹有何異同。 

三、算法描述

        首先我們應明確什么是哈夫曼樹,假設n個權值,構造有n個葉子結點的二叉樹,每個葉子結點的權值是n個權值之一其中帶權路徑長度最小的一棵就是哈夫曼樹。在哈夫曼樹的構造過程中,選取兩棵根結點權值最小的樹作為左、右子樹,每次將權值最小的兩棵樹進行合並,構造成一新的二叉樹,置新二叉樹根結點的權值等於左、右子樹根結點的權值之和。從集合中刪除作為左、右子樹的兩棵二叉樹,並將新構造的二叉樹加入到集合中;重復操作,直到集合中只含一棵二叉樹為止,這棵二叉樹便是要建立的哈夫曼樹。

四、詳細設計

 

五、程序代碼

#include<stdio.h>

#include<stdlib.h>

#define MinData -1

typedef struct TreeNode *HuffmanTree;//哈夫曼樹類型

struct TreeNode{

int Weight;  //結點權值

HuffmanTree Left;//指向左子樹

HuffmanTree Right;//指向右子樹

}HuffmanNode;//定義新的結構變量

  

typedef struct HeapStruct *MinHeap;

struct HeapStruct{

HuffmanTree *Data;  //存儲堆元素的數組  存儲時從下標1開始

int Size;  //堆的當前元素的個數

int Capacity;  //堆的最大容量

};

 

HuffmanTree NewHuffmanNode();

//構造新的哈夫曼樹

MinHeap CreateMinHeap(int MaxSize);

//創建容量為MaxSize的最小堆

bool Insert(MinHeap H,HuffmanTree item);

//將元素item插入到最小堆H

HuffmanTree DeleteMin(MinHeap H);

//從最小堆H中取出權值為最小的元素,並刪除一個結點

MinHeap BuildMinHeap(MinHeap H);

//H->data[]按權值調整為最小堆

HuffmanTree Huffman(MinHeap H);

//最小堆構造哈夫曼樹

void PreOrderTraversal(HuffmanTree BST);

//先序遍歷哈夫曼樹

 

int main()

{

int i,N;

MinHeap h;

HuffmanTree T,BT = NULL;

 

printf("輸入葉子結點的個數:\n");

scanf("%d",&N);

h = CreateMinHeap(2*N);  //創建最小堆

printf("輸入%d個葉子結點對應的權值:\n",N);

for(i=1; i<=N; i++){/*最小堆元素賦值*/

T = NewHuffmanNode();

scanf("%d",&(T->Weight));

h->Data[++(h->Size)] = T;

}

BT = Huffman(h);  //構造哈夫曼樹

printf("先序遍歷此哈夫曼樹:\n");

PreOrderTraversal(BT);  //先序遍歷哈夫曼樹

 

return 0;

 }

  /*哈夫曼樹構造算法*/

 HuffmanTree Huffman(MinHeap H)

 {/*假設H->Size個權值已經存在H->data[]->Weight*/

  int i,n;

HuffmanTree T;

 

BuildMinHeap( H );  //H->data[]按權值調整為最小堆

/*此處必須將H->Size的值交給num,因為后面做DeleteMin()Insert()函數會改變H->Size的值*/

n = H->Size;     

for(i=1; i<n; i++){  //H->Size-1次合並

T = NewHuffmanNode();  //建立一個新的根結點

T->Left = DeleteMin(H);  //從最小堆中刪除一個節點,作為新T的左子結點

T->Right = DeleteMin(H);  //從最小堆中刪除一個節點,作為新T的右子結點

T->Weight = T->Left->Weight+T->Right->Weight;  //計算新權值

Insert(H,T);  //將新T插入到最小堆

}

T = DeleteMin(H);

 

return T;

  }

  

//先序遍歷哈夫曼樹

void PreOrderTraversal(HuffmanTree BST)

{

if( BST ){

printf("%d ",BST->Weight);     //先訪問根節點

PreOrderTraversal(BST->Left);  //再訪問左子樹

PreOrderTraversal(BST->Right); //最后訪問右子樹

}

}

 

HuffmanTree NewHuffmanNode()

{

HuffmanTree BST = (HuffmanTree)malloc(sizeof(HuffmanNode));

BST->Weight = 0;

BST->Left = BST->Right = NULL;

 

return BST;

 }  

  

MinHeap CreateMinHeap(int MaxSize)

{  /*創建容量為MaxSize的最小堆*/

MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));

H->Data = (HuffmanTree *)malloc((MaxSize+1) * sizeof(HuffmanTree));

H->Size = 0;

H->Capacity = MaxSize;

HuffmanTree T = NewHuffmanNode();

T->Weight = MinData;  /*定義哨兵-為小於堆中所有可能元素權值的值,便於以后更快操作*/

H->Data[0] = T;

 

return H;

}

 //插入新增節點

bool  IsFull(MinHeap H)

{

return (H->Size == H->Capacity);

}

 

bool IsEmpty(MinHeap H)

{

return (H->Size == 0);

}

 

 

bool Insert(MinHeap H,HuffmanTree item)

{        //將元素item插入到最小堆H

int i;

if( IsFull(H) ){

printf("最小堆已滿\n");

return false;

}

i = ++H->Size;  //i指向插入后堆中的最后一個元素的位置

for(; H->Data[i/2]->Weight > item->Weight; i/=2)  //無哨兵,則增加判決條件 i>1

    H->Data[i] = H->Data[i/2];  //向下過濾結點

H->Data[i] = item;   //item插入

 

return true;

 }

 

HuffmanTree DeleteMin(MinHeap H)

{/*從最小堆H中取出權值為最小的元素,並刪除一個結點*/

int parent,child;

HuffmanTree MinItem,temp = NULL;

if( IsEmpty(H) ){

printf("最小堆為空\n");

return NULL;

}

MinItem = H->Data[1];  //取出根結點-最小的元素-記錄下來

//用最小堆中的最后一個元素從根結點開始向上過濾下層結點

temp = H->Data[H->Size--];  //最小堆中最后一個元素,暫時將其視為放在了根結點

for(parent=1; parent*2<=H->Size; parent=child){

child = parent*2;

if((child != H->Size) && (H->Data[child]->Weight > H->Data[child+1]->Weight)){

/*有右兒子,並且左兒子權值大於右兒子*/

child++; //child指向左右兒子中較小者

}

if(temp->Weight > H->Data[child]->Weight){

H->Data[parent] = H->Data[child];  //向上過濾結點-temp存放位置下移到child位置

}else{

break;  //找到了合適的位置

}

}

H->Data[parent] = temp;  //temp存放到此處

 

return MinItem;

}

 

MinHeap BuildMinHeap(MinHeap H)

{

int i,parent,child;

HuffmanTree temp;

for(i=H->Size/2;i>0;i--){  //從最后一個父結點開始,直到根結點

temp = H->Data[i];

for(parent=i; parent*2<=H->Size; parent=child){

    /*向下過濾*/

child = parent*2;

    if((child != H->Size) && (H->Data[child]->Weight > H->Data[child+1]->Weight)){/*有右兒子,並且左兒子權值大於右兒子*/

    child++; //child指向左右兒子中較小者

    }

    if(temp->Weight > H->Data[child]->Weight){

    H->Data[parent] = H->Data[child];  //向上過濾結點-temp存放位置下移到child位置

    }else{

    break;  //找到了合適的位置

    }

    }/*結束內部for循環對以H->data[i]為根的子樹的調整*/

 

H->Data[parent] = temp;  //temp存放到此處  

}

return H;

}

 

六、測試和結果

測試用例:課本154頁哈夫曼樹的生成過程

七、用戶手冊

打開devC++,新建一個源程序,拷貝5部分的代碼進去,點擊運行,在出現的界面中按照提示輸入數據一步步按下回車鍵即可運行該程序,最后測試完畢,關閉界面


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM