哈夫曼树的操作运算以上文的哈夫曼树作为具体实例,用详细的程序展示哈夫曼树的操作运算:
- /** 哈夫曼树编码 **/
- #include<stdio.h>
- #include<stdlib.h>
- #define LENGTH 6
- typedef int ElemType;
- typedef struct HuffmanTreeNode{
- ElemType data; //哈夫曼树中节点的权值
- struct HuffmanTreeNode* left;
- struct HuffmanTreeNode* right;
- }HuffmanTreeNode,*PtrHuffman;
- /**
- * 创建哈夫曼树
- */
- PtrHuffman createHuffmanTree(ElemType arr[]){
- PtrHuffman ptrArr[LENGTH];
- PtrHuffman ptr,pRoot=NULL;
- for (int i = 0; i < LENGTH; i++){ //初始化结构体指针数组,数组中每一个元素为一个结构体指针类型
- ptr = (PtrHuffman)malloc(sizeof(HuffmanTreeNode));
- ptr->data = arr[i];
- ptr->left = ptr->right = NULL;
- ptrArr[i] = ptr;
- }
-
- for(i = 1; i < LENGTH; i++){ //进行 n-1 次循环建立哈夫曼树
- //k1表示森林中具有最小权值的树根结点的下标,k2为次最小的下标
- int k1 = -1, k2;
- for(int j = 0; j < LENGTH; j++){
- if (ptrArr[j] != NULL && k1 == -1){
- k1 = j;
- continue;
- }
- if (ptrArr[j] != NULL){
- k2 = j;
- break;
- }
- }
- //将指针数组中的指针指向的最小值赋值给索引号为k1的,次小值赋值给索引号为k2的
- for (j = k2; j < LENGTH; j++){
- if(ptrArr[j] != NULL){
- if(ptrArr[j]->data < ptrArr[k1]->data){
- k2 = k1;
- k1 = j;
- }else if(ptrArr[j]->data < ptrArr[k2]->data){
- k2 = j;
- }
- }
- }
- //由最小权值树和次最小权值树建立一棵新树,pRoot指向树根结点
- pRoot = (PtrHuffman)malloc(sizeof(HuffmanTreeNode));
- pRoot->data = ptrArr[k1]->data + ptrArr[k2]->data;
- pRoot->left = ptrArr[k1];
- pRoot->right = ptrArr[k2];
- ptrArr[k1] = pRoot; //将指向新树的指针赋给ptrArr指针数组中k1位置
- ptrArr[k2] = NULL; //k2位置为空
- }
- return pRoot;
- }
- /**
- * 计算哈夫曼树带权路径长度WPL
- */
- ElemType calculateWeightLength(PtrHuffman &ptrTree,int len){
- if(ptrTree==NULL){ //空树返回0
- return 0;
- }else{
- if(ptrTree->left==NULL && ptrTree->right==NULL){ //访问到叶子节点
- return ptrTree->data * len;
- }else{
- return calculateWeightLength(ptrTree->left,len+1) + calculateWeightLength(ptrTree->right,len+1); //向下递归计算
- }
- }
- }
- /**
- * 哈夫曼树编码(叶子节点按中序方式依次打印其编码)
- */
- void HuffmanCoding(PtrHuffman &ptrTree,int len){
- //静态局部变量相当于全局变量(只是只有在这个函数中能访问,但是生命周期是和全局变量差不多的)函数退出之后变量还在,而且只在第一次进入的时候做初始化,以后会跳过初始化语句,保留原来的值
- static int arr[20];
- if(ptrTree != NULL){
- if(ptrTree->left==NULL && ptrTree->right==NULL){
- printf("结点权值为%d的编码: ", ptrTree->data);
- for(int i = 0; i < len; i++){
- printf("%d", arr[i]);
- }
- printf("\n");
- }else{
- arr[len] = 0;
- HuffmanCoding(ptrTree->left,len+1);
- arr[len] = 1;
- HuffmanCoding(ptrTree->right,len+1);
- }
- }
- }
- /**
- * 打印哈夫曼树中各个节点的孩子节点
- * 若为叶子节点,则只显示提示信息
- * @param node 需要显示孩子节点的父节点
- */
- void printHuffmanTreeChildNode(PtrHuffman node){
- if(node->left == NULL && node->right == NULL){
- printf("x=%d是哈夫曼树中的叶子节点",node->data);
- printf("\n\n");
- return;
- }
- if(node->left != NULL){
- printf("x=%d在哈夫曼树中的左孩子节点是lchild=%d",node->data,node->left->data);
- printf("\n");
- }
- if(node->right != NULL){
- printf("x=%d在哈夫曼树中的右孩子节点是rchild=%d",node->data,node->right->data);
- printf("\n");
- }
- printf("\n");
- }
- /**
- * 中序打印哈夫曼树的节点
- */
- void midOrderprintHuffmanTreeNode(PtrHuffman &pRoot){
- if(pRoot==NULL){
- return;
- }else{
- midOrderprintHuffmanTreeNode(pRoot->left);
- printf("%d ",pRoot->data);
- midOrderprintHuffmanTreeNode(pRoot->right);
- }
- }
- /**
- * 先序打印哈夫曼树的节点
- */
- void PreOrderprintHuffmanTreeNode(PtrHuffman &pRoot){
- if(pRoot==NULL){
- return;
- }else{
- printHuffmanTreeChildNode(pRoot); //依次打印哈夫曼树中各个节点的孩子节点
- PreOrderprintHuffmanTreeNode(pRoot->left);
- PreOrderprintHuffmanTreeNode(pRoot->right);
- }
- }
- /**
- * 测试程序入口
- */
- int main(){
- ElemType arr[] = {3,9,5,12,6,15};
- PtrHuffman pRoot = createHuffmanTree(arr); //返回指向哈夫曼树根节点的指针
- printf("==========中序打印哈夫曼树节点数据==========\n");
- midOrderprintHuffmanTreeNode(pRoot);
- printf("\n\n");
- printf("==========先序打印哈夫曼树节点关系==========\n");
- PreOrderprintHuffmanTreeNode(pRoot);
- printf("==========计算带权路径长度==========\n");
- printf("WeightLength=%d\n",calculateWeightLength(pRoot,0));
- printf("\n");
- printf("==========各节点的哈夫曼树编码==========\n");
- HuffmanCoding(pRoot,0);
- fprintf(stdout,"\n");
-
- return 0;
- }
运行结果截图:

|