feat: 新增数据结构实验 7 和实验 8
This commit is contained in:
133
DataStructure/test7/实验七.cpp
Normal file
133
DataStructure/test7/实验七.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int inf = 1000;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int weight; // 结点权值
|
||||
int parent, lchild, rchild; // 结点的双亲、左孩子、右孩子的下标
|
||||
char ch; // 字符
|
||||
} HTNode, *HuffmanTree;
|
||||
|
||||
// 查找
|
||||
int Find(HuffmanTree HT, int n)
|
||||
{
|
||||
int min = 0;
|
||||
for (int i = 1; i <= n; i++)
|
||||
{
|
||||
if (HT[i].weight < HT[min].weight && HT[i].parent == 0)
|
||||
min = i;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
// 选择
|
||||
void select(HuffmanTree HT, int n, int &s1, int &s2) // 传入参数n=k-1
|
||||
{
|
||||
s1 = Find(HT, n); // a、在HT[k](1≤k≤i-1)中选择两个其双亲域为0, 且权值最小的结点,并返回它们在HT中的序号s1和s2
|
||||
HT[s1].parent = n + 1; // b、得到新结点n + 1,从森林中删除s1,s2,将s1,s2的双亲域由0改为k (即n+1)
|
||||
s2 = Find(HT, n);
|
||||
HT[s2].parent = n + 1; // b、得到新结点n + 1,从森林中删除s1,s2,将s1,s2的双亲域由0改为k (即n+1)
|
||||
}
|
||||
|
||||
// 构造
|
||||
void CreatHuffmanTree(HuffmanTree &HT, int weight[], char c[], int n) // char c[100]; 字母
|
||||
{
|
||||
if (n <= 1)
|
||||
return;
|
||||
int m = 2 * n - 1; // 数组存储2n-1个元素
|
||||
HT = new HTNode[m + 1]; // 0号单元未用,所以需要开辟m+1个单元,HT[m]表示根结点
|
||||
for (int i = 1; i <= m; ++i) // 将2n-1个元素的lch、 rch、 parent初始化为0, ch字符全部初始化为#
|
||||
{
|
||||
// todo list 处理parent 、lchild 、rchild
|
||||
HT[i].parent = 0;
|
||||
HT[i].lchild = 0;
|
||||
HT[i].rchild = 0;
|
||||
HT[i].ch = '#';
|
||||
}
|
||||
HT[0].weight = inf; // int inf = 1000;
|
||||
|
||||
for (int j = 1; j <= n; ++j)
|
||||
{
|
||||
// todo list //获取 前n个单元中叶子节点的 weight值
|
||||
HT[j].weight = weight[j];
|
||||
HT[j].ch = c[j]; // 获取 前n个单元中叶子节点的 字符
|
||||
}
|
||||
for (int k = n + 1; k <= m; ++k) // 合并产生n-1个结点——构造Huffman树
|
||||
{
|
||||
int s1, s2;
|
||||
select(HT, k - 1, s1, s2); // 选择两个需要求和的下标
|
||||
// todo list //c、s1,s2分别作为k的左右孩子
|
||||
HT[k].lchild = s1;
|
||||
HT[k].rchild = s2;
|
||||
// todo list //c、k 的权值为左右孩子权值之和
|
||||
HT[k].weight = HT[s1].weight + HT[s2].weight;
|
||||
}
|
||||
}
|
||||
|
||||
// 输出哈夫曼树
|
||||
void DisplayHF(HuffmanTree HT, int r)
|
||||
{
|
||||
printf("%c %d\n", HT[r].ch, HT[r].weight);
|
||||
|
||||
int s1 = HT[r].lchild;
|
||||
int s2 = HT[r].rchild;
|
||||
if (s1 != 0)
|
||||
DisplayHF(HT, s1);
|
||||
if (s2 != 0)
|
||||
DisplayHF(HT, s2);
|
||||
}
|
||||
|
||||
// 输出哈夫曼编码
|
||||
void DisplayHFCode(HuffmanTree HT, int r, int arr[], int top)
|
||||
{
|
||||
int s1 = HT[r].lchild; // 获取当前节点的左孩子索引赋值给s1
|
||||
int s2 = HT[r].rchild; // 获取当前节点的右孩子索引赋值给s2
|
||||
|
||||
if (HT[r].lchild != 0)
|
||||
{ // 左孩子存在
|
||||
arr[top] = 0; // 在路径数组arr的当前位置top存入0,表示走向左孩子
|
||||
DisplayHFCode(HT, s1, arr, top + 1); // 递归调用DisplayHFCode函数,处理左孩子节点,同时top加1
|
||||
}
|
||||
if (HT[r].rchild != 0)
|
||||
{ // 右孩子存在
|
||||
arr[top] = 1; // 在路径数组arr的当前位置top存入1,表示走向右孩子
|
||||
DisplayHFCode(HT, s2, arr, top + 1); // 递归调用DisplayHFCode函数,处理右孩子节点,同时top加1
|
||||
}
|
||||
if (HT[r].lchild == 0 && HT[r].rchild == 0)
|
||||
{ // 叶子节点
|
||||
printf("字符 %c 的编码: ", HT[r].ch); // 打印当前叶子节点对应的字符
|
||||
for (int i = 0; i < top; ++i)
|
||||
{ // 遍历路径数组arr,从0到top-1
|
||||
printf("%d", arr[i]); // 打印路径数组中的每个元素,即字符的哈夫曼编码
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
HuffmanTree HT;
|
||||
int a[100]; // 权值
|
||||
char c[100]; // 字母
|
||||
int arr[100]; // arr:用于存储从根结点到当前结点的路径上的0和1的数组
|
||||
int top = 0; // top: arr数组的当前索引,表示已经存储到的路径的长度
|
||||
|
||||
printf("请输入七组数据!(字母 权值)\n");
|
||||
for (int i = 1; i <= 7; i++)
|
||||
{
|
||||
scanf("%c %d", &c[i], &a[i]);
|
||||
getchar(); // 吸收换行符,避免影响下一次输入
|
||||
}
|
||||
CreatHuffmanTree(HT, a, c, 7);
|
||||
printf("哈夫曼树先序遍历序列为(字母 权值):\n");
|
||||
printf("新生成结点用‘#’标记\n");
|
||||
DisplayHF(HT, 7 * 2 - 1); // 根节点下标为2n-1=13
|
||||
|
||||
printf("哈夫曼编码为:\n");
|
||||
DisplayHFCode(HT, 7 * 2 - 1, arr, top);
|
||||
|
||||
// 释放动态分配的内存(避免内存泄漏)
|
||||
delete[] HT;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user