《数据结构与算法》第四次(下) 霍夫曼树哈夫曼编码

《数据结构与算法》第四次

二叉树的创建、销毁、插入、删除、遍历等操作的实现(下)

实验目的:

  1. 掌握二叉树的存储结构和相关算法。
  2. 掌握哈夫曼树的构建和哈夫曼编码的算法。

实验内容:

建立一个霍夫曼树,并输出编码表。

实验步骤:

1.参考代码,建立完整的霍夫曼树

2.并输出这课霍夫曼树的编码表。

参考提示:

1.在bianryTreeNode的声明里增加一个string类型的变量code,用来存储binaryTreeNode类型结点的霍夫曼编码。

 

2.编写一个输出霍夫曼编码表的函数在主函数里调用,可以采用一边深度遍历已经建立好的霍夫曼树,一边维护code变量的方法实现霍夫曼编码并输出。

3.主函数可以为以下形式


输出霍夫曼编码需要访问二叉树根节点,但是root变量是私有成员,所以需要在里新定义个获取根节点的成员函数(如下图)

 

函数的实现如下图所示。

江米条想说的(简单快速记忆):

哈夫曼编码应用广泛,JPEG中就应用了哈夫曼编码。 那么什么是哈夫曼树呢?哈夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。

最优二叉树,简单吧。就是每次从数据里面拿出最小的两个数,求和,然后把这个数和剩下的数里面再挑最小的两个,再求和。

以此类推。生成的树就是路径长度最短的最优二叉树。它是一颗大根堆的树。

那我为什么要用在这个程序里面用minHeap.h(小根堆)呢,因为我要每次都寻找最小的两个数呀,所以每次加完了就把得到的结果插入小根堆中。不用担心插入的数据出错,如果担心的话,可以看小根堆插入数据的算法。

最后输出的霍夫曼编码就是从上到下走过的路径的编码,每往左走一次,多记一个0;往右走一次多记一个1。

顺序千万不能错,小根堆的数据插入是有规矩的,插入数据之后,需要调整位置再次成为小根堆,合成的数据和集合里面的数据不能乱提出来,否则霍夫曼编码的01的位置会出错!可以看看下图,每次插入数据的时候,小根堆是怎样维护,使它永远是小根堆的。

附加代码(小根堆插入数据时候的排序问题):

template<class T>
void minHeap<T>::push(const T& theElement)
{
   
   if (heapSize == arrayLength - 1)//大小不够的话,就将数组扩大一倍
   {
      changeLength1D(heap, arrayLength, 2 * arrayLength);
      arrayLength *= 2;
   }

   
   int currentNode = ++heapSize;
   while (currentNode != 1 && heap[currentNode / 2] > theElement)
   {
     
      heap[currentNode] = heap[currentNode / 2]; // 
      currentNode /= 2;                          // 元素移动到它的父母那里
   }

   heap[currentNode] = theElement;
}

附霍夫曼编码图:

A对应的编码:11

B对应的编码:10

C对应的编码:00

D对应的编码:011

E对应的编码:010

实验代码:

// Huffman tree

#include <iostream>
#include "minHeap.h"
#include"binaryTreeNode.h"
#include "linkedBinaryTree.h"
#include "huffmanNode.h"
#include<cstring>

using namespace std;

template <class T>
linkedBinaryTree<int>* huffmanTree(T weight[], int n)
{// Generate Huffman tree with weights weight[1:n], n >= 1.
   // create an array of single node trees
   huffmanNode<T> *hNode = new huffmanNode<T> [n + 1];
   linkedBinaryTree<int> emptyTree;
   for (int i = 1; i <= n; i++)
   {
      hNode[i].weight = weight[i];
      hNode[i].tree = new linkedBinaryTree<int>;
      hNode[i].tree->makeTree(i, emptyTree, emptyTree);
   }

   // make node array into a min heap
   minHeap<huffmanNode<T> > heap(1);
   heap.initialize(hNode, n);

   // repeatedly combine trees from min heap
   // until only one tree remains
   huffmanNode<T> w, x, y;
   linkedBinaryTree<int> *z;
   for (int i = 1; i < n; i++)
   {
      // remove two lightest trees from the min heap
      x = heap.top(); heap.pop();
      y = heap.top(); heap.pop();

      // combine into a single tree
      z = new linkedBinaryTree<int>;
      z->makeTree(0, *x.tree, *y.tree);
      w.weight = x.weight + y.weight;
      w.tree = z;
      heap.push(w);
      delete x.tree;
      delete y.tree;
   }

   // destructor for min heap deletes hNode
   return heap.top().tree;
}

template<class T>
void setHuffmanCode(binaryTreeNode<T>*t)
{
	if (t->leftChild != NULL)
	{
		t->leftChild->code = t->code;
		t->leftChild->code.append("0");//往左走的路线是0
	}
	if (t->rightChild != NULL)
	{
		t->rightChild->code = t->code;
		t->rightChild->code.append("1");//往右走的路线是1
	}
}

template<class T>
void output(binaryTreeNode<T>*t)
{
	if (t->leftChild == NULL&&t->rightChild == NULL)
		cout << "节点" << t->element << "的霍夫曼编码为" << t->code << endl;
}

template<class E>
void huffmanCode(linkedBinaryTree<E>*h)
{
	h->preOrder(setHuffmanCode);
	h->preOrder(output);
}

int main(void)
{
   int a[11];
   int n = 10;
   for (int i = 1; i <= n; i++)
      a[i] = 2 * i;
   linkedBinaryTree<int> *x = huffmanTree(a, n);
   huffmanCode(x);
   return 0;
}

代码链接:

如有问题,请联系我 QQ:1239825268

备注 CSDN

共勉!

猜你喜欢

转载自blog.csdn.net/lzjstudy/article/details/81156392
今日推荐