哈夫曼树的创建和操作

来源:互联网 发布:淘宝女鞋品牌 编辑:程序博客网 时间:2024/06/02 05:54

哈夫曼树的引进是与带有权重的二叉树有关的
首先定义带权路径长度(WPL):设二叉树有n个叶子结点,每个叶子结点带有权值Wk,从根结点到每个叶子的长度为Ik,则每个叶子结点的带权路径长度之和就是:WPL=nk=1wklk
最优二叉树哈夫曼树:WPL最小的二叉树

哈夫曼树

那么如何创建一棵哈夫曼树呢,哈夫曼提出了一种方法,就是每次把权值最小的两棵二叉树合并,例如下图所示

Huffman树的例子

这就可以用到堆,每次把新生成的树插入进堆,然后弹出两个树依次就是最小的树,揭下来就是具体的实现了,首先是把之前的最小堆改为最大堆,然后把Elements的类型改掉,最后是写Huffman树

#include <stdio.h>    #include <stdlib.h>    #define MinData -1000;#define ERROR -1; /* 错误标识应根据具体情况定义为堆中不可能出现的元素值 */  struct TreeNode{    int Weight;    TreeNode *Left;    TreeNode *Right;};typedef struct TreeNode *HuffmanTree;  typedef HuffmanTree ElementType;   struct HeapStruct{        ElementType *Elements;//储存堆元素的数组        int Size;//堆的当前元素个数      int Capacity;//堆的最大容量  };typedef struct HeapStruct *MinHeap;  //创建容量为MinSize的空的最小堆  MinHeap Create(int MinSize);  //判断最小堆是否已满  int IsFull(MinHeap H);  //最小堆的插入  void Insert(MinHeap &H,ElementType item);  //判断最小堆是否为空  int IsEmpty(MinHeap H);  //从堆中删除一个元素  ElementType DeleteMin(MinHeap H);  //建造最小堆void PercDown( MinHeap H, int p );  void BuildHeap( MinHeap H );  //打印堆中元素  void Print(MinHeap H);//创建Huffman树HuffmanTree Huffman(MinHeap H);//遍历树 void preOrder(HuffmanTree t);  //先序遍历    void intOrder(HuffmanTree t);  //中序遍历     void postOrder(HuffmanTree t);  //后序遍历    int main(){       MinHeap H= Create(15);      int a[]={1,2,3,4,5};      int len=sizeof(a)/sizeof(int);      H->Size=len;      for(int i=0;i<len;i++)          H->Elements[i+1]->Weight=a[i];    Print(H);      HuffmanTree T;    T=Huffman(H);    printf("前序遍历:");     preOrder(T) ;     printf("\n");     printf("中序遍历:");     intOrder(T);     printf("\n");     printf("后序遍历:");       postOrder(T);       printf("\n");       system("pause");  }  //创建容量为MinSize的空的最小堆  MinHeap Create(int MinSize){      MinHeap H=(MinHeap)malloc(sizeof(struct HeapStruct));      H->Elements=(ElementType *)malloc((MinSize+1)*sizeof(ElementType));//从小标为1的地方开始存放    //for(int i=0;i<=MinSize;i++)        //H->Elements[i]=(HuffmanTree)malloc(sizeof(TreeNode));    for(int i=0;i<=MinSize;i++)    {        H->Elements[i]=(ElementType )malloc(sizeof(ElementType));//从小标为1的地方开始存放        H->Elements[i]->Weight=0;//定义“哨兵”为大于堆中所有可能元素的值,便于以后更快操作        H->Elements[i]->Left=NULL;        H->Elements[i]->Right=NULL;    }    H->Size=0;      H->Capacity=MinSize;      H->Elements[0]->Weight=MinData;//定义“哨兵”为大于堆中所有可能元素的值,便于以后更快操作      return H;      //时间复杂性是O(logN)  };  //判断最小堆是否已满  int IsFull(MinHeap H){      return(H->Size==H->Capacity);  };  //最小堆的插入  void Insert(MinHeap &H,ElementType item)  {//将元素item插入最小堆H,其中H->Elements[0]已经定义为哨兵      int i;      if(IsFull(H)){        printf("最小堆已满\n");        return;    }    i=++H->Size;//先Size自加1再赋给i,i指向插入后堆中的最后一个元素      for(;H->Elements[i/2]->Weight>item->Weight;i/=2)          H->Elements[i]=H->Elements[i/2];//向下过滤结点      //哨兵的作用就是避免插入的值比Elements[0]还小      H->Elements[i]=item;//将item插入,运行速度比交换快      //时间复杂性是O(logN)  };  //判断最小堆是否为空  int IsEmpty(MinHeap H){      return(H->Size==0);   };  //从堆中删除一个元素  ElementType DeleteMin(MinHeap H){//从最小堆H中取出键值最小的元素,并删除一个结点      int Parent,Child;      ElementType MinItem,temp;      if(IsEmpty(H)){          printf("最小堆已为空\n");          return NULL;      }      MinItem=H->Elements[1];//取出根节点(最小值)      //用最小堆中的最后一个元素从根节点开始向上过滤下层结点      temp=H->Elements[H->Size--];      for(Parent=1;Parent*2<=H->Size;Parent=Child){          Child=Parent*2;          if((Child!=H->Size)&&(H->Elements[Child]->Weight>H->Elements[Child+1]->Weight))              Child++;//Child指向左右子结点中较小的          if(temp->Weight<=H->Elements[Child]->Weight)break;          else//移动temp到下一层              H->Elements[Parent]=H->Elements[Child];      }      H->Elements[Parent]=temp;      return MinItem;  }  /*----------- 建造最小堆 -----------*/  void PercDown( MinHeap H, int p )  { /* 下滤:将H中以H->Data[p]为根的子堆调整为最小堆 */      int Parent, Child;      ElementType X= H->Elements[p]; /* 取出根结点存放的值 */      for( Parent=p; Parent*2<=H->Size; Parent=Child ) {          Child = Parent * 2;          if( (Child!=H->Size) && (H->Elements[Child]->Weight>H->Elements[Child+1]->Weight) )              Child++;  /* Child指向左右子结点的较小者 */          if( X->Weight <= H->Elements[Child]->Weight ) break; /* 找到了合适位置 */          else  /* 下滤X */              H->Elements[Parent] = H->Elements[Child];      }      H->Elements[Parent] = X;  }  void BuildHeap( MinHeap H )  { /* 调整H->Data[]中的元素,使满足最小堆的有序性  */    /* 这里假设所有H->Size个元素已经存在H->Data[]中 */      int i;      /* 从最后一个结点的父节点开始,到根结点1 */      for( i = H->Size/2; i>0; i-- )          PercDown( H, i );  }  //打印堆中元素  void Print(MinHeap H){      printf("H中的元素为:\n");      for(int i=1;i<=H->Size;i++)          printf("%d ",H->Elements[i]->Weight);      printf("\n");  }//创建Huffman树HuffmanTree Huffman(MinHeap H){    //假设H->Size个权值已经存在H->Elements[]->Weight里    int i;HuffmanTree T;    BuildHeap(H);//将堆调整为最小堆    int len=H->Size;    for(i=1;i<len;i++){//做H->Size-1次合并        T=(HuffmanTree)malloc(sizeof(struct TreeNode));//建立新结点        T->Left=DeleteMin(H);        T->Right=DeleteMin(H);        T->Weight=T->Left->Weight+T->Right->Weight;        Insert(H,T);    }    T=DeleteMin(H);    return T;};//遍历树 void preOrder(HuffmanTree t)  //先序遍历    {         if(t)         {               printf("%d ",t->Weight);             preOrder(t->Left);             preOrder(t->Right);         }     }     void intOrder(HuffmanTree t)  //中序遍历    {        if(t)         {            intOrder(t->Left);            printf("%d ",t->Weight);            intOrder(t->Right);         }     }     void postOrder(HuffmanTree t)  //后序遍历     {         if(t)         {                postOrder(t->Left);             postOrder(t->Right);            printf("%d ",t->Weight);         }     }  

重点有这么两个地方

MinHeap Create(int MinSize){      MinHeap H=(MinHeap)malloc(sizeof(struct HeapStruct));      H->Elements=(ElementType *)malloc((MinSize+1)*sizeof(ElementType));//从小标为1的地方开始存放    //for(int i=0;i<=MinSize;i++)        //H->Elements[i]=(HuffmanTree)malloc(sizeof(TreeNode));    for(int i=0;i<=MinSize;i++)    {        H->Elements[i]=(ElementType )malloc(sizeof(ElementType));//从小标为1的地方开始存放        H->Elements[i]->Weight=0;//定义“哨兵”为大于堆中所有可能元素的值,便于以后更快操作        H->Elements[i]->Left=NULL;        H->Elements[i]->Right=NULL;    }    H->Size=0;      H->Capacity=MinSize;      H->Elements[0]->Weight=MinData;//定义“哨兵”为大于堆中所有可能元素的值,便于以后更快操作      return H;      //时间复杂性是O(logN)  }; 

一个是这里创建时的malloc竟然有三次。。还是请同学帮我解决的

另外一个是下面Huffman树的生成函数

HuffmanTree Huffman(MinHeap H){    //假设H->Size个权值已经存在H->Elements[]->Weight里    int i;HuffmanTree T;    BuildHeap(H);//将堆调整为最小堆    int len=H->Size;    for(i=1;i<len;i++){//做H->Size-1次合并        T=(HuffmanTree)malloc(sizeof(struct TreeNode));//建立新结点        T->Left=DeleteMin(H);        T->Right=DeleteMin(H);        T->Weight=T->Left->Weight+T->Right->Weight;        Insert(H,T);    }    T=DeleteMin(H);    return T;};

下面是实现效果
这里写图片描述

最后附上一段小代码

//整数转化为树之后再插入void Insertint(MinHeap &H,int item){    int i;    if(IsFull(H)){        printf("最小堆已满\n");        return;    }    i=++H->Size;//先Size自加1再赋给i,i指向插入后堆中的最后一个元素    ElementType E1=(ElementType )malloc(sizeof(ElementType));    E1->Right=E1->Left=NULL;    E1->Weight=item;    for(;H->Elements[i/2]->Weight>E1->Weight;i/=2)          H->Elements[i]=H->Elements[i/2];//向下过滤结点      //哨兵的作用就是避免插入的值比Elements[0]还小      H->Elements[i]=E1;//将item插入,运行速度比交换快      //时间复杂性是O(logN)  }; 

这样就可以调用

  MinHeap H= Create(15);    Insertint(H,55);      Insertint(H,79);      Insertint(H,66);      Insertint(H,83);      Insertint(H,72);      Insertint(H,30);      Insertint(H,49);      Insertint(H,91);      Insertint(H,87);      Insertint(H,43);      Insertint(H,9);      Insertint(H,38);      Print(H);      DeleteMin(H);      DeleteMin(H);      Print(H);  

等语句,哦耶终于完成啦^^

2 0
原创粉丝点击