《数据结构(C语言版)第二版》第五章-树和二叉树(5.7 哈夫曼树及其应用)

5.7 哈夫曼树及其应用

5.7.2 哈夫曼树的构造算法

c语言哈夫曼树及其编码 ------ 十八岁没有梦想

c 复制代码
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
	int weight;
	int parent;
	int lchild;
	int rchild;
}HTNode, * HuffmanTree;

void CreateHuffmanTree(HuffmanTree& HT, int n);
void Select(HTNode* s, int n, int& s1, int& s2);
void OrderHuffmanTree(HuffmanTree& HT, int n);

int main()
{
	HuffmanTree HT = NULL;
	CreateHuffmanTree(HT, 8);
	OrderHuffmanTree(HT, 8);

	return 0;
}


void CreateHuffmanTree(HuffmanTree& HT, int n)
{
	if (n < 1)
	{
		return;
	}
	
	//n = 1 时,只有一个结点,其权重为输入值,其双亲结点、左孩子、右孩子的结点下标均不存在(设为0).且n = 1时,程序无法生成其最优前缀编码(实际中用最短的0或1均可)。

	int i = 0;
	int m = 2 * n - 1;
	
	int s1 = 0;
	int s2 = 0;

	HT = (HuffmanTree)malloc(sizeof(HTNode) * (m + 1));
	//HT指向了一个一维数组的基地址,数组中的元素类型是HTNode,数组大小为m+1
	//等价于HTNode HT[m+1]
	//不说明数组大小时,为HTNode* HT,HuffmanTree HT

	for (i = 1; i <= m; ++i)
	{
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}

	for (i = 1; i <= n; i++)
	{
		printf("请输入第%d个叶子结点的权值:", i);
		scanf_s("%d", &HT[i].weight);
	}

	/*-----------初始化工作结束,下面开始创建哈夫曼树----------*/

	for (i = n + 1; i <= m; i++)
	{
		//选择
		Select(HT, i - 1, s1, s2);

		//删除
		HT[s1].parent = i;
		HT[s2].parent = i;

		//合并
		HT[i].weight = HT[s1].weight + HT[s2].weight;
		HT[i].lchild = s1;
		HT[i].rchild = s2;
	}
}

//在大小为n的一维整数型数组s中,找到最小的两个整数,并将其坐标存储在变量s1和s2中,下标从1开始
void Select(HTNode* s, int n, int& s1, int& s2)
{
	int m = 0;  //最小的值,下标为s1
	int p = 0;  //第二小的值,下标为s2

	int r = 1;
	int t = 1;

	//找到第一个双亲不为0的s[r]
	while (s[r].parent != 0)
	{
		r++;
	}

	//找到第二个双亲不为0的s[t]
	t = r + 1;
	while (s[t].parent != 0)
	{
		t++;
	}

	//比较s[r]和s[t]
	if (s[r].weight <= s[t].weight)
	{
		m = s[r].weight;
		p = s[t].weight;
		s1 = r;
		s2 = t;
	}
	else
	{
		m = s[t].weight;
		p = s[r].weight;
		s1 = t;
		s2 = r;
	}


	for (int k = 3; k <= n; k++)
	{
		if (s[k].parent == 0 && s[k].weight < m)
		{
			p = m;
			s2 = s1;
			m = s[k].weight;
			s1 = k;
		}
		else if (s[k].parent == 0 && s[k].weight > m && s[k].weight < p)
		{
			p = s[k].weight;
			s2 = k;
		}
		else
		{
			;
		}
	}

	//将下标小的作为新结点的左孩子,将下标大的作为新结点的右孩子
	int temp = 0;
	if (s1 > s2)
	{
		temp = s1;
		s1 = s2;
		s2 = temp;
	}

	printf("\ns1 = %d, s2 = %d", s1, s2);
}
//遍历哈夫曼树(即遍历其HT数组各个结点元素的信息)
void OrderHuffmanTree(HuffmanTree& HT, int n)
{
	int k = 0;

	if (HT)
	{
		for (k = 1; k <= (2 * n - 1); k++)
		{
			printf("\n\nHT[%d].weight = %d, HT[%d].parent = %d, HT[%d].lchild = %d, HT[%d].rchild = %d ", k, HT[k].weight, k, HT[k].parent, k, HT[k].lchild, k, HT[k].rchild);
		}
	}
}


5.7.3 哈夫曼编码

用C语言实现哈夫曼编码 --------- 爱编程的小木可

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct
{
	int weight;
	int parent;
	int lchild;
	int rchild;
}HTNode, * HuffmanTree;

typedef char** HuffmanCode;

void CreateHuffmanTree(HuffmanTree& HT, int n);
void Select(HTNode* s, int n, int& s1, int& s2);
void OrderHuffmanTree(HuffmanTree& HT, int n);
void CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n);

int main()
{
	HuffmanTree HT = NULL;
	HuffmanCode HC = NULL;
	int i = 0;
	char* p = NULL;

	CreateHuffmanTree(HT, 8);
	OrderHuffmanTree(HT, 8);
	CreatHuffmanCode(HT, HC,8);

	printf("\n\n各权重对应的编码为:");
	for (i = 1; i <= 8; i++)
	{
		printf("\n%d:", HT[i].weight);
		for (p = HC[i]; *p != '\0'; p++)
		{
			printf("%c ", *p);
		}
	}

	return 0;
}


void CreateHuffmanTree(HuffmanTree& HT, int n)
{
	if (n <= 1)
	{
		return;
	}

	int i = 0;
	int m = 2 * n - 1;

	int s1 = 0;
	int s2 = 0;

	HT = (HuffmanTree)malloc(sizeof(HTNode) * (m + 1));
	//HT指向了一个一维数组的基地址,数组中的元素类型是HTNode,数组大小为m+1
	//等价于HTNode HT[m+1]
	//不说明数组大小时,为HTNode* HT,HuffmanTree HT

	for (i = 1; i <= m; ++i)
	{
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}

	for (i = 1; i <= n; i++)
	{
		printf("请输入第%d个叶子结点的权值:", i);
		scanf_s("%d", &HT[i].weight);
	}

	/*-----------初始化工作结束,下面开始创建哈夫曼树----------*/

	for (i = n + 1; i <= m; i++)
	{
		//选择
		Select(HT, i - 1, s1, s2);

		//删除
		HT[s1].parent = i;
		HT[s2].parent = i;

		//合并
		HT[i].weight = HT[s1].weight + HT[s2].weight;
		HT[i].lchild = s1;
		HT[i].rchild = s2;
	}
}

//在大小为n的一维整数型数组s中,找到最小的两个整数,并将其坐标存储在变量s1和s2中,下标从1开始
void Select(HTNode* s, int n, int& s1, int& s2)
{
	int m = 0;  //最小的值,下标为s1
	int p = 0;  //第二小的值,下标为s2

	int r = 1;
	int t = 1;

	//找到第一个双亲不为0的s[r]
	while (s[r].parent != 0)
	{
		r++;
	}

	//找到第二个双亲不为0的s[t]
	t = r + 1;
	while (s[t].parent != 0)
	{
		t++;
	}

	//比较s[r]和s[t]
	if (s[r].weight <= s[t].weight)
	{
		m = s[r].weight;
		p = s[t].weight;
		s1 = r;
		s2 = t;
	}
	else
	{
		m = s[t].weight;
		p = s[r].weight;
		s1 = t;
		s2 = r;
	}


	for (int k = 3; k <= n; k++)
	{
		if (s[k].parent == 0 && s[k].weight < m)
		{
			p = m;
			s2 = s1;
			m = s[k].weight;
			s1 = k;
		}
		else if (s[k].parent == 0 && s[k].weight > m && s[k].weight < p)
		{
			p = s[k].weight;
			s2 = k;
		}
		else
		{
			;
		}
	}

	//将下标小的作为新结点的左孩子,将下标大的作为新结点的右孩子
	int temp = 0;
	if (s1 > s2)
	{
		temp = s1;
		s1 = s2;
		s2 = temp;
	}

	printf("\ns1 = %d, s2 = %d", s1, s2);
}

//遍历哈夫曼树(即遍历其HT数组各个结点元素的信息)
void OrderHuffmanTree(HuffmanTree& HT, int n)
{
	int k = 0;

	if (HT)
	{
		for (k = 1; k <= (2 * n - 1); k++)
		{
			printf("\n\nHT[%d].weight = %d, HT[%d].parent = %d, HT[%d].lchild = %d, HT[%d].rchild = %d ", k, HT[k].weight, k, HT[k].parent, k, HT[k].lchild, k, HT[k].rchild);
		}
	}
}

//算法5.11 根据哈夫曼树求哈夫曼编码
void CreatHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
	int i = 0;
	int start = 0;
	int c = 0;
	int f = 0;

	HC = (HuffmanCode)malloc(sizeof(char*) * (n + 1));
	char* cd = (char*)malloc(sizeof(char) * (n));
	cd[n - 1] = '\0';

	for (i = 1; i <= n; ++i)
	{
		start = n - 1;
		c = i;  //结点c
		f = HT[i].parent;  //f为结点c的双亲
		
		while (f != 0)  //根结点与叶子结点及其它内部结点的区别
		{
			--start;

			if (HT[f].lchild == c)
			{
				cd[start] = '0';
			}
			else  //HT[f].rchild == c
			{
				cd[start] = '1';
			}

			c = f;
			f = HT[f].parent;
		}

		HC[i] = (char*)malloc(sizeof(char) * (n - start));
		strcpy_s(HC[i], n - start, &cd[start]);
/* strcpy_s(*a,strlen(b)+1,*b)将指针b开始指向的内容(包括空终止符'\0')复制到a指针		
  第一个参数:目标字符串指针 ;
  第二个参数:要复制的字符串长度,可使用strlen()函数直接求出。切记在使用strlen()求出字符串长度时,因为不包括终止符'\0',因此需要+1;
 第三个参数:待复制的字符串指针。   */
//由复制的长度n - start,这里复制的编码不包括终止符'\0',若要包括,长度再加一即可

	}

	free(cd);
}



哈夫曼译码

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXSIZE 100

typedef struct
{
	int weight;
	int parent;
	int lchild;
	int rchild;
}HTNode, * HuffmanTree;

typedef char** HuffmanCode;

void CreateHuffmanTree(HuffmanTree& HT, int n);
void Select(HTNode* s, int n, int& s1, int& s2);
void OrderHuffmanTree(HuffmanTree HT, int n);
void CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n);
void Decode(HuffmanTree HT,int n, char* s);
int getline(char s[], int limit);

int main()
{
	HuffmanTree HT = NULL;
	HuffmanCode HC = NULL;
	int i = 0;
	char* p = NULL;

	char s[MAXSIZE];
	int length = 0;
	int num = 1;
	char choice = '\0';


	CreateHuffmanTree(HT, 8);
	OrderHuffmanTree(HT, 8);
	CreateHuffmanCode(HT, HC, 8);

	printf("\n\n各权值对应的编码是:");
	for (i = 1;i <= 8; i++)
	{
		printf("\n%d : ", HT[i].weight);
		for (p = HC[i]; *p != '\0'; p++)
		{
			printf("%c", *p);
		}
	}

	getchar();  //此处有一个回车需要回收

	while (1)
	{
		printf("\n请输入第%d个哈夫曼编码:", num);
		length = getline(s, MAXSIZE);

		printf("该编码对应的权值是:");
		Decode(HT, 8, s);

		printf("\n是否继续?(y/n)");
		scanf_s(" %c", &choice);
		getchar();

		num++;

		if (choice != 'y' && choice != 'Y')
		{
			break;
		}
	}

	return 0;
}

void CreateHuffmanTree(HuffmanTree& HT, int n)
{
	if (n < 1)
	{
		return;
	}

	int i = 0;
	int m = 2 * n - 1;

	int s1 = 0;
	int s2 = 0;

	HT = (HuffmanTree)malloc(sizeof(HTNode) * (m + 1));

	for (i = 1; i <= m; i++)
	{
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}

	for (i = 1; i <= n; i++)
	{
		printf("请输入第%d个权值:", i);
		scanf_s("%d", &HT[i].weight);
	}

	for (i = n+ 1; i <= m; i++)
	{
		//选择
		Select(HT, i - 1, s1, s2);
	
		//删除
		HT[s1].parent = i;
		HT[s2].parent = i;

		//合并
		HT[i].weight = HT[s1].weight + HT[s2].weight;
		HT[i].lchild = s1;
		HT[i].rchild = s2;
	}
}


void Select(HuffmanTree HT, int n, int& s1, int& s2)
{
	int m = 0; //最小值,下标是s1
	int p = 0; //第二小值,下标是s2

	int t = 1;
	int r = 1;

	int k = 1;

	while (HT[t].parent != 0)
	{
		t++;
	}

	r = t + 1;
	while (HT[r].parent != 0)
	{
		r++;
	}

	if (HT[t].weight <= HT[r].weight)
	{
		m = HT[t].weight;
		s1 = t;
		p = HT[r].weight;
		s2 = r;
	}
	else
	{
		m = HT[r].weight;
		s1 = r;
		p = HT[t].weight;
		s2 = t;
	}


	for (k = r+1; k <= n; k++)
	{
		if (HT[k].parent == 0 && HT[k].weight < m)
		{
			p = m;
			s2 = s1;
			m = HT[k].weight;
			s1 = k;
		}
		else if(HT[k].parent == 0 && HT[k].weight > m && HT[k].weight < p)
		{
			p = HT[k].weight;
			s2 = k;
		}
		else
		{
			;
		}
	}


	if (s1 > s2)
	{
		int temp = s1;
		s1 = s2;
		s2 = temp;
	}

}


void OrderHuffmanTree(HuffmanTree HT,int n)
{
	if (HT)
	{
		for (int i = 1; i <= 2*n-1; i++)
		{
			printf("HT[%d].weight = %d, HT[%d].parent = %d, HT[%d].lchild = %d, HT[%d].rchild = %d\n",i,HT[i].weight,i,HT[i].parent,i,HT[i].lchild,i,HT[i].rchild);
		}
	}
}

void CreateHuffmanCode(HuffmanTree HT, HuffmanCode& HC, int n)
{
	int i = 0;
	int start = 0;
	int c = 0;
	int f = 0;

	HC = (HuffmanCode)malloc(sizeof(char*) * (n + 1));
	char* cd = (char*)malloc(sizeof(char) * n);
	cd[n - 1] = '\0';

	for (i = 1; i <= n; i++)
	{
		start = n - 1;
		c = i;
		f = HT[i].parent;

		while (f != 0)
		{
			--start;

			if (HT[f].lchild == c)
			{
				cd[start] = '0';
			}

			if (HT[f].rchild == c)
			{
				cd[start] = '1';
			}

			c = f;
			f = HT[c].parent;
		}

		HC[i] = (char*)malloc(sizeof(char) * (n - start));
		strcpy_s(HC[i], n - start, &cd[start]);
	}

	free(cd);
}


//译码
void Decode(HuffmanTree HT, int n,char *s)
{
	int m = 2 * n - 1;
	char *p = s;
	int c = m; //从根节点开始往叶子结点走

	for (p = s; *p != '\0'; p++)
	{
		//printf("\np = %c", *p);
		if (*p == '0')
		{
			c = HT[c].lchild;
			//printf("\nHT[c].weight = %d", HT[c].weight);
		}
		else if (*p == '1')
		{

			c = HT[c].rchild;
			//printf("\nHT[c].weight = %d", HT[c].weight);
		}
		else
		{
			;
		}
	}

	if (HT[c].lchild == 0 && HT[c].rchild == 0)
	{
		printf("%d", HT[c].weight);
	}
	else
	{
		printf("输入的编码有误。\n");
	}
}

int getline(char s[], int limit)
{
	int i = 0;
	int c = 0;

	for (i = 0; i < limit-1 && (c = getchar()) != EOF && c != '\n'; i++)
	{
		s[i] = c;
	}

	s[i] = '\0';
	return i;
}


相关推荐
2401_857617622 分钟前
“无缝购物体验”:跨平台网上购物商城的设计与实现
java·开发语言·前端·安全·架构·php
觅远2 分钟前
python+reportlab创建PDF文件
开发语言·python·pdf
td爆米花16 分钟前
C#冒泡排序
数据结构·算法·排序算法
我曾经是个程序员18 分钟前
C#File文件基础操作大全
开发语言·c#
林浔090623 分钟前
QT信号槽
开发语言·qt
重生之绝世牛码27 分钟前
Java设计模式 —— 【结构型模式】享元模式(Flyweight Pattern) 详解
java·大数据·开发语言·设计模式·享元模式·设计原则
Allen Bright41 分钟前
【Java基础-26.1】Java中的方法重载与方法重写:区别与使用场景
java·开发语言
执着的小火车43 分钟前
02-18.python入门基础一基础算法
数据结构·python·算法·排序算法
梦茹^_^44 分钟前
排序算法(系列)
数据结构·python·算法·排序算法·希尔排序·基数排序·计数排序和桶排序
秀儿y1 小时前
单机服务和微服务
java·开发语言·微服务·云原生·架构