贪心法构造哈夫曼树

合集下载

哈夫曼树结点数和叶子结点数的关系

哈夫曼树结点数和叶子结点数的关系

哈夫曼树结点数和叶子结点数的关系哈夫曼树是一种用来压缩信息的数据结构,它的关键在于能够将出现频率高的字符用较短的编码表示,从而达到节省空间的目的。

在构造哈夫曼树时,我们需要知道它的结点数和叶子结点数之间的关系,这是本文将要探讨的问题。

一、哈夫曼树的定义哈夫曼树(Huffman Tree)又称最优二叉树,是一种带权路径长度最短的树。

它的构造基于贪心算法,通过不断合并权值最小的两个子树来构造出最终的哈夫曼树。

在哈夫曼树中,树的每一个叶子结点都对应着一个字符,并且权值越大的叶子结点距离根结点越近。

二、哈夫曼树的结点数对于给定的n个字符(字符的出现概率已知),构造哈夫曼树时所需要的结点数是2n-1个。

这个结论可以通过归纳法证明。

首先,当n=1时,哈夫曼树只有一个结点,结论成立。

其次,当n=2时,哈夫曼树有3个结点。

假设当n=k时结论成立,考虑当n=k+1时的情况。

我们先对n个字符进行排序,找出权值最小的两个字符,将它们的权值相加得到一个新的权值,并构造一棵新的子树。

这样就将原来的n 个字符缩减成了n-1个字符,并且引入了一个新的结点。

在接下来的n-2次合并中,每次都引入了一个新的结点,所以总共需要2n-3个结点来构造出这n个字符对应的哈夫曼树。

此时,还需要引入一个新的根结点,作为两个结点(n个字符对应的两个子树)的父结点,并将两个子树连接到这个新的根结点上。

因此,总结点数为2n-3+1=2n-2。

最后,将新的根结点变为虚拟结点,并将n个叶子结点作为其子结点,就得到了结点数为2n-1的哈夫曼树。

三、哈夫曼树的叶子结点数在哈夫曼树中,每个叶子结点都对应着一个字符,因此叶子结点数就等于字符的个数n。

这个结论显然成立。

综上所述,哈夫曼树的结点数和叶子结点数之间存在如下关系:- 结点数 = 2n-1- 叶子结点数 = n这个结论可以帮助我们更好地理解哈夫曼树的构造过程,并且可以在实际应用中帮助我们提前估算哈夫曼树的大小。

哈夫曼树最短路径长度

哈夫曼树最短路径长度

哈夫曼树最短路径长度
(实用版)
目录
1.哈夫曼树的概念
2.哈夫曼树的最短路径长度
3.哈夫曼树的应用
4.结论
正文
1.哈夫曼树的概念
哈夫曼树(Huffman Tree)是一种用于数据压缩的树形结构,由美国计算机科学家 David A.Huffman 在 1952 年提出。

它是一种带权路径长度最短的二叉树,权值越大的节点离根节点越远。

哈夫曼树的构造方法称为贪心算法,每次选择权值最小的两个节点进行合并,直到所有节点合并为一个树。

2.哈夫曼树的最短路径长度
哈夫曼树的最短路径长度是指从根节点到叶子节点的最短路径长度。

在哈夫曼树中,叶子节点对应着输入数据中的各个字符,而根节点对应着输出数据中的各个位。

通过哈夫曼树,可以将原始数据压缩为较短的二进制编码,从而实现数据压缩。

3.哈夫曼树的应用
哈夫曼树广泛应用于数据压缩、图像压缩、语音识别等领域。

其中,数据压缩是哈夫曼树的主要应用之一。

通过对原始数据进行哈夫曼编码,可以得到较短的二进制编码,从而实现数据压缩。

在解压缩时,只需按照哈夫曼树从根节点到叶子节点的路径进行解码,即可还原原始数据。

4.结论
哈夫曼树是一种重要的数据结构,它可以实现带权路径长度最短,从而应用于数据压缩等领域。

哈夫曼编码贪心算法

哈夫曼编码贪心算法

哈夫曼编码贪心算法
一、哈夫曼编码
哈夫曼编码(Huffman Coding)是一种著名的数据压缩算法,也称作霍夫曼编码,由美国信息论家杰弗里·哈夫曼在1952年提出[1]。

哈夫曼编码可以有效地将资料压缩至最小,它的原理是将资料中出现频率最高的字元编码为最短的码字,而出现频率低的字元编码为较长的码字,从而显著提高了信息的保密性和容量。

二、贪心算法
贪心算法(Greedy Algorithm)是一种计算机算法,它试图找到一种满足条件的最佳解决方案,通常每一步都是做出在当前状态下最佳的选择,而不考虑将来可能发生的结果。

哈夫曼编码贪心算法是利用贪心算法来实现哈夫曼编码的。

该算法的步骤如下:
1. 首先统计出每一个字符出现的次数,并以此建立森林。

森林
中的每一棵树都用一个节点表示,每个节点的数值为字符出现的次数。

2. 从森林中挑选出两个出现次数最少的字符,将它们作为左右
子树合成一颗新的树,新树的根节点的数值为两个孩子节点的和。

3. 将新树加入森林中,并删除左右子树对应的原节点。

4. 重复上述步骤,直到森林中只剩一颗树,这颗树就是哈夫曼树。

5. 从哈夫曼树根节点出发,逐层往下搜索,左子节点编码为“0”,右子节点编码为“1”,最终得到每个字符的哈夫曼编码。

贪心算法实现Huffman编码

贪心算法实现Huffman编码

算法分析与设计实验报告第次实验附录:完整代码#include <iostream>#include <string>#include<stdio.h>#include <time.h>#include <iomanip>#include <vector>#include<algorithm>using namespace std;class Huffman{public:char elementChar;//节点元素int weight;//权重char s;//哈夫曼编码Huffman* parent;//父节点Huffman* leftChild;//左孩子Huffman* rightChild;//右孩子public:Huffman();Huffman(char a, int weight);bool operator < (const Huffman &m)const { return weight < m.weight;} };Huffman::Huffman(){this->s = ' ';this->elementChar = '*';//非叶子节点this->parent = this->leftChild = this->rightChild = NULL;}Huffman::Huffman(char a, int weight):elementChar(a),weight(weight) {this->s = ' ';this->elementChar = '*';//非叶子节点this->parent = this->leftChild = this->rightChild = NULL;}//递归输出哈夫曼值void huffmanCode(Huffman & h){if(h.leftChild == NULL && h.rightChild == NULL){//如果是叶子节点,输出器哈夫曼编码string s;Huffman temp = h;while(temp.parent != NULL){s = temp.s + s;temp = *temp.parent;}cout << h.elementChar << "的哈夫曼编码是:" << s << endl; return;}//左孩子huffmanCode(*h.leftChild);//右孩子huffmanCode(*h.rightChild);}int main(){int l,p=0;double q=0.0;clock_t start,end,over;start=clock();end=clock();over=end-start;start=clock();string huffmanStr;cout << "请输入一串字符序列:" << endl;cin >> huffmanStr;//得到字符串信息int i=0,j,n,m[100],h,k=0;char cha[100];n = huffmanStr.length();cout << "字符串总共有字符" << n << "个" << endl;for(int i = 0; i < n; i++){j = 0; h = 0;while(huffmanStr[i] != huffmanStr[j])j++;if(j == i){cha[k] = huffmanStr[i];cout << "字符" << cha[k] << "出现";}//如果j !=i 则略过此次循环elsecontinue;for(j = i; j < n; j++){if(huffmanStr[i] == huffmanStr[j])h++;}cout << h << "次" << endl;m[k] = h;k++;}//哈夫曼编码Huffman huffmanTemp;vector < Huffman > huffmanQueue;//初始化队列for(int i = 0; i < k; i++){huffmanTemp.elementChar = cha[i];huffmanTemp.weight = m[i];huffmanQueue.push_back(huffmanTemp);}//得到哈夫曼树所有节点int huffmanQueue_index = 0;sort(huffmanQueue.begin(), huffmanQueue.end());while(huffmanQueue.size() < 2 * k - 1){//合成最小两个节点的父节点huffmanTemp.weight = huffmanQueue[huffmanQueue_index].weight + huffmanQueue[huffmanQueue_index + 1].weight;huffmanQueue[huffmanQueue_index].s = '0';huffmanQueue[huffmanQueue_index + 1].s = '1';huffmanTemp.elementChar = '*';//将父节点加入队列huffmanQueue.push_back(huffmanTemp);sort(huffmanQueue.begin(), huffmanQueue.end());huffmanQueue_index += 2;}//把所有节点构造成哈夫曼树int step = 0;//步长while(step + 2 < 2 * k){for(int j = step + 1; j <= huffmanQueue.size(); j++){if(huffmanQueue[j].elementChar == '*' && huffmanQueue[j].leftChild == NULL && (huffmanQueue[j].weight == huffmanQueue[step].weight + huffmanQueue[step+1].weight)){huffmanQueue[j].leftChild = &huffmanQueue[step];huffmanQueue[j].rightChild = &huffmanQueue[step+1];huffmanQueue[step].parent = huffmanQueue[step+1].parent = &huffmanQueue[j]; break;}}step += 2;}//序列最后一个元素,即哈弗曼树最顶端的节点huffmanTemp = huffmanQueue.back();huffmanCode(huffmanTemp);for(l=0;l<1000000000;l++)p=p+l;end=clock();printf("The time is %6.3f",(double)(end-start-over)/CLK_TCK);return 0;}。

哈夫曼编码的贪心算法时间复杂度

哈夫曼编码的贪心算法时间复杂度

哈夫曼编码的贪心算法时间复杂度哈夫曼编码的贪心算法时间复杂度在信息技术领域中,哈夫曼编码是一种被广泛应用的数据压缩技术,它利用了贪心算法的思想来设计。

贪心算法是一种在每一步都选择当前状态下最优解的方法,从而希望通过一系列局部最优解达到全局最优解。

在哈夫曼编码中,这个想法被巧妙地运用,从而有效地实现了数据的高效压缩和解压缩。

哈夫曼编码是由大名鼎鼎的大卫·哈夫曼(David A. Huffman)在1952年提出的,它通过将频率最高的字符赋予最短的编码,最低的字符赋予最长的编码,从而实现了对数据的高效压缩。

这种编码技术在通信领域、存储领域和计算机科学领域都有着广泛的应用,是一种非常重要的数据处理技术。

在哈夫曼编码的实现过程中,贪心算法的时间复杂度是非常重要的。

时间复杂度是用来衡量算法所需时间的数量级,通常使用大O记号(O(n))来表示。

对于哈夫曼编码的贪心算法来说,其时间复杂度主要取决于以下几个步骤:1. 需要对数据进行统计,以获取每个字符出现的频率。

这个步骤的时间复杂度是O(n),其中n表示字符的数量。

在实际应用中,这个步骤通常由哈希表或统计排序来实现,因此时间复杂度可以控制在O(n)的数量级。

2. 接下来,需要构建哈夫曼树。

哈夫曼树是一种特殊的二叉树,它的构建过程需要将频率最低的两个节点合并成一个新的节点,然后再对新节点进行排序。

这个过程会持续n-1次,直到所有节点都被合并到一棵树中。

构建哈夫曼树的时间复杂度是O(nlogn),其中n表示字符的数量。

3. 根据哈夫曼树生成每个字符的编码。

这个过程涉及到对哈夫曼树进行遍历,并记录下每个字符对应的编码。

由于哈夫曼树的特性,每个字符的编码可以通过从根节点到叶子节点的路径来得到。

这个步骤的时间复杂度是O(n),因为对于每个字符都需要进行一次遍历。

哈夫曼编码的贪心算法时间复杂度主要由构建哈夫曼树的步骤决定,为O(nlogn)。

这意味着在实际应用中,哈夫曼编码的运行时间随着字符数量的增加而增加,并且增长速度为nlogn的数量级。

c语言哈夫曼树的构造及编码

c语言哈夫曼树的构造及编码

c语言哈夫曼树的构造及编码一、哈夫曼树概述哈夫曼树是一种特殊的二叉树,它的构建基于贪心算法。

它的主要应用是在数据压缩和编码中,可以将频率高的字符用较短的编码表示,从而减小数据存储和传输时所需的空间和时间。

二、哈夫曼树的构造1. 哈夫曼树的定义哈夫曼树是一棵带权路径长度最短的二叉树。

带权路径长度是指所有叶子节点到根节点之间路径长度与其权值乘积之和。

2. 构造步骤(1) 将待编码字符按照出现频率从小到大排序。

(2) 取出两个权值最小的节点作为左右子节点,构建一棵新的二叉树。

(3) 将新构建的二叉树加入到原来排序后队列中。

(4) 重复上述步骤,直到队列只剩下一个节点,该节点即为哈夫曼树的根节点。

3. C语言代码实现以下代码实现了一个简单版哈夫曼树构造函数:```ctypedef struct TreeNode {int weight; // 权重值struct TreeNode *leftChild; // 左子节点指针struct TreeNode *rightChild; // 右子节点指针} TreeNode;// 构造哈夫曼树函数TreeNode* createHuffmanTree(int* weights, int n) {// 根据权值数组构建节点队列,每个节点都是一棵单独的二叉树TreeNode** nodes = (TreeNode**)malloc(sizeof(TreeNode*) * n);for (int i = 0; i < n; i++) {nodes[i] = (TreeNode*)malloc(sizeof(TreeNode));nodes[i]->weight = weights[i];nodes[i]->leftChild = NULL;nodes[i]->rightChild = NULL;}// 构建哈夫曼树while (n > 1) {int minIndex1 = -1, minIndex2 = -1;for (int i = 0; i < n; i++) {if (nodes[i] != NULL) {if (minIndex1 == -1 || nodes[i]->weight < nodes[minIndex1]->weight) {minIndex2 = minIndex1;minIndex1 = i;} else if (minIndex2 == -1 || nodes[i]->weight < nodes[minIndex2]->weight) {minIndex2 = i;}}}TreeNode* newNode =(TreeNode*)malloc(sizeof(TreeNode));newNode->weight = nodes[minIndex1]->weight + nodes[minIndex2]->weight;newNode->leftChild = nodes[minIndex1];newNode->rightChild = nodes[minIndex2];// 将新构建的二叉树加入到原来排序后队列中nodes[minIndex1] = newNode;nodes[minIndex2] = NULL;n--;}return nodes[minIndex1];}```三、哈夫曼编码1. 哈夫曼编码的定义哈夫曼编码是一种前缀编码方式,它将每个字符的编码表示为二进制串。

贪心算法-哈弗曼编码、汽车加油问题

贪心算法-哈弗曼编码、汽车加油问题

1.问题描述哈夫曼编码(贪心策略)——要求给出算法思想、编码程序和译码程序,对样本数据“哈夫曼编码实验数据.dat”,要求提交符号的具体编码以及编码后的文件。

2.求解问题的贪心算法描述压缩数据由以下步骤组成:a)检查字符在数据中的出现频率。

b)构建哈夫曼树。

c)创建哈夫曼编码表。

d)生成压缩后结果,由一个文件头和压缩后的数据组成。

3.算法实现的关键技巧1.最小堆两种基本操作:插入新元素,抽取最小元素。

(1)插入新元素:把该元素放在二叉树的末端,然后从该新元素开始,向根节点方向进行交换,直到它到达最终位置。

(2)抽取最小元素:把根节点取走。

然后把二叉树的末端节点放到根节点上,然而把该节点向子结点反复交换,直到它到达最终位置。

2. 构建哈夫曼树:a)把所有出现的字符作为一个节点(单节点树),把这些树组装成最小堆;b)从该优先级队列中连续抽取两个频率最小的树分别作为左子树,右子树,将他们合并成一棵树(频率=两棵树频率之和),然后把这棵树插回队列中。

c)重复步骤b,每次合并都将使优先级队列的尺寸减小1,直到最后队列中只剩一棵树为止,就是我们需要的哈夫曼树。

3.压缩数据: 遍历输入的文本,对每个字符,根据编码表依次把当前字符的编码写入到编码结果中去。

File Header(文件头):unsigned int size; 被编码的文本长度(字符数);unsigned char freqs[ NUM_CHARS ]; 字符频率表compressed; (Bits: 压缩后的数据);4.贪心选择性质&最优子结构性质证明:即证明最优前缀码问题具有弹性选择性质和最优子结构性质.(1)贪心选择性质设C是编码字符集,C中字符c的频率为f(c)。

又设x,y是C中具有最小频率的两个字符,则存在C的最优前缀码使x,y具有相同码长且仅最后一位编码不同。

证明:设二叉树T表示C的任意一个最优前缀码。

对C左适当修改得到T“,使得在新树中,x和y是最深叶子且为兄弟。

哈夫曼树及哈夫曼编码的算法实现c语言

哈夫曼树及哈夫曼编码的算法实现c语言

哈夫曼树及哈夫曼编码的算法实现c语言1.引言1.1 概述哈夫曼树及哈夫曼编码是数据压缩和编码中常用的重要算法。

哈夫曼树由大卫·哈夫曼于1952年提出,用于根据字符出现的频率构建一种最优的前缀编码方式。

而哈夫曼编码则是根据哈夫曼树构建的编码表将字符进行编码的过程。

在现代通信和计算机领域,数据传输和存储中往往需要大量的空间。

为了有效利用有限的资源,减少数据的存储和传输成本,数据压缩成为一个重要的技术。

而哈夫曼树及哈夫曼编码正是数据压缩中常用的技术之一。

哈夫曼树的概念及原理是基于字符的频率和概率进行构建的。

在哈夫曼树中,字符出现频率越高的节点越接近根节点,出现频率越低的节点离根节点越远。

这种构建方式保证了哈夫曼树的最优性,即最小化编码的总长度。

哈夫曼编码的算法实现是根据哈夫曼树构建的编码表进行的。

编码表中,每个字符都与一段二进制编码相对应。

在进行数据压缩和解压缩时,通过查表的方式将字符转化为相应的二进制编码,或将二进制编码解析为原始字符。

本文旨在介绍哈夫曼树及哈夫曼编码的概念和原理,并通过C语言实现算法。

通过深入理解哈夫曼树及哈夫曼编码的实现过程,可以更好地理解数据压缩和编码的原理,为后续的研究和应用提供基础。

接下来,我们将首先介绍哈夫曼树的概念和原理,然后详细讲解哈夫曼编码的算法实现。

最后,我们将总结哈夫曼树及哈夫曼编码的重要性,并提出对哈夫曼树和哈夫曼编码进一步研究的方向。

让我们一起深入探索哈夫曼树及哈夫曼编码的奥秘吧!1.2 文章结构文章结构部分的内容可以包括以下内容:文章结构部分主要介绍了本文的组织结构和各个章节的内容概述,以帮助读者更好地理解全文的逻辑结构和内容安排。

首先,本文包括引言、正文和结论三个部分。

引言部分主要对哈夫曼树及哈夫曼编码的算法实现进行了概述,包括相关的概念、原理和目的。

正文部分则深入介绍了哈夫曼树的概念和原理,以及哈夫曼编码的算法实现。

最后,结论部分对本文的主要内容进行了总结,并提出了对哈夫曼树和哈夫曼编码的进一步研究方向。

哈夫曼算法的理解及原理分析算法实现构造哈夫曼树的算法

哈夫曼算法的理解及原理分析算法实现构造哈夫曼树的算法

哈夫曼算法的理解及原理分析算法实现构造哈夫曼树的算法哈夫曼算法(Huffman Algorithm)是一种贪心算法,用于构建最优二叉树(也称为哈夫曼树或者最优前缀编码树),主要用于数据压缩和编码。

它通过统计字符出现的频率来构建一个编码表,将较频繁出现的字符用较短的编码表示,从而减少存储空间和传输带宽。

原理分析:1.统计字符出现的频率:遍历待编码的字符串,统计每个字符出现的次数。

2.构建哈夫曼树:根据字符频率构建二叉树,频率越高的字符位置越靠近根节点,频率越低的字符位置越远离根节点。

构建哈夫曼树的通常做法是使用最小堆来存储频率,并反复合并堆中最小的两个节点,直到堆中只剩一个节点,即根节点。

3.生成编码表:从根节点开始,沿着左子树为0,右子树为1的路径将所有叶子节点的编码存储在一个编码表中。

算法实现:下面是一个简单的Python实现示例:```pythonclass Node:def __init__(self, char, freq):self.char = charself.freq = freqself.left = Noneself.right = Nonedef build_huffman_tree(text):#统计字符频率freq_dict = {}for char in text:if char in freq_dict:freq_dict[char] += 1else:freq_dict[char] = 1#构建最小堆heap = []for char, freq in freq_dict.items(: node = Node(char, freq)heap.append(node)heap.sort(key=lambda x: x.freq)#构建哈夫曼树while len(heap) > 1:left = heap.pop(0)right = heap.pop(0)parent = Node(None, left.freq + right.freq) parent.left = leftparent.right = rightheap.append(parent)heap.sort(key=lambda x: x.freq)root = heap[0]#生成编码表code_table = {}generate_code(root, "", code_table)return code_tabledef generate_code(node, code, code_table):if node.char:code_table[node.char] = codereturngenerate_code(node.left, code + "0", code_table) generate_code(node.right, code + "1", code_table) ```构造哈夫曼树的算法:上述的 `build_huffman_tree` 函数通过统计频率构建了最小堆`heap`,然后不断地合并最小的两个节点,直到堆中只剩下一个节点,即哈夫曼树的根节点。

构造哈夫曼树代码

构造哈夫曼树代码

构造哈夫曼树:理论与实践哈夫曼树是一种重要的数据结构,它广泛应用于编码压缩和加密算法中。

本文将介绍哈夫曼树的原理和构造方法,并给出代码实现。

一、哈夫曼树的种类哈夫曼树分为静态哈夫曼树和动态哈夫曼树两种,其中静态哈夫曼树适用于数据量较小且变化不大的情况,而动态哈夫曼树则更适用于数据量较大且动态变化的情况。

二、哈夫曼树的构造方法哈夫曼树的构造方法一般有两种:贪心算法和分治算法。

其中贪心算法是最常用的构造方法,它的基本思想是每次选择出现频率最小的两个节点作为左右子树,然后合并成一个节点,直到所有节点都合并为一个根节点。

三、哈夫曼树的代码实现以下是基于贪心算法的哈夫曼树代码实现:```include <iostream>include <queue>include <vector>include <algorithm>using namespace std;struct Node {int val, freq;Node *left, *right;Node(int v, int f) : val(v), freq(f), left(nullptr), right(nullptr) {};};struct cmp {bool operator()(Node* a, Node* b) {return a->freq > b->freq;}};void buildHuffmanTree(vector<int>& arr) {priority_queue<Node*, vector<Node*>, cmp> pq;for (int i = 0; i < arr.size(); i++) {pq.push(new Node(arr[i], arr[i]));}while (pq.size() > 1) {Node* left = pq.top();pq.pop();Node* right = pq.top();pq.pop();Node* parent = new Node(-1, left->freq + right->freq);parent->left = left;parent->right = right;pq.push(parent);}}int main() {vector<int> arr {1, 2, 3, 4, 5};buildHuffmanTree(arr);return 0;}```四、总结本文介绍了哈夫曼树的原理和构造方法,并给出了基于贪心算法的代码实现。

acm贪心算法经典题型归纳

acm贪心算法经典题型归纳

acm贪心算法经典题型归纳
贪心算法是一种在求解最优化问题时常用的算法思想,它通常
用于解决那些具有最优子结构性质的问题。

在ACM竞赛中,贪心算
法经典题型主要包括以下几类:
1. 区间调度问题,这类问题要求在一系列区间中选择尽量多的
不重叠区间。

经典问题包括最大不重叠区间数量、最小区间覆盖等。

2. 背包问题,在给定背包容量和一系列物品的重量、价值的情
况下,选择装入背包的物品,使得背包内物品的总价值最大。

贪心
算法通常用于解决部分背包问题或者分数背包问题。

3. 最小生成树,贪心算法经典的应用之一是求解最小生成树,
其中Prim算法和Kruskal算法就是典型的贪心算法。

4. 最短路径问题,在有向图或者无向图中,求解起点到终点的
最短路径。

Dijkstra算法和Bellman-Ford算法都可以使用贪心思
想进行优化。

5. 哈夫曼编码,贪心算法还可以用于构造哈夫曼树,实现数据
的最优编码。

以上仅是贪心算法在ACM竞赛中的一些经典题型,实际上贪心算法还可以应用于很多其他问题的求解中。

在解决这些问题时,需要注意贪心选择性质和最优子结构性质,合理选择贪心策略,并证明其正确性。

同时,也需要注意到贪心算法并不适用于所有问题,有时候需要结合动态规划等其他算法来求解。

希望这些信息对你有帮助。

哈夫曼编码的贪心算法时间复杂度

哈夫曼编码的贪心算法时间复杂度

哈夫曼编码是一种广泛应用于数据压缩领域的编码方式,而哈夫曼编码的贪心算法是实现这一编码方式的重要方法之一。

在本文中,我将深入探讨哈夫曼编码及其贪心算法的时间复杂度,并就此展开全面评估。

让我们简要回顾一下哈夫曼编码的基本概念。

哈夫曼编码是一种变长编码方式,通过将出现频率高的字符用较短的编码表示,而将出现频率低的字符用较长的编码表示,从而实现数据的有效压缩。

在这一编码方式中,贪心算法被广泛应用于构建哈夫曼树,以实现最优编码方案的选择。

那么,接下来我们将重点关注哈夫曼编码的贪心算法时间复杂度。

哈夫曼编码的贪心算法的时间复杂度主要取决于两个方面:构建哈夫曼树的时间复杂度和编码字符串的时间复杂度。

让我们来看构建哈夫曼树的时间复杂度。

在哈夫曼编码的贪心算法中,构建哈夫曼树的时间复杂度主要取决于构建最小堆(或最大堆)以及合并节点的操作。

在构建最小堆的过程中,需要对所有字符按照其频率进行排序,并将其依次插入最小堆中,这一操作的时间复杂度为O(nlogn)。

而在合并节点的过程中,需要不断从最小堆中取出两个频率最小的节点,并将其合并为一个新节点,然后再将新节点插入最小堆中,这一操作需要进行n-1次,所以合并节点的时间复杂度为O(nlogn)。

构建哈夫曼树的时间复杂度为O(nlogn)。

我们来看编码字符串的时间复杂度。

在使用哈夫曼编码对字符串进行编码时,需要根据构建好的哈夫曼树来进行编码,这一过程的时间复杂度主要取决于字符串的长度和哈夫曼树的深度。

由于哈夫曼树是一个二叉树,所以在最坏情况下,编码一个字符的时间复杂度为O(n),其中n为哈夫曼树的深度。

编码字符串的时间复杂度为O(kn),其中k 为字符串的长度。

哈夫曼编码的贪心算法的时间复杂度主要包括构建哈夫曼树的时间复杂度和编码字符串的时间复杂度,其中构建哈夫曼树的时间复杂度为O(nlogn),编码字符串的时间复杂度为O(kn)。

哈夫曼编码的贪心算法的时间复杂度为O(nlogn+kn)。

贪心法求哈夫曼编码

贪心法求哈夫曼编码

实验题目:设需要编码的字符集为{d1, d2, …, dn},它们出现的频率为{w1, w2, …, wn},应用哈夫曼树构造最短的不等长编码方案。

实验目的:(1)了解前缀编码的概念,理解数据压缩的基本方法;(2)掌握最优子结构性质的证明方法;(3)掌握贪心法的设计思想并能熟练运用。

实验内容:实验代码:#include <iostream>using namespace std;/** 霍夫曼树结构*/class HuffmanTree{public:unsigned int Weight, Parent, lChild, rChild;};typedef char **HuffmanCode;/** 从结点集合中选出权值最小的两个结点* 将值分别赋给s1和s2*/void Select(HuffmanTree* HT,int Count,int *s2,int *s1){unsigned int temp1=0;unsigned int temp2=0;unsigned int temp3;for(int i=1;i<=Count;i++){if(HT[i].Parent==0){if(temp1==0){temp1=HT[i].Weight;(*s1)=i;}else{if(temp2==0){temp2=HT[i].Weight;(*s2)=i;if(temp2<temp1){temp3=temp2;temp2=temp1;temp1=temp3;temp3=(*s2);(*s2)=(*s1);(*s1)=temp3;}}else{if(HT[i].Weight<temp1){temp2=temp1;temp1=HT[i].Weight;(*s2)=(*s1);(*s1)=i;}if(HT[i].Weight>temp1&&HT[i].Weight<temp2){temp2=HT[i].Weight;(*s2)=i;}}}}}}/** 霍夫曼编码函数*/void HuffmanCoding(HuffmanTree * HT,HuffmanCode * HC,int *Weight,int Count){int i;int s1,s2;int TotalLength;char* cd;unsigned int c;unsigned int f;int start;if(Count<=1) return;TotalLength=Count*2-1;HT = new HuffmanTree[(TotalLength+1)*sizeof(HuffmanTree)];for(i=1;i<=Count;i++){HT[i].Parent=0;HT[i].rChild=0;HT[i].lChild=0;HT[i].Weight=(*Weight);Weight++;}for(i=Count+1;i<=TotalLength;i++){HT[i].Weight=0;HT[i].Parent=0;HT[i].lChild=0;HT[i].rChild=0;}//建造霍夫曼树for(i=Count+1;i<=TotalLength;++i){Select(HT, i-1, &s1, &s2);HT[s1].Parent = i;HT[s2].Parent = i;HT[i].lChild = s1;HT[i].rChild = s2;HT[i].Weight = HT[s1].Weight + HT[s2].Weight;}//输出霍夫曼编码(*HC)=(HuffmanCode)malloc((Count+1)*sizeof(char*));cd = new char[Count*sizeof(char)];cd[Count-1]='\0';for(i=1;i<=Count;++i){start=Count-1;for(c = i,f = HT[i].Parent; f != 0; c = f, f = HT[f].Parent){if(HT[f].lChild == c)cd[--start]='0';elsecd[--start]='1';(*HC)[i] = new char [(Count-start)*sizeof(char)];strcpy((*HC)[i], &cd[start]);}}delete [] HT;delete [] cd;}/** 在字符串中查找某个字符* 如果找到,则返回其位置*/int LookFor(char *str, char letter, int count){int i;for(i=0;i<count;i++){if(str[i]==letter) return i;}return -1;}void OutputWeight(char *Data,int Length,char **WhatLetter,int **Weight,int *Count){int i;char* Letter = new char[Length];int* LetterCount = new int[Length];int AllCount=0;int Index;int Sum=0;float Persent=0;for(i=0;i<Length;i++){if(i==0){Letter[0]=Data[i];LetterCount[0]=1;AllCount++;}else{Index=LookFor(Letter,Data[i],AllCount);if(Index==-1){Letter[AllCount]=Data[i];LetterCount[AllCount]=1;AllCount++;}else{LetterCount[Index]++;}}}for(i=0;i<AllCount;i++){Sum=Sum+LetterCount[i];}(*Weight) = new int[AllCount];(*WhatLetter) = new char[AllCount];for(i=0;i<AllCount;i++){Persent=(float)LetterCount[i]/(float)Sum;(*Weight)[i]=(int)(100*Persent);(*WhatLetter)[i]=Letter[i];}(*Count)=AllCount;delete [] Letter;delete [] LetterCount;}int main(){HuffmanTree * HT = NULL;HuffmanCode HC;char Data[100];char *WhatLetter;int *Weight;int Count;cout<<"请输入一行文本数据:"<<endl;cin>>Data;cout<<endl;OutputWeight(Data,strlen(Data),&WhatLetter,&Weight,&Count); HuffmanCoding(HT, &HC, Weight, Count);cout<<"字符出现频率编码结果"<<endl;for(int i = 0; i<Count; i++){cout<<WhatLetter[i]<<" ";cout<<Weight[i]<<"%\t";cout<<HC[i+1]<<endl;}cout<<endl;system("pause");return 0;}实验结果截图:哈夫曼算法描述:(1)初始化:将初始森林的各根结点(双亲)和左右孩子指针置为-1;(2)输入叶子权:叶子在向量T的前n个分量中,构成初始森林的n个根结点;(3)合并:对森林中的树进行n-1次合并,共产生n-1个新结点,依次放入向量T的第i 个分量(n<=i<=m-1)中,每次合并的步骤是:a、在当前森林的所有结点中,选取具有最小权值和次小权值的两个结点,分别用p1和p2记住这两个根节点在向量T中的下标;b、将根为T[p1]和T[p2]的两棵树合并,使其成为新结点T[i]的左右孩子,得到一棵以新结点T[i]为根的二叉树若取pi为叶结点的权,取编码长度li为叶结点的路径长度,则∑ pi ⨯li最小的问题就是带权路径长度最小的哈夫曼树的构造问题。

哈夫曼树构造规则

哈夫曼树构造规则

哈夫曼树构造规则哈夫曼树是一种用于数据压缩和编码的重要数据结构。

它是由一组字符和它们对应的频率构成的,根据频率构造出来的一种特殊的二叉树。

哈夫曼树的构造规则如下:1. 频率越高的字符越靠近根节点在哈夫曼树中,频率越高的字符被赋予越短的编码,这样可以减少编码的长度,从而达到压缩数据的目的。

因此,在构造哈夫曼树时,我们需要根据字符的频率来确定它们在树中的位置,频率越高的字符越靠近根节点。

2. 构造过程中采用贪心算法构造哈夫曼树的过程中,我们需要根据字符的频率来选择合适的节点进行合并。

在每一步中,我们选择频率最小的两个节点进行合并,然后将合并后的节点作为一个新节点插入到原来的节点集合中。

这种选择最小频率的节点的策略就是贪心算法。

3. 合并节点的频率为两个节点频率之和当我们选择两个频率最小的节点进行合并时,合并后的节点的频率就是这两个节点的频率之和。

这是因为合并后的节点代表了这两个节点的集合,所以它的频率就是这两个节点频率之和。

4. 构造过程中节点数目逐渐减少在构造哈夫曼树的过程中,每次合并两个节点,树的节点数目就减少一个。

最终,当只剩下一个节点时,这个节点就是哈夫曼树的根节点。

5. 构造过程中节点的位置不变在哈夫曼树的构造过程中,每个节点的位置是固定的,只是节点之间的连接关系发生了变化。

频率越高的节点越靠近根节点,频率越低的节点越远离根节点。

6. 哈夫曼树的带权路径长度最小哈夫曼树的带权路径长度是指树中每个叶子节点的权值乘以它到根节点的路径长度之和。

在所有可能的二叉树中,哈夫曼树的带权路径长度是最小的,这也是它被广泛应用于数据压缩和编码的原因之一。

通过以上的构造规则,我们可以得到一个符合要求的哈夫曼树。

这棵树可以用于对字符进行编码和解码,实现数据的压缩和解压缩。

在哈夫曼树中,频率高的字符对应的编码较短,频率低的字符对应的编码较长,从而实现了数据的有效压缩。

同时,由于哈夫曼树的构造过程中采用了贪心算法,所以构造出来的哈夫曼树的带权路径长度是最小的,这也保证了数据压缩的效果。

13、利用贪婪法构造哈夫曼编码(1)

13、利用贪婪法构造哈夫曼编码(1)

数学与计算机学院课程设计说明书课程名称: 算法设计与分析-课程设计课程代码: 7106620题目: 利用贪婪法构造哈夫曼编码年级/专业/班:学生姓名:学号:开始时间:2010 年12 月26日完成时间:2011 年01 月09 日课程设计成绩:学习态度及平时成绩(30)技术水平与实际能力(20)创新(5)说明书撰写质量(45)总分(100)指导教师签名:年月日目录1 引言 (1)1.1问题的提出 (1)1.2国内外研究的现状 (1)1.3任务与分析 (4)2 程序的主要功能 (4)2.1定义结构体 (4)2.2动态存储 (4)2.3静态存储 (4)2.4哈夫曼算法 (4)2.5选择结点编码 (4)3 总体设计 (5)3.1数据存储结构设计 (5)3.2操作模块设计 (6)3.3建树算法设计 (6)4 结构体的说明 (7)5 模块分析 (7)5.1静态存储选择最小结点的算法 (7)5.2静态存储哈夫曼编码 (8)5.3动态存储选择最小结点的算法 (9)5.4动态存储哈夫曼编码 (10)6 系统测试 (12)6.1设计测试数据 (12)6.2静态存储测试结果及分析 (12)6.3动态存储测试结果及分析 (13)7 结论 (14)8 参考文献 (14)致谢 (15)摘要哈夫曼编码是哈夫曼树的一个应用。

哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。

哈夫曼在上世纪五十年代初就提出这种编码时,根据字符出现的概率来构造平均长度最短的编码。

它是一种变长的编码。

在编码中,若各码字长度严格按照码字所对应符号出现概率的大小的逆序排列,则编码的平均长度是最小的。

(注:码字即为符号经哈夫曼编码后得到的编码,其长度是因符号出现的概率而不同,所以说哈夫曼编码是变长的编码。

)哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。

以哈夫曼树─即最优二叉树,带权路径长度最小的二叉树,经常应用于数据压缩。

贪心法构造哈夫曼树

贪心法构造哈夫曼树

实验报告( 2013 / 2014 学年第二学期)学院贝尔学院学生姓名任晓强班级学号 Q12010218 指导教师季一木指导单位计算机软件教学中心日期 2014年3月12日实验一:贪心算法构造哈夫曼树问题简述:两路合并最佳模式的贪心算法主要思想如下:(1)设w={w0,w1,......w}是一组权值,以每个权值作为根结点值,构造n棵只有根的n-1二叉树(2)选择两根结点权值最小的树,作为左右子树构造一棵新二叉树,新树根的权值是两棵子树根权值之和(3)重复(2),直到合并成一颗二叉树为止一、实验目的(1)了解贪心算法和哈夫曼树的定义(2)掌握贪心法的设计思想并能熟练运用(3)设计贪心算法求解哈夫曼树(4)设计测试数据,写出程序文档二、实验内容(1)设计二叉树结点数据结构,编程实现对用户输入的一组权值构造哈夫曼树(2)设计函数,先序遍历输出哈夫曼树各结点(3)设计函数,按树形输出哈夫曼树三、程序源代码#include <stdio.h>#include <string.h>#include <time.h>#include <stdlib.h>typedef struct Node{ //定义树结构int data;struct Node *leftchild;struct Node *rightchild;}Tree;typedef struct Data{ //定义字符及其对应的频率的结构int data;//字符对应的频率是随机产生的char c;};void Initiate(Tree **root);//初始化节点函数int getMin(struct Data a[],int n);//得到a中数值(频率)最小的数void toLength(char s[],int k);//设置有k个空格的串svoid set(struct Data a[],struct Data b[]);//初始化a,且将a备份至b char getC(int x,struct Data a[]);//得到a中频率为x对应的字符void prin(struct Data a[]);//输出初始化后的字符及对应的频率int n;void main(){//srand((unsigned)time(NULL));Tree *root=NULL,*left=NULL,*right=NULL,*p=NULL;int min,num;int k=30,j,m;struct Data a[100];struct Data b[100];int i;char s[100]={'\0'},s1[100]={'\0'}; char c;set(a,b);prin(a);Initiate(&root);Initiate(&left);Initiate(&right);Initiate(&p);//设置最底层的左节点min=getMin(a,n);left->data=min;left->leftchild=NULL;left->rightchild=NULL;//设置最底层的右节点min=getMin(a,n-1);right->data=min;right->leftchild=NULL;right->rightchild=NULL;root->data=left->data+right->data; Initiate(&root->leftchild);Initiate(&root->rightchild);//将设置好的左右节点插入到root中root->leftchild=left;root->rightchild=right;for(i=0;i<n-2;i++){min=getMin(a,n-2-i);Initiate(&left);Initiate(&right);if(min<root->data)//权值小的作为左节点{left->data=min;left->leftchild=NULL;left->rightchild=NULL;p->data=min+root->data;Initiate(&p->leftchild);Initiate(&p->rightchild);p->leftchild=left;p->rightchild=root;root=p;}else{right->data=min;right->leftchild=NULL;right->rightchild=NULL;p->data=min+root->data;Initiate(&p->leftchild);Initiate(&p->rightchild);p->leftchild=root;p->rightchild=right;root=p;}Initiate(&p);}num=n-1;p=root;printf("哈夫曼树如下图:\n");while(num){if(num==n-1){for(j=0;j<k-3;j++)printf(" ");printf("%d\n",root->data);}for(j=0;j<k-4;j++)printf(" ");printf("/ \\\n");for(j=0;j<k-5;j++)printf(" ");printf("%d",root->leftchild->data);printf(" %d\n",root->rightchild->data);if(root->leftchild->leftchild!=NULL){root=root->leftchild;k=k-2;}else{root=root->rightchild;k=k+3;}num--;}num=n-1;Initiate(&root);root=p;printf("各字符对应的编码如下:\n");while(num){if(root->leftchild->leftchild==NULL){strcpy(s1,s);m=root->leftchild->data;c=getC(m,b);printf("%c 【%d】:%s\n",c,m,strcat(s1,"0"));}if(root->rightchild->leftchild==NULL){strcpy(s1,s);m=root->rightchild->data;c=getC(m,b);printf("%c 【%d】:%s\n",c,m,strcat(s1,"1"));}if(root->leftchild->leftchild!=NULL){strcat(s,"0");root=root->leftchild;}if(root->rightchild->leftchild!=NULL){strcat(s,"1");root=root->rightchild;}num--;}}int getMin(struct Data a[],int n){int i,t;for(i=1;i<n;i++){if(a[i].data<a[0].data){t=a[i].data;a[i].data=a[0].data;a[0].data=t;}}t=a[0].data;for(i=0;i<n-1;i++){a[i]=a[i+1];}return t;}void toLength(char s[],int k){int i=0;for(;i<k;i++)strcat(s," ");}void Initiate(Tree **root){*root=(Tree *)malloc(sizeof(Tree));(*root)->leftchild=NULL;(*root)->rightchild=NULL;}void set(struct Data a[],struct Data b[]) {int i;srand((unsigned)time(NULL));n=rand()%10+2;for(i=0;i<n;i++){a[i].data=rand()%100+1;a[i].c=i+97;b[i].data=a[i].data;b[i].c=a[i].c;if(i>=0&&a[i].data==a[i-1].data)i--;}}char getC(int x,struct Data b[]){int i;for(i=0;i<n;i++){if(b[i].data==x){break;}}return b[i].c;}void prin(struct Data a[]){int i;printf("字符\t出现的频率\n");for(i=0;i<n;i++){printf("%c\t %d\n",a[i].c,a[i].data);}}四、程序运行结果演示五、实验体会哈夫曼编码算法:每次将集合中两个权值最小的二叉树合并成一棵新二叉树,n-1次合并后,成为最终的一棵哈夫曼树。

贪心算法的概念

贪心算法的概念

贪心算法的概念贪心算法的概念概述贪心算法(Greedy Algorithm)是一种基于贪心策略的算法,它在每个阶段选择局部最优解,并以此来达到全局最优解的目标。

贪心算法通常用于求解最优化问题,如最小生成树、哈夫曼编码、背包问题等。

特点1. 贪心算法是一种简单而高效的算法,其时间复杂度通常较低。

2. 贪心算法只考虑当前状态下的最优解,不考虑未来可能出现的情况。

3. 贪心算法需要满足“无后效性”,即某个状态下的选择不会影响到之后状态的选择。

4. 贪心算法需要满足“局部最优性”,即每次选择都是当前状态下的最优解。

5. 贪心算法不能保证一定能得到全局最优解,但在某些情况下可以得到近似最优解。

应用1. 最小生成树:Kruskal和Prim两种方法都是基于贪心策略实现的。

2. 哈夫曼编码:通过构造一棵哈夫曼树来实现编码,其中每个字符对应一个叶子节点,权值为出现频率,通过合并权值较小的节点得到每个字符的编码。

3. 背包问题:贪心算法可以通过计算每个物品的单位价值(即价值与重量的比值)来选择最优解,但该方法只适用于部分背包问题。

4. 最短路径问题:Dijkstra算法和Bellman-Ford算法都是基于贪心策略实现的。

5. 调度问题:如任务调度、机器调度等,可以通过贪心算法得到近似最优解。

缺点1. 贪心算法不能保证一定能得到全局最优解,只能得到近似最优解。

2. 贪心算法需要满足“无后效性”和“局部最优性”,但这两个条件不一定容易满足,有时需要进行特殊处理。

3. 贪心算法可能会受到数据规模和数据分布等因素的影响,导致结果不准确或者无法得出结果。

总结贪心算法是一种简单而高效的算法,其时间复杂度通常较低。

它在求解最优化问题时具有一定的应用价值。

但贪心算法不能保证一定能得到全局最优解,只能得到近似最优解。

在实际应用中需要注意选择合适的贪心策略,并对特殊情况进行特殊处理。

贪心算法哈夫曼编码c语言

贪心算法哈夫曼编码c语言

贪心算法哈夫曼编码c语言哈夫曼编码的贪心算法可以分为以下几步:1. 读入需要编码的字符及其出现频率,并按照频率从小到大排序。

2. 构建哈夫曼树。

首先将所有字符看成只有一个节点的树,然后取出频率最小的两棵树,将它们合并成一棵树,这棵树的频率是两棵树的频率之和。

继续取出频率最小的两棵树,重复上述过程,直到只剩下一棵树为止,这就是哈夫曼树。

3. 对哈夫曼树进行编码。

从哈夫曼树的根节点开始,往左走为0,往右走为1,一直走到叶子节点,记录下这个叶子节点代表的字符的编码。

这就是哈夫曼编码。

以下是用C语言实现的贪心算法实现:```c#include <stdio.h>#include <stdlib.h>#include <string.h>#define MAX_N 256 // 假设字符集大小为256typedef struct node {char ch; // 字符int freq; // 频率struct node *left, *right; // 左右子节点} Node;// 建立一个新的节点Node* new_node(char ch, int freq) {Node *node = (Node*)malloc(sizeof(Node));node->ch = ch;node->freq = freq;node->left = node->right = NULL;return node;}// 在nodes数组中找寻最小的两个节点void find_min_two_nodes(Node **nodes, int size, int *min1, int *min2) {*min1 = *min2 = -1;for (int i = 0; i < size; i++) {if (nodes[i] == NULL) continue;if (*min1 == -1 || nodes[i]->freq < nodes[*min1]->freq) {*min2 = *min1;*min1 = i;} else if (*min2 == -1 || nodes[i]->freq < nodes[*min2]->freq) {*min2 = i;}}}// 构建哈夫曼树Node* build_huffman_tree(char *str, int *freq, int n) {Node *nodes[MAX_N];for (int i = 0; i < n; i++) {nodes[i] = new_node(str[i], freq[i]);}int size = n;while (size > 1) {int min1, min2;find_min_two_nodes(nodes, size, &min1, &min2);Node *node = new_node(0, nodes[min1]->freq +nodes[min2]->freq);node->left = nodes[min1];node->right = nodes[min2];nodes[min1] = node;nodes[min2] = NULL;size--;}return nodes[0];}// 递归生成哈夫曼编码void gen_huffman_code(Node *root, char *code, int depth, char **table) {if (root == NULL) return;if (root->left == NULL && root->right == NULL) {code[depth] = '\0';table[root->ch] = (char*)malloc((depth + 1) * sizeof(char)); strcpy(table[root->ch], code);return;}code[depth] = '0';gen_huffman_code(root->left, code, depth + 1, table);code[depth] = '1';gen_huffman_code(root->right, code, depth + 1, table); }// 哈夫曼编码char** huffman_code(char *str, int *freq, int n) {Node *root = build_huffman_tree(str, freq, n);char **table = (char**)malloc(MAX_N * sizeof(char*)); char code[MAX_N];gen_huffman_code(root, code, 0, table);return table;}int main() {char str[] = "ABACCABB";int freq[] = {2, 3, 1, 2, 1, 1, 1, 1};int n = strlen(str);char **table = huffman_code(str, freq, n);for (int i = 0; i < n; i++) {printf("char: %c, code: %s\n", str[i], table[str[i]]);}return 0;}```输出结果:```char: A, code: 11char: B, code: 0char: A, code: 11char: C, code: 100char: C, code: 100char: A, code: 11char: B, code: 1char: B, code: 01```这就是对字符串"ABACCABB"进行哈夫曼编码的结果。

哈夫曼树构造方法

哈夫曼树构造方法

哈夫曼树构造方法哈夫曼树(Huffman Tree)是一种广泛应用于数据压缩和编码的二叉树结构。

它是一种最优二叉树,即带权路径长度最短的二叉树。

哈夫曼树的构造方法主要有两种:贪心算法和分治算法。

1. 贪心算法:哈夫曼树的贪心算法是一种自底向上(从叶子节点到根节点)的构造方法。

首先,根据给定的权值列表,将每个权值看作一个独立的节点,并按照权值从小到大的顺序构建一个森林。

然后,从森林中选择权值最小的两个节点(可以使用最小堆来实现),将它们合并为一个新的节点,并将新节点的权值设为两个被合并节点的权值之和。

将新节点插入到森林中,并移除原来的两个节点。

重复上述步骤,直到森林中只有一个节点为止,该节点就是哈夫曼树的根节点。

贪心算法构造哈夫曼树的时间复杂度为O(nlogn),n为节点数量。

2. 分治算法:哈夫曼树的分治算法是一种自顶向下(从根节点到叶子节点)的构造方法。

首先,将给定的权值列表按照权值从小到大的顺序排序。

然后,将权值最小的两个节点合并为一个新的节点,并将新节点的权值设为两个被合并节点的权值之和。

将新节点插入到排序后的列表中,并移除原来的两个节点。

重复上述步骤,直到列表中只有一个节点为止,该节点就是哈夫曼树的根节点。

分治算法构造哈夫曼树的时间复杂度为O(n^2),n为节点数量。

无论是贪心算法还是分治算法,构造出的哈夫曼树都具有最优性质,即带权路径长度最短。

由于贪心算法的时间复杂度较低,因此在实际应用中更为常用。

另外,构造哈夫曼树的方法除了贪心算法和分治算法外,还可以使用动态规划等其他方法。

对于哈夫曼树的应用,最常见的是数据压缩和编码。

哈夫曼树可以根据字符出现的频率构建对应的编码表,将频率高的字符用较短的编码表示,将频率低的字符用较长的编码表示,从而实现对数据的压缩。

在压缩的过程中,利用哈夫曼树可以实现对数据的高效编码和解码。

此外,哈夫曼树还有其他应用,比如在路由表的构建和图像压缩等领域也有广泛应用。

贪心算法

贪心算法

max vi xi
i 1
n
于是,背包问题归结为寻找一个满足约束条 件式,并使目标函数式达到最大的解向量X=(x1, x2, …, xn)。
至少有三种看似合理的贪心策略: (1)选择价值最大的物品,因为这可以尽可能快 地增加背包的总价值。但是,虽然每一步选择获得 了背包价值的极大增长,但背包容量却可能消耗得 太快,使得装入背包的物品个数减少,从而不能保 证目标函数达到最大。 (2)选择重量最轻的物品,因为这可以装入尽可 能多的物品,从而增加背包的总价值。但是,虽然 每一步选择使背包的容量消耗得慢了,但背包的价 值却没能保证迅速增长,从而不能保证目标函数达 到最大。 (3)选择单位重量价值最大的物品,在背包价值 增长和背包容量消耗两者之间寻找平衡。
算法
main( ) { int i,j,n,GZ,A; int B[8]={0,100,50,20,10,5,2,1},S[8]; input(n); for(i=1;i<=n;i++) { input(GZ); for(j=1,j<=7;j++) { A=GZ/B[j]; S[j]=S[j]+A; GZ=GZ-A*B[j];} } for(i=1;i<=7;i++) print(B[i], “----”, S[i]); }
∞ b 4 0 a 8 h ∞ 4 b 4 0 a 8 h 8 11 7 11 7
8 ∞ i 6 1 2
∞ c
7
∞ d 14 9 e ∞ 10
4 g ∞
2
f ∞
(a)
8 ∞ i 6 1 g ∞ 2 4 f ∞ ∞ c 7 ∞ d 14 9 e ∞ 10 2
贪心法求解活动安排问题的关键是如何选择贪心策略,使 得按照一定的顺序选择相容活动,并能安排尽量多的活动。至 少有两种看似合理的贪心策略: (1)最早开始时间:这样可以增大资源的利用率。 (2)最早结束时间:这样可以使下一个活动尽早开始。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验报告( 2013 / 2014 学年第二学期)学院贝尔学院学生姓名任晓强班级学号 Q12010218 指导教师季一木指导单位计算机软件教学中心日期 2014年3月12日实验一:贪心算法构造哈夫曼树问题简述:两路合并最佳模式的贪心算法主要思想如下:(1)设w={w0,w1,......w}是一组权值,以每个权值作为根结点值,构造n棵只有根的n-1二叉树(2)选择两根结点权值最小的树,作为左右子树构造一棵新二叉树,新树根的权值是两棵子树根权值之和(3)重复(2),直到合并成一颗二叉树为止一、实验目的(1)了解贪心算法和哈夫曼树的定义(2)掌握贪心法的设计思想并能熟练运用(3)设计贪心算法求解哈夫曼树(4)设计测试数据,写出程序文档二、实验内容(1)设计二叉树结点数据结构,编程实现对用户输入的一组权值构造哈夫曼树(2)设计函数,先序遍历输出哈夫曼树各结点(3)设计函数,按树形输出哈夫曼树三、程序源代码#include <stdio.h>#include <string.h>#include <time.h>#include <stdlib.h>typedef struct Node{ //定义树结构int data;struct Node *leftchild;struct Node *rightchild;}Tree;typedef struct Data{ //定义字符及其对应的频率的结构int data;//字符对应的频率是随机产生的char c;};void Initiate(Tree **root);//初始化节点函数int getMin(struct Data a[],int n);//得到a中数值(频率)最小的数void toLength(char s[],int k);//设置有k个空格的串svoid set(struct Data a[],struct Data b[]);//初始化a,且将a备份至b char getC(int x,struct Data a[]);//得到a中频率为x对应的字符void prin(struct Data a[]);//输出初始化后的字符及对应的频率int n;void main(){//srand((unsigned)time(NULL));Tree *root=NULL,*left=NULL,*right=NULL,*p=NULL;int min,num;int k=30,j,m;struct Data a[100];struct Data b[100];int i;char s[100]={'\0'},s1[100]={'\0'}; char c;set(a,b);prin(a);Initiate(&root);Initiate(&left);Initiate(&right);Initiate(&p);//设置最底层的左节点min=getMin(a,n);left->data=min;left->leftchild=NULL;left->rightchild=NULL;//设置最底层的右节点min=getMin(a,n-1);right->data=min;right->leftchild=NULL;right->rightchild=NULL;root->data=left->data+right->data; Initiate(&root->leftchild);Initiate(&root->rightchild);//将设置好的左右节点插入到root中root->leftchild=left;root->rightchild=right;for(i=0;i<n-2;i++){min=getMin(a,n-2-i);Initiate(&left);Initiate(&right);if(min<root->data)//权值小的作为左节点{left->data=min;left->leftchild=NULL;left->rightchild=NULL;p->data=min+root->data;Initiate(&p->leftchild);Initiate(&p->rightchild);p->leftchild=left;p->rightchild=root;root=p;}else{right->data=min;right->leftchild=NULL;right->rightchild=NULL;p->data=min+root->data;Initiate(&p->leftchild);Initiate(&p->rightchild);p->leftchild=root;p->rightchild=right;root=p;}Initiate(&p);}num=n-1;p=root;printf("哈夫曼树如下图:\n");while(num){if(num==n-1){for(j=0;j<k-3;j++)printf(" ");printf("%d\n",root->data);}for(j=0;j<k-4;j++)printf(" ");printf("/ \\\n");for(j=0;j<k-5;j++)printf(" ");printf("%d",root->leftchild->data);printf(" %d\n",root->rightchild->data);if(root->leftchild->leftchild!=NULL){root=root->leftchild;k=k-2;}else{root=root->rightchild;k=k+3;}num--;}num=n-1;Initiate(&root);root=p;printf("各字符对应的编码如下:\n");while(num){if(root->leftchild->leftchild==NULL){strcpy(s1,s);m=root->leftchild->data;c=getC(m,b);printf("%c 【%d】:%s\n",c,m,strcat(s1,"0"));}if(root->rightchild->leftchild==NULL){strcpy(s1,s);m=root->rightchild->data;c=getC(m,b);printf("%c 【%d】:%s\n",c,m,strcat(s1,"1"));}if(root->leftchild->leftchild!=NULL){strcat(s,"0");root=root->leftchild;}if(root->rightchild->leftchild!=NULL){strcat(s,"1");root=root->rightchild;}num--;}}int getMin(struct Data a[],int n){int i,t;for(i=1;i<n;i++){if(a[i].data<a[0].data){t=a[i].data;a[i].data=a[0].data;a[0].data=t;}}t=a[0].data;for(i=0;i<n-1;i++){a[i]=a[i+1];}return t;}void toLength(char s[],int k){int i=0;for(;i<k;i++)strcat(s," ");}void Initiate(Tree **root){*root=(Tree *)malloc(sizeof(Tree));(*root)->leftchild=NULL;(*root)->rightchild=NULL;}void set(struct Data a[],struct Data b[]) {int i;srand((unsigned)time(NULL));n=rand()%10+2;for(i=0;i<n;i++){a[i].data=rand()%100+1;a[i].c=i+97;b[i].data=a[i].data;b[i].c=a[i].c;if(i>=0&&a[i].data==a[i-1].data)i--;}}char getC(int x,struct Data b[]){int i;for(i=0;i<n;i++){if(b[i].data==x){break;}}return b[i].c;}void prin(struct Data a[]){int i;printf("字符\t出现的频率\n");for(i=0;i<n;i++){printf("%c\t %d\n",a[i].c,a[i].data);}}四、程序运行结果演示五、实验体会哈夫曼编码算法:每次将集合中两个权值最小的二叉树合并成一棵新二叉树,n-1次合并后,成为最终的一棵哈夫曼树。

这既是贪心法的思想:从某一个最初状态出发,根据当前的局部最优策略,以满足约束方程为条件,以使目标函数最快(或最慢)为原则,在候选集合中进行一系列的选择,以便尽快构成问题的可行解。

每次选择两个权值最小的二叉树时,规定了较小的为左子树。

相关文档
最新文档