机试指南 cha3 哈夫曼

机试指南 cha3 哈夫曼

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

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>


using namespace std;
/*
1. 哈夫曼编码-顺序存储方式
2. 优先队列存储——堆存储
*/

void huffmanTree(int huffman[][5],int n)
{

    for (int i=0;i<n;i++)
    {
        huffman[i][0] = i;
        cin >> huffman[i][1];
        huffman[i][2] = -1;
        huffman[i][3] = -1;
        huffman[i][4] = -1;
    }
    int num1 = 0,num2 = 0;
    float min1 = 9999,min2 = 9999;

    for (int i=0;i<n-1;i++)
    {
        num1 = 0;
        num2 = 0;
        min1 = 9999;
        min2 = 9999;
        for (int j=0;j<n+i;j++)
        {
            // 找到一组数中未被排序(没有父节点)的的最小值和次小值,最小值优先判断,判断完最小值后判断次小值
            if (huffman[j][2] == -1 && huffman[j][1] < min1 )
            {
                    if (min1 < min2)
                {
                    min2 = min1;
                    num2 = num1;
                }
                min1 = huffman[j][1];
                num1 = j;
            }
            else if (huffman[j][2] == -1 && huffman[j][1] < min2)
            {
                min2 = huffman[j][1];
                num2 = j;
            }
        }
        huffman[n+i][0] = n+i;
        huffman[n+i][1] = huffman[num1][1]+huffman[num2][1];
        huffman[n+i][2] = -1;
        huffman[n+i][3] = num1;
        huffman[n+i][4] = num2;
        huffman[num1][2] = n+i;
        huffman[num2][2] = n+i;

    }
}
void printTree(int huffman[][5],int n)
{
    for (int i=0;i<2*n-1;i++)
    {
        for (int j=0;j<5;j++)
            cout << huffman[i][j] << ' ';
        cout << endl;
    }
}
void huffmanCode(int huffman[][5],int n)
{
    // 自顶向下法:找到根到所有孩子的路径,每条路径均对应一个孩子
    // 自底向上法:遍历每个叶子结点,往上寻找直到找到根为止
    char code[20];
    int q,parent;
    int j = 0;
    for (int i=0;i<n;i++)
    {
        q = i;
        parent = huffman[q][2];
        j = 0;
        while (parent!=-1)
        {
            if (huffman[parent][3] == q)
            {
                // q是parent的左孩子
                code[j] = '0';
            }
            if (huffman[parent][4] == q)
            {
                code[j] = '1';
            }
            j++;
            q = parent;
            parent = huffman[q][2];
        }
        code[j]  = '\0';
        cout << huffman[i][1] << " : " << code << endl;
    }
}
char code[10];
void printPath(int huffman[][5],int n,int root,int level)
{
    // 打印从根节点到所有叶子结点的路径
    level ++;
    if (huffman[root][3] != -1 && huffman[root][4]!=-1)
    {
        // 如果root不为根节点时
        code[level] = '0';
        printPath(huffman,n,huffman[root][3],level);
        code[level] = '1';
        printPath(huffman,n,huffman[root][4],level);
    }
    else {
        code[level] = '\0';
        for (int i=1;i<=level;i++)
            cout << code[i];
        cout << ' ' << huffman[root][1] <<endl;
    }

}

// 课本上的代码方法,结构体数组封装一个结点而不是二维数组
typedef struct HuffmanNode
{
    int weight;
    int parent,lchild,rchild;
}HuffmanNode,**HuffmanTree;

typedef char ** HuffmanCode ; // 动态分配数组存储哈夫曼编码表


void select_2(HuffmanTree t,int n,int &s1,int &s2)
{
    int min1 = 9999,min2 = 9999;
    int num1=1,num2 = 1;
    for (int i=1;i<=n;i++)
    {
        if (t[i]->weight < min1)
        {
            if ( min2 > min1 )
            { // 在替换min1之前判断min1舍弃的值是不是比min2小,如果是的话min2就占着大便宜!
                min2 = min1;
                num2 = num1;
            }
            num1 = i;
            min1 = t[i]->weight;
        }else if (t[i]->weight)
        {
            min2 = t[i]->weight;
            num2 = i;
        }
    }
    s1 = num1;
    s2 = num2;
}
void HuffmanCoding(HuffmanTree &t,HuffmanCode &c,int *w,int n)
{
   if (n<=1)
    return;

   int m = 2*n-1;
   t = (HuffmanTree)malloc(sizeof(HuffmanNode)*(m+1)); // m+1是因为0号单元未用
   for (int i=1;i<=n;i++)
   {
       t[i]->weight = w[i];
       t[i]->parent = 0;
       t[i]->lchild = 0;
       t[i]->rchild = 0;
   }
   // 下面的循环可省略,因为遍历过程中一定会重新写一遍
   for (int i=n+1;i<=m;i++)
   {
       t[i]->weight = 0 ;
       t[i]->parent = 0 ;
       t[i]->lchild = 0 ;
       t[i]->rchild = 0 ;
   }
    int s1,s2;
   // 建立哈夫曼树的循环
   for (int i = n+1;i<=m;i++)
   {
       //找到1-i-1中的最小值和次小值
       select_2(t,i-1,s1,s2);
       t[s1]->parent = i;
       t[s2]->parent = i;
       t[i]->weight = t[s1]->weight+t[s2]->weight;
       t[i]->lchild = s1;
       t[i]->rchild = s2;
   }

   // 计算哈弗曼编码值,从叶子到根逆向求
   c = (char **)malloc(sizeof(char*)*(n+1));//n个字符的头指针向量,从1开始
   char *cd = (char *)malloc(n*sizeof(char));// 哈弗曼树的高度不会超过n
   cd[n-1] = '\0';
   for (int i=1;i<=n;i++)
   {
       int start = n-1;//倒着存储编码
       for (int c = i,f = t[i]->parent;f!=0;c=f,f = t[f]->parent)
        if (t[f]->lchild == c)
        cd[--start] = '0';
       else
        cd[--start] = '1';

       c[i] = (char *)malloc(sizeof(char)*(n-start));
       strcpy(c[i],&cd[start]); // 复制编码
       /*
        char *p = (char *)malloc(sizeof(char)*10);
    p = "helloworld";
    cout << p << endl;
    char *q = (char *)malloc(sizeof(char)*5);
    strcpy(q,&p[5]);//两个参数都是地址,从起始地址到\0终止符之间的内容复制过去
    cout << q;
    */
   }

   // // 无栈非递归遍历哈夫曼树,求哈夫曼编码

    c = (HuffmanCode)malloc((n+1)*sizeof(char *));
    int p = m;
    int cdlen = 0;
    for (int i=1;i<=m;i++)
        t[i]->weight = 0; // 遍历哈夫曼树时用作结点状态标志
    while (p){
        if (t[p]->weight == 0 )
        {
            t[p]->weight = 1;
            if (t[p]->lchild!=0)
            { // 左右孩子均不为0的状况
                p = t[p]->lchild;
                cd[cdlen++] = "0";
            }
            else if (t[p]->rchild == 0 )
            {
                // 左右孩子均为0,P结点为叶节点,登记字符编码
                c[p] = (char *)malloc((cdlen+1)*sizeof(char));
                cd[cdlen] = '\0';
                strcpy(hc[p],cd);
            }
        }
        else if (t[p]->weight == 1){
            t[p]->weight = 2;
            if (t[p]->rchild != 0)
            {
                p = t[p]->rchild;
                cd[cdlen++] = '1';
            }else 
            {
                t[p]->weight = 0;
                p = t[p]->parent;
                --cdlen; //退回父节点,编码长度减一
            }
        }
    }
}


int main()
{
    int n;
    cout << "n:" <<endl;
    cin >> n;
//    int huffman[2*n-1][5];
//    huffmanTree(huffman,n);
//    printTree(huffman,n);
//    huffmanCode(huffman,n);
//    int level = 0;
//    printPath(huffman,n,2*n-2,level);
    HuffmanTree t;
    HuffmanCode c;
    int *w;
    for (int i=0;i<n;i++)
        cin >> w[i];
    HuffmanCoding(t,c,w,n);
    return 0;
}

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

优先队列的用法:
(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)友元函数可以访问类中的私有成员和其他数据,但是访问不可直接使用数据成员,需要通过对对象进行引用。

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

int main()
{
    int n;
    priority_queue<int,vector<int>,greater<int> > q;
    while (cin >> n)
    {
        while (!q.empty())
            q.pop(); // 清空小顶堆元素

        for (int i=1;i<=n;i++)
        {
            int d;
            cin >> d;
            q.push(d);
        }
        int ans = 0;
        while (q.size() > 1 )
        {
            int a = q.top();
            q.pop();
            int b = q.top();
            q.pop();
            q.push(a+b);

        }
        ans = q.top();
        cout << ans << endl;
    }

    return 0;
}

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

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <queue>
#include <vector>

using namespace std;
/*
搬水果
*/


int main()
{
    int n;
    priority_queue<int,vector<int>,greater<int> > q;
    while (cin >> n)
    {
        while (!q.empty())
            q.pop(); // 清空小顶堆元素

        for (int i=1;i<=n;i++)
        {
            int d;
            cin >> d;
            q.push(d);
        }
        int ans = 0;
        int sum = 0;
        while (q.size() > 1 )
        {
            int a = q.top();
            q.pop();
            int b = q.top();
            q.pop();
            ans = a+b;
            q.push(ans);
            sum += ans;

        }
        cout << sum << endl;
    }


    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_33846054/article/details/80736740