zoukankan      html  css  js  c++  java
  • 计算机考研机试指南(六)——哈夫曼树

    机试指南 cha3 哈夫曼

    自己写了一版代码+数据结构书上的标准代码

      1 #include <iostream>
      2 #include <string.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 
      6 
      7 using namespace std;
      8 /*
      9 1. 哈夫曼编码-顺序存储方式
     10 2. 优先队列存储——堆存储
     11 */
     12 
     13 void huffmanTree(int huffman[][5],int n)
     14 {
     15 
     16     for (int i=0;i<n;i++)
     17     {
     18         huffman[i][0] = i;
     19         cin >> huffman[i][1];
     20         huffman[i][2] = -1;
     21         huffman[i][3] = -1;
     22         huffman[i][4] = -1;
     23     }
     24     int num1 = 0,num2 = 0;
     25     float min1 = 9999,min2 = 9999;
     26 
     27     for (int i=0;i<n-1;i++)
     28     {
     29         num1 = 0;
     30         num2 = 0;
     31         min1 = 9999;
     32         min2 = 9999;
     33         for (int j=0;j<n+i;j++)
     34         {
     35             // 找到一组数中未被排序(没有父节点)的的最小值和次小值,最小值优先判断,判断完最小值后判断次小值
     36             if (huffman[j][2] == -1 && huffman[j][1] < min1 )
     37             {
     38                     if (min1 < min2)
     39                 {
     40                     min2 = min1;
     41                     num2 = num1;
     42                 }
     43                 min1 = huffman[j][1];
     44                 num1 = j;
     45             }
     46             else if (huffman[j][2] == -1 && huffman[j][1] < min2)
     47             {
     48                 min2 = huffman[j][1];
     49                 num2 = j;
     50             }
     51         }
     52         huffman[n+i][0] = n+i;
     53         huffman[n+i][1] = huffman[num1][1]+huffman[num2][1];
     54         huffman[n+i][2] = -1;
     55         huffman[n+i][3] = num1;
     56         huffman[n+i][4] = num2;
     57         huffman[num1][2] = n+i;
     58         huffman[num2][2] = n+i;
     59 
     60     }
     61 }
     62 void printTree(int huffman[][5],int n)
     63 {
     64     for (int i=0;i<2*n-1;i++)
     65     {
     66         for (int j=0;j<5;j++)
     67             cout << huffman[i][j] << ' ';
     68         cout << endl;
     69     }
     70 }
     71 void huffmanCode(int huffman[][5],int n)
     72 {
     73     // 自顶向下法:找到根到所有孩子的路径,每条路径均对应一个孩子
     74     // 自底向上法:遍历每个叶子结点,往上寻找直到找到根为止
     75     char code[20];
     76     int q,parent;
     77     int j = 0;
     78     for (int i=0;i<n;i++)
     79     {
     80         q = i;
     81         parent = huffman[q][2];
     82         j = 0;
     83         while (parent!=-1)
     84         {
     85             if (huffman[parent][3] == q)
     86             {
     87                 // q是parent的左孩子
     88                 code[j] = '0';
     89             }
     90             if (huffman[parent][4] == q)
     91             {
     92                 code[j] = '1';
     93             }
     94             j++;
     95             q = parent;
     96             parent = huffman[q][2];
     97         }
     98         code[j]  = '';
     99         cout << huffman[i][1] << " : " << code << endl;
    100     }
    101 }
    102 char code[10];
    103 void printPath(int huffman[][5],int n,int root,int level)
    104 {
    105     // 打印从根节点到所有叶子结点的路径
    106     level ++;
    107     if (huffman[root][3] != -1 && huffman[root][4]!=-1)
    108     {
    109         // 如果root不为根节点时
    110         code[level] = '0';
    111         printPath(huffman,n,huffman[root][3],level);
    112         code[level] = '1';
    113         printPath(huffman,n,huffman[root][4],level);
    114     }
    115     else {
    116         code[level] = '';
    117         for (int i=1;i<=level;i++)
    118             cout << code[i];
    119         cout << ' ' << huffman[root][1] <<endl;
    120     }
    121 
    122 }
    123 
    124 // 课本上的代码方法,结构体数组封装一个结点而不是二维数组
    125 typedef struct HuffmanNode
    126 {
    127     int weight;
    128     int parent,lchild,rchild;
    129 }HuffmanNode,**HuffmanTree;
    130 
    131 typedef char ** HuffmanCode ; // 动态分配数组存储哈夫曼编码表
    132 
    133 
    134 void select_2(HuffmanTree t,int n,int &s1,int &s2)
    135 {
    136     int min1 = 9999,min2 = 9999;
    137     int num1=1,num2 = 1;
    138     for (int i=1;i<=n;i++)
    139     {
    140         if (t[i]->weight < min1)
    141         {
    142             if ( min2 > min1 )
    143             { // 在替换min1之前判断min1舍弃的值是不是比min2小,如果是的话min2就占着大便宜!
    144                 min2 = min1;
    145                 num2 = num1;
    146             }
    147             num1 = i;
    148             min1 = t[i]->weight;
    149         }else if (t[i]->weight)
    150         {
    151             min2 = t[i]->weight;
    152             num2 = i;
    153         }
    154     }
    155     s1 = num1;
    156     s2 = num2;
    157 }
    158 void HuffmanCoding(HuffmanTree &t,HuffmanCode &c,int *w,int n)
    159 {
    160    if (n<=1)
    161     return;
    162 
    163    int m = 2*n-1;
    164    t = (HuffmanTree)malloc(sizeof(HuffmanNode)*(m+1)); // m+1是因为0号单元未用
    165    for (int i=1;i<=n;i++)
    166    {
    167        t[i]->weight = w[i];
    168        t[i]->parent = 0;
    169        t[i]->lchild = 0;
    170        t[i]->rchild = 0;
    171    }
    172    // 下面的循环可省略,因为遍历过程中一定会重新写一遍
    173    for (int i=n+1;i<=m;i++)
    174    {
    175        t[i]->weight = 0 ;
    176        t[i]->parent = 0 ;
    177        t[i]->lchild = 0 ;
    178        t[i]->rchild = 0 ;
    179    }
    180     int s1,s2;
    181    // 建立哈夫曼树的循环
    182    for (int i = n+1;i<=m;i++)
    183    {
    184        //找到1-i-1中的最小值和次小值
    185        select_2(t,i-1,s1,s2);
    186        t[s1]->parent = i;
    187        t[s2]->parent = i;
    188        t[i]->weight = t[s1]->weight+t[s2]->weight;
    189        t[i]->lchild = s1;
    190        t[i]->rchild = s2;
    191    }
    192 
    193    // 计算哈弗曼编码值,从叶子到根逆向求
    194    c = (char **)malloc(sizeof(char*)*(n+1));//n个字符的头指针向量,从1开始
    195    char *cd = (char *)malloc(n*sizeof(char));// 哈弗曼树的高度不会超过n
    196    cd[n-1] = '';
    197    for (int i=1;i<=n;i++)
    198    {
    199        int start = n-1;//倒着存储编码
    200        for (int c = i,f = t[i]->parent;f!=0;c=f,f = t[f]->parent)
    201         if (t[f]->lchild == c)
    202         cd[--start] = '0';
    203        else
    204         cd[--start] = '1';
    205 
    206        c[i] = (char *)malloc(sizeof(char)*(n-start));
    207        strcpy(c[i],&cd[start]); // 复制编码
    208        /*
    209         char *p = (char *)malloc(sizeof(char)*10);
    210     p = "helloworld";
    211     cout << p << endl;
    212     char *q = (char *)malloc(sizeof(char)*5);
    213     strcpy(q,&p[5]);//两个参数都是地址,从起始地址到终止符之间的内容复制过去
    214     cout << q;
    215     */
    216    }
    217 
    218    // // 无栈非递归遍历哈夫曼树,求哈夫曼编码
    219 
    220     c = (HuffmanCode)malloc((n+1)*sizeof(char *));
    221     int p = m;
    222     int cdlen = 0;
    223     for (int i=1;i<=m;i++)
    224         t[i]->weight = 0; // 遍历哈夫曼树时用作结点状态标志
    225     while (p){
    226         if (t[p]->weight == 0 )
    227         {
    228             t[p]->weight = 1;
    229             if (t[p]->lchild!=0)
    230             { // 左右孩子均不为0的状况
    231                 p = t[p]->lchild;
    232                 cd[cdlen++] = "0";
    233             }
    234             else if (t[p]->rchild == 0 )
    235             {
    236                 // 左右孩子均为0,P结点为叶节点,登记字符编码
    237                 c[p] = (char *)malloc((cdlen+1)*sizeof(char));
    238                 cd[cdlen] = '';
    239                 strcpy(hc[p],cd);
    240             }
    241         }
    242         else if (t[p]->weight == 1){
    243             t[p]->weight = 2;
    244             if (t[p]->rchild != 0)
    245             {
    246                 p = t[p]->rchild;
    247                 cd[cdlen++] = '1';
    248             }else 
    249             {
    250                 t[p]->weight = 0;
    251                 p = t[p]->parent;
    252                 --cdlen; //退回父节点,编码长度减一
    253             }
    254         }
    255     }
    256 }
    257 
    258 
    259 int main()
    260 {
    261     int n;
    262     cout << "n:" <<endl;
    263     cin >> n;
    264 //    int huffman[2*n-1][5];
    265 //    huffmanTree(huffman,n);
    266 //    printTree(huffman,n);
    267 //    huffmanCode(huffman,n);
    268 //    int level = 0;
    269 //    printPath(huffman,n,2*n-2,level);
    270     HuffmanTree t;
    271     HuffmanCode c;
    272     int *w;
    273     for (int i=0;i<n;i++)
    274         cin >> w[i];
    275     HuffmanCoding(t,c,w,n);
    276     return 0;
    277 }

    机试指南的题,优先队列哈夫曼树

    优先队列的用法:
    (1)priority_queue 默认设置大顶堆
    (2)priority_queue

    struct node  
    {  
        friend bool operator< (node n1, node n2)  
        {  
            return n1.priority < n2.priority;  
        }  
        int priority;  
        int value;  
    };
    1. 比较运算符外置

    运算符重载:
    用于对对象的运算符操作

    box operator+(const box a,const box b) 
    { 
    box c; 
    c.weight = a.weight+b.weight; 
    return c; 
    }

    友元函数:
    1)C++中引入友元函数,是为在该类中提供一个对外(除了他自己意外)访问的窗口;
    2)这个友元函数他不属于该类的成员函数,他是定义在类外的普通函数,只是在类中声明该函数可以直接访问类中的private或者protected成员。
    3)友元函数可以访问类中的私有成员和其他数据,但是访问不可直接使用数据成员,需要通过对对象进行引用。

    // 输出哈夫曼树树顶元素

     1 int main()
     2 {
     3     int n;
     4     priority_queue<int,vector<int>,greater<int> > q;
     5     while (cin >> n)
     6     {
     7         while (!q.empty())
     8             q.pop(); // 清空小顶堆元素
     9 
    10         for (int i=1;i<=n;i++)
    11         {
    12             int d;
    13             cin >> d;
    14             q.push(d);
    15         }
    16         int ans = 0;
    17         while (q.size() > 1 )
    18         {
    19             int a = q.top();
    20             q.pop();
    21             int b = q.top();
    22             q.pop();
    23             q.push(a+b);
    24 
    25         }
    26         ans = q.top();
    27         cout << ans << endl;
    28     }
    29 
    30     return 0;
    31 }

    搬水果 改版上面的代码,只需要把ans加起来

     1 #include <iostream>
     2 #include <string.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 #include <queue>
     6 #include <vector>
     7 
     8 using namespace std;
     9 /*
    10 搬水果
    11 */
    12 
    13 
    14 int main()
    15 {
    16     int n;
    17     priority_queue<int,vector<int>,greater<int> > q;
    18     while (cin >> n)
    19     {
    20         while (!q.empty())
    21             q.pop(); // 清空小顶堆元素
    22 
    23         for (int i=1;i<=n;i++)
    24         {
    25             int d;
    26             cin >> d;
    27             q.push(d);
    28         }
    29         int ans = 0;
    30         int sum = 0;
    31         while (q.size() > 1 )
    32         {
    33             int a = q.top();
    34             q.pop();
    35             int b = q.top();
    36             q.pop();
    37             ans = a+b;
    38             q.push(ans);
    39             sum += ans;
    40 
    41         }
    42         cout << sum << endl;
    43     }
    44 
    45 
    46     return 0;
    47 }
  • 相关阅读:
    js-事件总结
    iquery-个人总结
    CSS3-页面样式
    野生码农狂奔中的2014年度年终总结
    算不算被虚度的这几年
    在Ubuntu 12.4 下安装 nginx, MySQL, PHP
    使用WP8最新的AudioVideoCaptureDevice类制作录像应用
    WP8 MediaElement 实现循环播放
    WPF(WP7、WP8)多个Listbox嵌套时滚动问题的解决
    Weibo SDK WP版本回调参数没有uid的解决方法
  • 原文地址:https://www.cnblogs.com/twomeng/p/9509583.html
Copyright © 2011-2022 走看看