哈夫曼树——c

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30648823/article/details/79764699
// 哈夫曼树.cpp: 定义控制台应用程序的入口点。
//	陈鹏

#include "stdafx.h"
#include "stdio.h"
#include "malloc.h"

#define MAXSIZE 100

typedef struct shuZhu {				//给定数组类型里面只可以存放hTree类型的指针
	struct hTree *p;
}ShuZhu;
//这颗哈夫曼树没有数据类型 只有权值 如果要加入数据 那就在14行加入 char a; 写入数据的时候加入读取 a并保存 就行了
typedef struct hTree {				//定义二叉树 weight为权值  left为左边指针 right为右边指针
	int weight;						
	struct hTree *left, *right;
}HTree;

ShuZhu arr[MAXSIZE];
int t = 0;

//----------------------建立数据-----------------------------
//写入数据
void Init(int w, int t) {	//w权值 d数据 t位置 
	HTree *p;
	p = (HTree*)malloc(sizeof(hTree));
	arr[t].p = p;
	arr[t].p->weight = w;
	//初始化
	arr[t].p->left = NULL;
	arr[t].p->right = NULL;
}
//用户输入
void  XieRu() {
	int w;
	printf("请输入权值 0结束\n");
	scanf_s("%d", &w);
	while (w) {
		Init(w, t);				//往数组里面写
		printf("请输入权值 0结束\n");
		scanf_s("%d", &w);
		t++;
	}
}
//输出数据
void Prints() {
	for (int i = 0; i < t; i++) {
		printf("权值为%d \n", arr[i].p->weight);
	}
}

//----------------------建立数据结束-----------------------------
//----------------------堆排序-----------------------------------
	//落底
	void DuiLuoDi(int n, int k) {	//n代表长度 k代表节点
		int k1 = 2 * k + 1;			//设置k1为左边节点
		int k2 = 2 * k + 2;			//设置k2为右边节点
		if (k1 >= n&&k2 >= n) {		//判断是不是叶子
			return;
		}
		int a1 = _CRT_INT_MAX;			//设置两个最大值
		int a2 = _CRT_INT_MAX;
		if (k1 < n)a1 = arr[k1].p->weight; //如果左边节点纯在  因为传进来的数字为t t标识的是长度从1开始计数 而堆是从0开始计数的
		if (k2 < n)a2 = arr[k2].p->weight; //如果右边节点纯在
		if (arr[k].p->weight < a1&&arr[k].p->weight < a2)return; //节点比自己的两个孩子的权值都小 次节点栈排序完成 
														   //否则进行排序
		if (a1 < a2) {
			ShuZhu p = arr[k];			//定义一个YuanShu
			arr[k] = arr[k1];			//将节点与小的元素进行交换
			arr[k1] = p;
			DuiLuoDi(n, k1);			//将k1当做节点往下进行排序
		}
		else {
			ShuZhu p = arr[k];
			arr[k] = arr[k2];
			arr[k2] = p;
			DuiLuoDi(n, k2);
		}
	}
	//初始排序构成堆
	void DuiInit() {
		for (int i = t / 2; i >= 0; i--) {
			DuiLuoDi(t, i);
		}
	}
	//插入元素
	void DuiChaRu(HTree *p) {	//w代表权值 d代表数据
		t++;						//数组长度增加
		arr[t - 1].p = p;
		DuiInit();					//进行排序
	}
	//取出一个
	HTree *DuiOut() {
		DuiInit();					//构成堆
		HTree *p = arr[0].p;
		arr[0] = arr[t - 1];
		t--;
		DuiLuoDi(t, 0);				//只对放入第一个位置的那个数据进行落底操作
		return p;
	}

//----------------------堆排序-----------------------------------

//----------------------构成哈夫曼树-----------------------------
	HTree *HTreeGo() {
		DuiInit();												//先构成堆
		HTree *H = NULL;										//定义一个HTree
		int z = t;
		for (int i = 0; i < z - 1; i++) {
			H = (HTree*)malloc(sizeof(hTree));					//申请空间
			H->left = DuiOut();									//在栈里面取一个权值最小的值给新生成的一个节点的左边
			H->right = DuiOut();								//在栈里面取一个权值最小的值给新生成的一个节点的右边
			H->weight = H->left->weight + H->right->weight;		//给新生成的这个节点的权值赋值为左右孩子的权值之和
			DuiChaRu(H);										//添加这个新的节点到堆中去
		}
		H = DuiOut();											//上面for循环结结束 最后堆里面还剩一个元素 这个元素就是哈夫曼树的头
		return H;												//将这个头给返回出去
	}
//----------------------构成哈夫曼树-----------------------------
//先序遍历
	void XianXu(HTree *H) {
		if (H != NULL) {
			printf("%d  ", H->weight);
			XianXu(H->left);
			XianXu(H->right);
		}
	}
//字符编码
//构造哈夫曼编码  
	void HuffManCoding(HTree * FBT, int len) {				//传入一个哈夫曼树和一个长度
		static int a[MAXSIZE];								//定义一个数组来装编码
		if (FBT != NULL) {									//判断存不存在
			if (FBT->left == NULL && FBT->right == NULL) {  //如果左边和右边都为空那么这个点为叶子
				printf("结点的值为%d的编码:", FBT->weight);
				for (int i = 0; i < len; i++)				//根据长度遍历出编码
					printf("%d", a[i]);
				printf("\n");
			}else {											//如果纯在
				a[len] = 0;									//先往左边走
				HuffManCoding(FBT->left, len + 1);			//回调 从而往左下走 长度加一(len+1是因为不会改变初始的len的长度 因为往右边回来等下还要用)
				a[len] = 1;									//从左边回来将这个值改为1
				HuffManCoding(FBT->right, len + 1);			//回调 从而往右下走
			}
		}
	}

void main() {
	XieRu();
	Prints();
	printf("\n\n先序遍历哈夫曼树\n");
	HTree *H;
	H = HTreeGo();
	XianXu(H);
	printf("\n\n哈夫曼树编码\n");
	HuffManCoding(H,0);
}

猜你喜欢

转载自blog.csdn.net/qq_30648823/article/details/79764699