zoukankan      html  css  js  c++  java
  • 堆与优先队列、哈夫曼树(贪心算法)

      一、哈夫曼树最优二叉树,WPL最小的二叉树 

      带权路径长度(WPL):

      设二叉树有n个叶子结点,每个叶子结点带 有权值 wk,从根结点到每个叶子结点的长度为 lk,则每个叶子结点的带权路径长度之和WPL

      哈夫曼树的特点: 

      1、没有度为1的结点

      2、哈夫曼树的任意非叶节点的左右子树交换后仍是哈夫曼树

      3、n个叶子结点的哈夫曼树共有2n-1个结点(由没有度为1的结点推出, n0+n1+n2 = 2*n0-1)

      4、对同一组权值{w1 ,w2 , …… , wn},存在不同构的两棵哈夫曼树;

      5、外部结点的个数比内部结点的个数多一;

      二、堆的两个特性

    结构性:用数组表示的完全二叉树; 

    有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)

    (堆的结点的子结点之间没有关系)

      1、堆的操作

      1 typedef struct HNode *Heap; /* 堆的类型定义 */
      2 struct HNode {
      3     ElementType *Data; /* 存储元素的数组 */
      4     int Size;          /* 堆中当前元素个数 */
      5     int Capacity;      /* 堆的最大容量 */
      6 };
      7 typedef Heap MaxHeap; /* 最大堆 */
      8 typedef Heap MinHeap; /* 最小堆 */
      9  
     10 #define MAXDATA 1000  /* 该值应根据具体情况定义为大于堆中所有可能元素的值 */
     11  
     12 MaxHeap CreateHeap( int MaxSize )
     13 { /* 创建容量为MaxSize的空的最大堆 */
     14  
     15     MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode));
     16     H->Data = (ElementType *)malloc((MaxSize+1)*sizeof(ElementType));
     17     H->Size = 0;
     18     H->Capacity = MaxSize;
     19     H->Data[0] = MAXDATA; /* 定义"哨兵"为大于堆中所有可能元素的值*/
     20  
     21     return H;
     22 }
     23  
     24 bool IsFull( MaxHeap H )
     25 {
     26     return (H->Size == H->Capacity);
     27 }
     28  
     29 bool Insert( MaxHeap H, ElementType X )
     30 { /* 将元素X插入最大堆H,其中H->Data[0]已经定义为哨兵 */
     31     int i;
     32   
     33     if ( IsFull(H) ) { 
     34         printf("最大堆已满");
     35         return false;
     36     }
     37     i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */
     38     for ( ; H->Data[i/2] < X; i/=2 )
     39         H->Data[i] = H->Data[i/2]; /* 上滤X */
     40     H->Data[i] = X; /* 将X插入 */
     41     return true;
     42 }
     43  
     44 #define ERROR -1 /* 错误标识应根据具体情况定义为堆中不可能出现的元素值 */
     45  
     46 bool IsEmpty( MaxHeap H )
     47 {
     48     return (H->Size == 0);
     49 }
     50  
     51 ElementType DeleteMax( MaxHeap H )
     52 { /* 从最大堆H中取出键值为最大的元素,并删除一个结点 */
     53     int Parent, Child;
     54     ElementType MaxItem, X;
     55  
     56     if ( IsEmpty(H) ) {
     57         printf("最大堆已为空");
     58         return ERROR;
     59     }
     60  
     61     MaxItem = H->Data[1]; /* 取出根结点存放的最大值 */
     62     /* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */
     63     X = H->Data[H->Size--]; /* 注意当前堆的规模要减小 */
     64     for( Parent=1; Parent*2<=H->Size; Parent=Child ) {
     65         Child = Parent * 2;
     66         if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) )
     67             Child++;  /* Child指向左右子结点的较大者 */
     68         if( X >= H->Data[Child] ) break; /* 找到了合适位置 */
     69         else  /* 下滤X */
     70             H->Data[Parent] = H->Data[Child];
     71     }
     72     H->Data[Parent] = X;
     73  
     74     return MaxItem;
     75 } 
     76  
     77 /*----------- 建造最大堆 -----------*/
     78 void PercDown( MaxHeap H, int p )
     79 { /* 下滤:将H中以H->Data[p]为根的子堆调整为最大堆 */
     80     int Parent, Child;
     81     ElementType X;
     82  
     83     X = H->Data[p]; /* 取出根结点存放的值 */
     84     for( Parent=p; Parent*2<=H->Size; Parent=Child ) {
     85         Child = Parent * 2;
     86         if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) )
     87             Child++;  /* Child指向左右子结点的较大者 */
     88         if( X >= H->Data[Child] ) break; /* 找到了合适位置 */
     89         else  /* 下滤X */
     90             H->Data[Parent] = H->Data[Child];
     91     }
     92     H->Data[Parent] = X;
     93 }
     94  
     95 void BuildHeap( MaxHeap H )
     96 { /* 调整H->Data[]中的元素,使满足最大堆的有序性  */
     97   /* 这里假设所有H->Size个元素已经存在H->Data[]中 */
     98  
     99     int i;
    100  
    101     /* 从最后一个结点的父节点开始,到根结点1 */
    102     for( i = H->Size/2; i>0; i-- )
    103         PercDown( H, i );
    104 }
    堆的操作,c代码

      2、堆的操作实例

    堆的路径,将一系列给定数字插入一个初始为空的小顶堆H[]。

    随后对任意给 定的下标`i`,打印从H[i]到根结点的路径。

      

     1 #include <stdio.h>
     2 /* 1.定义堆H */
     3 #define MAXN 1001
     4 #define MINH -10001
     5 int H[MAXN], size;//堆,堆的大小
     6 /* 2.堆的初始化 */
     7 void Create ()
     8 {
     9     size = 0;
    10     H[0] = MINH;/*设置“岗哨”*/    
    11 }
    12 /* 3.堆插入 */
    13 void Insert ( int X )
    14 {
    15     /* 省略检查堆是否已满 */
    16     int i; //46 23 26 24 10
    17     /* 
    18         下标从1开始,逐个插入,
    19         插入过程,从后向前,逐个与其父结点比较
    20         父结点大, 上滤X
    21         1  2  3  4  5 
    22         46               <-46  1/2==0  0
    23         23 46            <-23  2/2==1  1 0
    24         23 46 26         <-26  3/2==1  1 0
    25         23 24 26 46      <-24  4/2==2  2 1 0
    26         10 23 26 46 24   <-10  5/2==2  2 1 0
    27     */
    28     for (i=++size; H[i/2] > X; i/=2)
    29         H[i] = H[i/2];
    30     H[i] = X;//将X插入H
    31 }
    32 
    33 int main()
    34 {    
    35 /* 
    36     读入n和m
    37     根据输入序列建堆
    38     对m个要求:打印到根的路径
    39     5 3
    40     46 23 26 24 10
    41     5 4 3
    42  */    
    43     int n, m, x, i, j;
    44     scanf("%d%d", &n, &m);
    45     Create(); /* 堆初始化 */
    46     for (i=0; i<n; i++) { 
    47         scanf("%d", &x);
    48         Insert(x); /*以逐个插入方式建堆 */
    49     }
    50     
    51     /* for(int i=1; i<=n; ++i)
    52         printf("%3d",H[i]); */
    53     
    54     /* m个结点 */
    55     for (i=0; i<m; i++) 
    56     {
    57         scanf("%d", &j);//具体结点
    58         printf("%d", H[j]);
    59          /*向根方向输出各结点*/
    60         while (j>1) {
    61             j /= 2;
    62             printf(" %d", H[j]);
    63         }
    64         printf("
    ");
    65     }
    66     return 0;
    67 }
    最小堆,插入建堆

      三、C++  根据给定的权值创建,哈夫曼树  (用到优先队列,贪心算法,青岛大学mooc)

     1 #include <iostream>
     2 #include <vector>
     3 #include <queue>
     4 using namespace std;
     5 struct Node{
     6     int data;
     7     Node* left;
     8     Node* right;
     9     Node(){ left = right= NULL;}
    10     Node(int data){
    11         this->data = data;
    12         left = right = NULL;
    13     }
    14 };
    15 struct HuffmanTree{
    16     Node* root;
    17     HuffmanTree(){root = NULL;}
    18     HuffmanTree(int weight){
    19         root = new Node(weight);        
    20     }
    21     HuffmanTree(vector<HuffmanTree> &nodes){
    22         priority_queue<HuffmanTree, vector<HuffmanTree>, 
    23             greater<HuffmanTree>> q(nodes.begin(),nodes.end());
    24         HuffmanTree tmp;
    25         for(int i=1; i<nodes.size();++i){
    26             tmp.root =  new Node();
    27             tmp.root->left = q.top().root; q.pop();
    28             tmp.root->right = q.top().root; q.pop();
    29             tmp.root->data = tmp.root->left->data + tmp.root->right->data;
    30             q.push(tmp);
    31         }
    32         root = q.top().root;
    33     }
    34     bool operator > (const HuffmanTree &t) const{
    35         return this->root->data > t.root->data;
    36     }
    37     void print(){
    38         rprint(root,0);
    39     }
    40     void rprint(Node* r, int depth){
    41         for(int i=0; i<depth; ++i) cout<<"  ";
    42         if(!r) cout<<"[/]"<<endl;
    43         else{
    44             cout<<r->data<<endl;
    45             rprint(r->left, depth+1);
    46             rprint(r->right,depth+1);
    47         }
    48     }
    49 };
    50 
    51 int main()
    52 {
    53     int nv,weight;
    54     cin>>nv;
    55     vector<HuffmanTree> nodes;
    56     for(int i=0; i<nv; ++i){
    57         cin>>weight;
    58         nodes.emplace_back(weight);
    59     }
    60     HuffmanTree ht(nodes);
    61     ht.print();
    62     return 0;
    63 }
    64 /*
    65 7
    66 10 15 12 3 4 13 1 
    67  */
    哈夫曼树(贪心算法)
  • 相关阅读:
    php的源代码包构建一个空的php扩展。
    Web服务器上可能被包含或被请求的不同脚本源代码文件
    是否采用Sybase形式的自动字符串转义(用 '' 表示 ')
    数据库导入的大小是否要分段处理?
    Maven常用参数及其说明【转:http://blog.csdn.net/wangjunjun2008/article/details/18982089】
    bat常用命令,转【http://www.cnblogs.com/yplong/archive/2013/04/02/2996550.html】
    ftp链接、上传、下载、断开
    maven配置中国下载源【转:http://www.cnblogs.com/libingbin/p/5949483.html】
    经经经!!!!
    spring中quartz的使用。【转http://www.cnblogs.com/kay/archive/2007/11/02/947372.html】
  • 原文地址:https://www.cnblogs.com/GoldenEllipsis/p/11372513.html
Copyright © 2011-2022 走看看