哈夫曼树的创建和操作
来源:互联网 发布:淘宝女鞋品牌 编辑:程序博客网 时间:2024/06/02 05:54
哈夫曼树的引进是与带有权重的二叉树有关的
首先定义带权路径长度(WPL):设二叉树有n个叶子结点,每个叶子结点带有权值
最优二叉树或哈夫曼树:WPL最小的二叉树
那么如何创建一棵哈夫曼树呢,哈夫曼提出了一种方法,就是每次把权值最小的两棵二叉树合并,例如下图所示
这就可以用到堆,每次把新生成的树插入进堆,然后弹出两个树依次就是最小的树,揭下来就是具体的实现了,首先是把之前的最小堆改为最大堆,然后把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
- 哈夫曼树的创建和操作
- 数据库的创建和操作
- 二叉树的创建和操作
- 线性表的创建和操作
- 链表的创建和操作
- Oracle 数据库分区表的创建和操作
- 二叉排序树的创建,插入和 删除操作
- AVL树的创建和插入操作
- XML的创建和读写操作
- NSString 字符串的创建和操作
- 栈的创建和部分操作
- 简单堆的创建和操作
- 单向链表的创建和操作
- 6.1MATLAB数组的创建和操作
- Linux创建用户和用户组的操作
- 单链表的创建和常用操作
- KVM存储池的创建和操作
- 数据结构--双链表的创建和操作
- 【framework】EventLog分析
- Jsonp
- 8位数据越界处理
- 延时、丢包、抖动,用尽洪荒之力也传不到,该怎么办?
- 润乾报表jboss性能优化
- 哈夫曼树的创建和操作
- Robot Framework 的安装配置
- 跨域请求jsonp
- ads优化设置中优化方式random和gradient的选择
- 二叉搜索树与双向链表
- 哈夫曼树的基本构建与操作
- linux nginx安装配置 nginx1.6.2
- uva129 Krypton Factor
- Linux系统下安装MegaCli64工具查看和管理raid卡