Loading

<数据结构>XDOJ334.分组统计

问题与解答

问题描述
先输入一组数,然后输入其分组,按照分组统计出现次数并输出,参见样例。
输入格式
输入第一行表示样例数m,对于每个样例,第一行为数的个数n,接下来两行分别有n个数,第一行有n个数,第二行的n个数分别对应上一行每个数的分组,n不超过100。数和分组号的值都不超过10000。
输出格式
按顺序输出各个样例的结果。输出格式参见样例,按组号从小到大输出,组内数字也按编号从小到大输出。
样例输入
1
7
3 2 3 8 8 2 3
1 2 3 2 1 3 1
样例输出
1={2=0,3=2,8=1}
2={2=1,3=0,8=1}
3=

//分组统计
//sort排序结构体数组,hash表缩短查找时间
#include<stdio.h>
#include<vector>
#include<algorithm>
using namespace std;
#define MaxN 10010
struct Node{
    int Data;
    int Group;
};
Node Elements[100];  //结构体数组,存储元素及其对应的组号
int Count[MaxN];     //hash表:1.记录所有出现的元素;2.记录每组各元素出现的次数
vector<int> All_Data;  //将hash中的元素转移到变长数组All_Data中避免多次遍历Count数组
void Divide(int n,int Max_Group);  //核心函数:划分组别并输出
bool cmp(Node x, Node y);  
/*对Elements进行排序时的比较函数:
1.先由组别从小到大;2.组别相同时按元素大小从小到大
*/
void Print_Result(int group_num);  //输出结果
vector<int> AllGroupNumber; //存储所有组的编号(组号不一定连续,如1、2、4)
int AllGroup[100];  //将AllGroupNumber复制到AllGroup好调用Sort排序
void Copy(); //复制函数
bool Find(int group); //寻找AllGroupNumber中是否已经有组号group

int main(){
    int m,n,i,data,group,Max_Group;
    scanf("%d", &m);
    while(m--){
        fill(Count, Count+MaxN, -1);  //Count数组初始化为-1
        scanf("%d", &n);
        for(i = 0; i < n; i++){  //输入数据
            scanf("%d", &data);
            Elements[i].Data = data;
            if(Count[data] == -1)
                Count[data]++;
        }
        for(i = 0; i < n; i++){  //输入组别
            scanf("%d", &group);
            Elements[i].Group = group;
            if(!Find(group))
                AllGroupNumber.push_back(group);  //AllGroupNumber记录所有输入的组号
        }
        for(i = 0; i < MaxN; i++){  //将所有输入元素由小到大输入All_Data
            if(Count[i] != -1)
                All_Data.push_back(i);  //All_Data记录所有输入的元素
        }
        Divide(n,Max_Group);  //调用核心函数
        All_Data.clear();   //清空All_Data
        AllGroupNumber.clear();  //清空AllGroupNumber
    }
}

void Divide(int n,int Max_Group){
    int group_num,data,index,i;
    sort(Elements, Elements+n, cmp);  //对Elements数组进行sort排序,用自定的cmp函数
    int size = AllGroupNumber.size();
    Copy();   //把AllGroupNumber的数据复制到AllGroup中(无法对vector调用sort)
    sort(AllGroup, AllGroup+size);  //对AllGroup进行sort排序,默认从小到大
    for(index = 0; index < size; index++){  //循环处理每一个组
        group_num = AllGroup[index];  //得到组号[已经从小到大有序]
        fill(Count, Count+MaxN, 0);   //重新初始化Count数组,为0
        for(i = 0; i < n; i++){       //统计Elements数组中第group组的各个元素的出现次数
            if(Elements[i].Group != group_num)
                continue;
            data = Elements[i].Data;
            Count[data] += 1;  //Count[data] = number表示元素data的出现次数是number
        }
        Print_Result(group_num);  //打印结果
    }
}

void Print_Result(int group_num){
    int i,count;
    printf("%d={", group_num);
    for(i = 0; i < All_Data.size(); i++){  //对于每一个输入的元素,打印出现次数
        count = Count[All_Data[i]];
        if(i == All_Data.size()-1)
            printf("%d=%d}\n", All_Data[i], count);
        else
            printf("%d=%d,", All_Data[i],count);
    }
}

bool cmp(Node x, Node y){  //Elements的比较函数
    if(x.Group != y.Group)  //先有组别从小到大
        return x.Group <= y.Group;
    else                   //组别相同时,按元素大小从小到大
        return x.Data <= y.Data;
}

bool Find(int group){  //判断AllGroupNumber中是否已经含有group
    int i,flag = 0;
    for(i = 0; i < AllGroupNumber.size(); i++){
        if(AllGroupNumber[i] == group)
            flag = 1;
    }
    return flag;
}
void Copy(){   //将AllGroupNumber中的元素复制到AllGroup
    int i,size;
    size = AllGroupNumber.size();
    for(i = 0; i < size; i++)
        AllGroup[i] = AllGroupNumber[i];
}

题后反思:核心算法简单,细节处理复杂

要解决的问题

  1. 要得到所有的组号,并由小到大排序。【因为组号不一定连续如1、3、5、8组,所以每个值都要记录】
  2. 要得到所有的输入元素,并由小到大排序。【分组统计时,所有输入元素在该组出现的次数都要输出】
  3. 要统计所有输入元素在每个组中的出现次数。

对应的解决方法

  1. 用AllGroupNumber记录无重复地记录所有输入的组别。在对AllGroupNumber进行排序。【由于无法直接对vector排序,所以不得不重新引入AllGroup数组并将AllGroupNumber的元素复制进去】
  2. 参考Dijstra算法的Vis数组的思想【本质就是hash】,创建Count数组,初始化为-1。在输入元素data时,将Vis[data]+1。输入结束后遍历Vis数组,Vis[i]!=0说明i是输入的元素,把它添加到变长数组vector<int> All_Data中,这样需要再次遍历所有出现的元素时,就不必遍历Vis[MaxN]数组。由于i是从小到大遍历Vis数组,所以All_Data中的元素已经从小到大有序。
  3. 遍历Elements数组,统计所有输入元素在每个组中的出现次数。以第一组为例。
    • 当把所有组号为1(Elements[data].Group == 1)的元素的出现次数+1(Count[Elements[data].Data]+1)。
    • 最终遍历按照vector<int> All_Data中元素的出现顺序遍历Count数组就得到了各个元素在该组的出现结果
    • 其他组则重置Count数组为0,重复上述步骤

细节实现繁琐

  1. AllGroupNumber无法直接Sort排序,因此设置AllGroup数组进行复制,再对AllNumber排序
  2. vector类型没有.find()方法,所以不得不手动实现AllGourpNumberFind()
  3. 原以为用Sort函数+hash查找来做会比较简单,没想到各种细节的添加导致了程序非常臃肿,思路不是非常清晰简洁。
posted @ 2021-12-23 20:44  咪啪魔女  阅读(429)  评论(0编辑  收藏  举报