数据结构——分别通过数组和队列实现哈夫曼树的构建以及哈夫曼编码的实现(C语言)...

#include<stdio.h>
#include<stdlib.h>


//哈夫曼树结点结构
typedef struct {
        int weight;//结点权重
        int parent, left, right;//父结点、左孩子、右孩子在数组中的位置下标
}HTNode,*HuffmanTree;
int test01=0;
int test02 =0;
int *s1 = &test01;
int *s2 = &test02;
typedef  char **HuffCode;
//HT数组中存放的哈夫曼树,end表示HT数组中存放结点的最终位置,s1和s2传递的是HT数组中权重值最小的两个结点在数组中的位置
void Select(HuffmanTree HT,int end)
{
    int min1=-1, min2=-1;
    //遍历数组初始下标为 1

    int min = 1000;
	int i;
    
    //找到还没构建树的结点中权重最小的下标
    for(i =1; i < end; i++){
            if(HT[i].parent ==0 && min > HT[i].weight){
                    min =  HT[i].weight;
                    min1 = i;
            }
    }

    if(min1== -1) return;
    HT[min1].parent =1;
    min = 1000;
    for(i =1; i < end; i++){
            if(HT[i].parent ==0 && min > HT[i].weight){
                    min =  HT[i].weight;
                    min2 = i;
            }
    }
     HT[min2].parent =1;
     if(min1== -1) return;
   
    *s1 = min1;
    *s2 = min2;
}
//HT为地址传递的存储哈夫曼树的数组,w为存储结点权重值的数组,n为结点个数
void CreateHuffmanTree(HuffmanTree *HT, int *w, int n)
{
    int m,i;

    if(n<=1) return; // 如果只有一个编码就相当于0
   
	m= 2*n-1; // 哈夫曼树总节点数,n就是叶子结点
    *HT = (HuffmanTree) malloc((m+1)*sizeof(HTNode)); // 0号位置不用

    // 初始化哈夫曼树中的所有结点
    for(i = 1; i <= n;i++)
    {
        (*HT)[i].weight = *(w+i-1);
        (*HT)[i].parent = 0;
        (*HT)[i].left = 0;
        (*HT)[i].right = 0;
    }
    //从树组的下标 n+1 开始初始化哈夫曼树中除叶子结点外的结点
    for(i = n+1; i <= m; i++)
    {
        (*HT)[i].weight = 0;
        (*HT)[i].parent = 0;
        (*HT)[i].left = 0;
        (*HT)[i].right = 0;
    }
    //构建哈夫曼树
    for(i = n+1; i<=m; i++){
            Select(*HT,i);

            (*HT)[i].left = *s1;
            (*HT)[i].right = *s2;
            (*HT)[*s1].parent = (*HT)[*s2].parent=i;
            (*HT)[i].weight = (*HT)[*s1].weight + (*HT)[*s2].weight;
    }
}

//哈夫曼编码(从底部向上)
void haFuCode(HuffmanTree *HT,HuffCode *HC,int n){
        int i,start,currentIndex,parentIndex;

        char *cd;
        //定义一位字符串
        cd = (char *)malloc(sizeof(char)*n);
		cd[n-1] = '\0';//字符串结束符
        *HC = (HuffCode)malloc(sizeof(char *)*(n+1));
        for(i = 1; i <=n; i++){
                start = n-1;
                currentIndex = i;
                parentIndex = (*HT+i)->parent;
                while(parentIndex !=0){
                        if((*HT+parentIndex)->left == currentIndex){
                                cd[--start] ='0';
                        }else if((*HT+parentIndex)->right == currentIndex){
                                cd[--start] ='1';
                        }
                        //父节点作为孩子节点,继续遍历
                     currentIndex =  parentIndex;
                     parentIndex= (*HT+parentIndex)->parent;

                }

                //将该节点的编码保存
                (*HC)[i] = (char *)malloc((n-start)*sizeof(char));
                strcpy((*HC)[i],&cd[start]);
        }
        free(cd);
}

//哈夫编码(从顶到底部)
void haFuCode02(HuffmanTree *HT,HuffCode *HC,int n){
	int i;
        int m = 2*n -1;  //节点总数,哈夫曼树是先满二叉树,节点关系:N0  = N2+1
        int p = m;  //未遍历的节点个数
        int index=0;

        char *cd = (char *)malloc(sizeof(char)*n);
        *HC = (HuffCode)malloc(sizeof(char *)*(n+1));
        //初始化节点,权重为遍历次数
        for(i = 1; i <= p; i++){
                (*HT+i)->weight = 0;
        }

        while(p != 0){
                if((*HT+p)->weight == 0){
                        (*HT+p)->weight =1;
                        if((*HT+p)->left != 0){
                                cd[index++] = '0';
                                p = (*HT+p)->left;
			}
			else if((*HT+p)->right == 0){ //左右节点都遍历完,保存编码
                                (*HC)[p]  =  (char *)malloc(sizeof(char)*(index+1));
				cd[index] = '\0';   //字符串结束符
                                strcpy((*HC)[p] ,cd);  //内置函数
                        }
                }
                else if((*HT+p)->weight == 1){  //从左节点返回,再次回到父节点
                        (*HT+p)->weight =2;
                        if((*HT+p)->right != 0){
                                cd[index++] = '1';
                                p = (*HT+p)->right;
                        }

                }
               else if((*HT+p)->weight == 2){  //左右节点都遍历完,返回父节点
                        (*HT+p)->weight =0;
                        p = (*HT+p)->parent;  //返回父节点
                        index--;
               }

        }

        
}
//打印编码
void PrintHuffmanCode(HuffCode htable,int *w,int n)
{
    int i;
    printf("Huffman code : \n");
    for( i = 1; i <= n; i++){
        printf("%d code = %s\n",w[i-1], htable[i]);
    }
}

//打印哈夫曼树的数组
void printTreeArr(HuffmanTree *HT,int n){
        int i=1;
        while( i<=2*n-1){
                printf("%d ",(*HT)[i].weight);
                i++;
        }
        printf("\n");
}


int main(void)
{
    int w[5] = {2, 8, 7, 6, 5};
    int n = 5;
    HuffmanTree htree;
    HuffCode htable;
    HuffCode htable02;
   //创造哈夫曼树
    CreateHuffmanTree(&htree, w, n);
    printTreeArr(&htree,n);
    //从低到顶
    haFuCode(&htree,&htable,n);
    PrintHuffmanCode(htable,w,n);
    //从顶部到底部
    haFuCode02(&htree,&htable02,n);
    PrintHuffmanCode(htable02,w,n);

    return 0;
}

队列实现

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

//定义哈夫树的节点的结构
typedef struct HafuNode{
        int weight;
        struct HafuNode* parent;
        struct HafuNode* left;
        struct HafuNode* right;
}HaNode,*HaTreeNode;

//全局变量,都可以操作
int n= 5;
int test01=0;
int test02 =0;
int *min = &test01;
int *max = &test02;
//二位数组,存放哈夫曼编码
typedef  char **HuffCode;
int codeindex = 0;


void swap(int *a, int *b){
        int temp;
        temp = *a;
        *a = *b;
        *b = temp;
}

void initArr(HaTreeNode arr,int *w,int *flag){
        int i;   
        for(i = 0; i < 5; i++){
                arr[i].weight = w[i];
                arr[i].left = NULL;
                arr[i].right = NULL;
                arr[i].parent = NULL;
        }
}

//往动态数组里加入元素
void addNode(HaTreeNode arr,int *flag,int weight,HaTreeNode left,HaTreeNode right){
        arr[n].weight = weight;
        arr[n].left = left;
        arr[n].right = right;
        arr[n].parent = NULL;
        flag[n] =0;
        n++;
}
//找出权重数组的最小的两个权重值的下标
void lookMinIndex(HaTreeNode arr,int *flag){
        int i;
	int k=-1,kk =-1;
        int minWeight01 =100,minWeight02 =100;

        for(i = 0; i < n; i++){
               if(flag[i] ==0 && minWeight01 > arr[i].weight){
                       minWeight01 = arr[i].weight;
                       k = i;
               }
        }
        flag[k] = 1;
        for(i = 0; i < n; i++){
               if(flag[i] ==0 && minWeight02 > arr[i].weight){
                       minWeight02 = arr[i].weight;
                       kk = i;
               }
        }
        flag[kk] = 1;
        *min = k;
        *max = kk;
		
}
//构造哈夫曼树,从底部往顶部构造
void create_HafuTree(HaTreeNode* H,HaTreeNode arr,int *flag){
        int i;
        for(i = 0; i< n; i ++){
                        
                //构建哈夫曼树,目标函数就是使树的带权路径长度最小,左右节点可以互换,不影响结果,编码(0/1)没有大小之分
                lookMinIndex(arr,flag);
	        if(*min ==-1|| *max == -1) break;
                //将小的放在父节点的右边,大值放在父节点放在左边
                (*H) = (HaNode *)malloc(sizeof(HaNode));
                //最小值的node
                
                (*H)->left = &arr[*min];
		arr[*min].parent = *H ;

                
                (*H)->right = &arr[*max];
		arr[*max].parent = *H ;

                (*H)->weight =(*H)->left ->weight + (*H)->right ->weight;
                addNode(arr,flag, (*H)->weight,(*H)->left,(*H)->right);

        }

}

//哈夫曼编码(从底部向上)
void haFuCode(HaTreeNode arr,HuffCode *HC){
        int i;
        HaTreeNode p;
        char *cd;
		int start;
		HaTreeNode temp;;
		cd = (char *)malloc(sizeof(char)*n);
        *HC = (HuffCode)malloc(sizeof(char *)*(n+1));
        for(i = 0; i <n; i++){
                start = n-1;  //从叶子节点开始,保存编码,故逆序存放
                temp = &arr[i];  //数组当前节点位置
                p = arr[i].parent;
                while(p != NULL){
                        if (p->left == temp){
                                cd[--start] = '0';
                        }
						else if (p->right ==temp){
                                cd[--start] = '1';
                        }
						temp=p;
						printf("%d ",p ->parent->weight);
                        p= p->parent; //以父节点为孩子节点,继续遍历
                }
                
                //将该节点的编码保存
                (*HC)[i] = (char *)malloc((n-start)*sizeof(char));
                strcpy((*HC)[i],&cd[start]);
        }
        free(cd);
}

//哈夫曼编码(从上往下) //通过双队列实现
void haFuCodeTopTo(HaTreeNode HT,HaTreeNode arr,HuffCode *HC,int num){
        int i;
        HaTreeNode p;
        HaNode* arrtest[20];
        char *cd;

        int  temp;
        int rear = -1,star= -1;
        cd = (char *)malloc(sizeof(char)*num);
        *HC = (HuffCode)malloc(sizeof(char *)*(num+1));
         while(HT != NULL){
                        while(HT!= NULL){
                                arrtest[++rear] = HT;
                                cd[++start] = '0';
                                HT =HT->left;
                                ++rear;
                                ++start;
                        }
			if (rear != -1){
                                HT = arrtest[rear--];
                                if(HT->left ==NULL){
                                        (*HC)[codeindex] = (char *)malloc((n)*sizeof(char));
                                        strcpy((*HC)[codeindex],&cd[start]);
                                        codeindex++;  
                                        start--;      
                                }

                                HT = HT ->right;
                                cd[start++] = '1';
                        }

                }
                
        free(cd);
}
//打印哈夫曼编码
//打印哈夫曼编码的函数
void PrintHuffmanCode(HuffCode htable,int num){
	int i;

    printf("Huffman code :\n");
    for(i = 0; i < num; i++)
        printf(" %s\n",htable[i]);
}
//打印哈夫曼树的原属组
void printf_Test(HaTreeNode arr){
        int i;
        for(i = 0; i < 9; i++){
		if(arr[i].parent == NULL) break;
                printf("weight=%d  p = %p  parentW = %d parentIndex =%p",arr[i].weight,&arr[i], arr[i].parent->weight, arr[i].parent);
		printf("\n");
		}
        printf("\n");

}

//中序遍历
void mid_Search(HaTreeNode Ha){
        if(Ha){
                mid_Search(Ha->left);
                printf("%d    Ha = %p \n",Ha ->weight,Ha);
                mid_Search(Ha->right);
        }
}


int main(){
        HaTreeNode Ha;
        HuffCode HC;
        //节点weight值的数组
        int w[5] = {2, 8, 7, 6, 5};
        int flag[5] ={0,0,0,0,0};

        //创建一个存HaNode的数组
        HaNode* arr[11];
        //初始化
        initArr(arr,w,flag);
	
        create_HafuTree(&Ha,arr,flag);
        printf_Test(arr);
        mid_Search(Ha);

        //哈弗编码
        haFuCode(arr,&HC);
        PrintHuffmanCode(arr,HC,5);

        printf("\n");
        return 0;  
}

运行结果:

ce3a5f2d1125a6a9acebda1fdcce2aa78fa.jpg

转载于:https://my.oschina.net/1024and1314/blog/3089660

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值