哈夫曼树的实现

来源:互联网 发布:手机变脸软件 编辑:程序博客网 时间:2024/06/05 05:00

BinaryTree.h

#pragma once#pragma once  #include<iostream>  using namespace std;  template<class T>  struct BTNode {      BTNode() { lchild = rchild = NULL; }      BTNode(const T& x){          element = x;          lchild = rchild = NULL;      }      BTNode(const T& x, BTNode<T>* l, BTNode<T>* r) {          element = x;          lchild = l;          rchild = r;      }      T element;      BTNode<T>* lchild, *rchild;  };    template<class T>  class BinaryTree {  public:      BinaryTree() { root = NULL; }       ~BinaryTree();      bool IsEmpty()const;      void Clear();//移去所有结点,使其成为空树      bool Root(T& x)const;//若二叉树非空,则x为根的值,并返回true,否则返回false      void MakeTree(const T& x, BinaryTree<T>& left, BinaryTree<T>& right);//构造一棵二叉树,根的值为x,以left和right为左右子树      void BreakTree(T& x, BinaryTree<T>& left, BinaryTree<T>& right);//拆分二叉树为三部分,x为根的值,left和right分别为左右子树      //---------------------(华丽分割线)----------------------      void PreOrder(void (*Visit)(T& x));//使用函数Visit访问结点,先序遍历二叉树      void InOrder(void (*Visit)(T& x));//中序遍历二叉树      void PostOrder(void (*Visit)(T& x));//后序遍历二叉树      //---------------------(华丽分割线)----------------------      //分割线内的函数面向用户,主要提供一个用户与类内递归循环的一个接口  protected:      BTNode<T>* root;//指向根结点的指针  private:      void Clear(BTNode<T>* &t);      //---------------------(华丽分割线)----------------------      void PreOrder(void (*Visit)(T& x),BTNode<T>*t);      void InOrder(void (*Visit)(T& x), BTNode<T>*t);      void PostOrder(void (*Visit)(T& x), BTNode<T>*t);      //---------------------(华丽分割线)----------------------      //分割线内的函数才是主要实现递归遍历算法的函数  };  template<class T>  BinaryTree<T>::~BinaryTree() {      Clear();  };  template<class T>  bool BinaryTree<T>::IsEmpty()const {      return (root == NULL) ? true : false;  };  template<class T>  void BinaryTree<T>::Clear() {      Clear(root);  };  template<class T>  void BinaryTree<T>::Clear(BTNode<T>*&t=root) {      if (p!= NULL) {          Clear(p->lchild);          Clear(p->rchild);          delete p;      }  };  template<class T>  bool BinaryTree<T>::Root(T& x)const {      if (root == NULL)return false;      else {          x = root.element;          return true;      }      return false;  };  template<class T>  void BinaryTree<T>::MakeTree(const T& x, BinaryTree<T>& left, BinaryTree<T>& right) {      if (root || &left == &right)return;//若root非空,说明root已是某二叉树树根      root = new BTNode<T>(x,left.root,right.root);      left.root = right.root = NULL;//left和right已与新树结合,故将其指针设为空  };  template<class T>  void BinaryTree<T>::BreakTree(T& x, BinaryTree<T>& left, BinaryTree<T>& right) {      if (!root || &left == &right || left.root || right.root)return;      //如果实参left和right的root非空则说明用户传过来用于获取左右子树的的BTNode指针是某个树的结点      x == root->element;      left.root = root->lchild; right.root = root->rchild;      delete root;      root = NULL;  };  //先序遍历,面向用户  template<class T>  void BinaryTree<T>::PreOrder(void(*Visit)(T& x)) {      PreOrder(Visit, root);  };  //先序遍历,真正实现的函数  template<class T>  void BinaryTree<T>::PreOrder(void(*Visit)(T& x), BTNode<T>* t) {      if (t) {          Visit(t->element);          PreOrder(Visit, t->lchild);          PreOrder(Visit, t->rchild);      }  };      template<class T>  void Visit(T& x) {      cout << x << " ";  };      //中序遍历,面向用户  template<class T>  void BinaryTree<T>::InOrder(void(*Visit)(T& x)) {      InOrder(Visit, root);  };  //中序遍历,真正实现的函数  template<class T>  void BinaryTree<T>::InOrder(void(*Visit)(T& x),BTNode<T>*t) {      if (t) {          InOrder(Visit, t->lchild);          Visit(t->element);          InOrder(Visit, t->rchild);      }  };    //后序遍历,面向用户  template<class T>  void BinaryTree<T>::PostOrder(void(*Visit)(T& x)) {      InOrder(Visit, root);  };  //后序遍历,真正实现的函数  template<class T>  void BinaryTree<T>::PostOrder(void(*Visit)(T& x),BTNode<T>*t) {      if (t) {          PostOrder(Visit, t->lchild);          PostOrder(Visit, t->rchild);          Visit(t->element);      }  };
PrioQueue.h

#pragma once/*优先权队列是多个元素的集合,每个元素都有一个优先权。优先权队列的特点是:每次从队列中取出具有最高优先权的元素ADT PrioQueue{Data:n个元素的最小堆Operation:Create();//建立一个空队列Destroy();//撤销一个队列IsEmpty();//空则返回true,非空则falseIsFull();//满则true,非满则falseAppend(x);//元素值为x的新元素入队Serve(x);//将该队列中具有最小优先权的元素值返回给x,并从优先权队列中删除该元素}*/template<class T>class PrioQueue{public:PrioQueue(int mSize = 20) {maxSize = mSize;q = new T[maxSize];}~PrioQueue() { delete[]q; }bool IsEmpty() const{return n == 0;}bool IsFull() {return n == maxSize;}void Append(const T&x);void Serve(T& x);private:void AdjustDown(int r, int j);void AdjustUp(int j);T*q;int n, maxSize;};template<class T>void PrioQueue<T>::AdjustDown(int r, int j){int child = 2*r + 1;//child定位到r的左子位置T temp = q[r];while (child <= j) {if ((child < j) && (q[child] > q[child + 1]))child++;//找到左右子中最小的那一个if (temp <= q[child])break;//如果temp比左右子最小的都小,说明符合向下调整的规则q[(child - 1) / 2] == q[child];//将该子值赋给其父结点child = 2 * child + 1;//继续向下(跳到该节点的子节点)}q[(child - 1) / 2] = temp;//temp的位置}template<class T>void PrioQueue<T>::AdjustUp(int j){//j为新插入元素的位置+1int i = j; T temp = q[i];while (i > 0 && temp < q[(i - 1) / 2]) {q[i] = q[(i - 1) / 2];//父子交换i = (i - 1) / 2;//跳到该节点的父位置}q[i] = temp;//i即为temp最后合理的位置}//因为插入新元素之前堆中元素都已经满足最小堆的条件//故只需调整新元素影响到的节点即可template<class T>void PrioQueue<T>::Append(const T&x) {if (IsFull())throw Overflow;q[n++] = x;//将新元素插入完全二叉树的最后位置AdjustUp(n - 1);//新元素插入位置即为n-1,故用AdjustUp调整0~n-1;}template<class T>void PrioQueue<T>::Serve(T& x) {if (IsEmpty())throw Underflow;x = q[0]; //返回具有最低优先权的元素(即堆顶元素)q[0] = q[--n];//然后将堆底元素放到堆顶AdjustDown(0, n - 1);//向下调整}

HfmTree.h

#pragma once#include"BinaryTree.h"#include"PrioQueue.h"template<class T>class HfmTree :public BinaryTree<T> {public :HfmTree<T>CreateHfmTree(T w[], int n);operator T()const { return weight; }T getW() { return weight; }void putW(const T& x) { weight = x; }//设置权重setNull() { root = NULL; }private:T weight;};template<class T>HfmTree<T> HfmTree<T>::CreateHfmTree(T w[], int n) {PrioQueue<HfmTree<T>>pq(n);//pq是一个优先权队列,他的元素是哈夫曼树对象HfmTree<T>x, y, z, zero;//----------------------第一个for循环--------------for (int i = 0; i < n; i++) {z.MakeTree(w[i], x, y);z.putW(w[i]);//构造一个数中只有一个结点的哈夫曼树对象pq.Append(z);//将哈夫曼树对象放进优先权队列z.setNull();//将z置为空数}//将w数组中的每一个元素当作一个哈夫曼树的权值构造一//个只有一个结点的哈夫曼树,pq//压进优先权队列pq//----------------------第一个for循环--------------//----------------------第二个for循环--------------for (int i = 1; i < n; i++) {pq.Serve(x);//取出最小值pq.Serve(y);//取出次最小值z.MakeTree(x.getW() + y.getW(), x, y);//分别将该次取出的最小值和次最小值当作左、右子//构造一个新的哈夫曼树对象z.putW(x.getW() + y.getW());pq.Append(z);z.setNull();}//对优先权队列pq中的元素(即哈夫曼树对象)进行合并n-1次//则最后剩一个完整的即构造完成的哈夫曼树//----------------------第二个for循环--------------pq.Serve(z);return z;}


0 0
原创粉丝点击