问题与解答

问题描述

先输入一组数,然后输入其分组,按照分组统计出现次数并输出,参见样例。

输入格式

输入第一行表示样例数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={2=1,3=1,8=0}

//分组统计
//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查找来做会比较简单,没想到各种细节的添加导致了程序非常臃肿,思路不是非常清晰简洁。

<数据结构>XDOJ334.分组统计的更多相关文章

  1. Oracle按不同时间分组统计

    Oracle按不同时间分组统计 Oracle按不同时间分组统计的sql 如下表table1: 日期(exportDate) 数量(amount) -------------- ----------- ...

  2. 数据可视化之powerBI技巧(二十)采悟:创建度量值,轻松进行分组统计

    上一篇文章中的分组,都是通过新建列的方式实现的,直观上比较容易理解.不过这样都修改了原始数据的结构,如果我们不在源表上进行修改,直接通过度量值的方式来进行分组,是否可以实现呢? 答案当然是肯定的. 采 ...

  3. Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等)

    Linq to SQL 语法查询(链接查询,子查询 & in操作 & join,分组统计等) 子查询 描述:查询订单数超过5的顾客信息 查询句法: var 子查询 = from c i ...

  4. Dev用于界面按选中列进行分组统计数据源(实用技巧)

    如果有用U8的可以明白这个功能就是模仿他的统计功能.我不过是把他造成通用的与适应于DEV的. (效率为6000条数据分组统计时间为3秒左右分组列过多5秒.1000条以下0.几秒,500条下0.00几秒 ...

  5. DataTable、List使用groupby进行分组和分组统计;List、DataTable查询筛选方法

    DataTable分组统计: .用两层循环计算,前提条件是数据已经按分组的列排好序的. DataTable dt = new DataTable(); dt.Columns.AddRange(new ...

  6. 每日学习心得:CustomValidator验证控件验证用户输入的字符长度、Linq 多字段分组统计、ASP.NET后台弹出confirm对话框,然后点击确定,执行一段代码

    2013-9-15 1.    CustomValidator验证控件验证用户输入的字符长度 在实际的开发中通常会遇到验证用户输入的字符长度的问题,通常的情况下,可以写一个js的脚本或者函数,在ASP ...

  7. ORACLE的分组统计之ROLLUP(一)

    Oracle 9i以后,扩展了group by 的功能,能够满足大部分多维数据的分析统计功能,主要表现: 1. rollup,cube,grouping sets 扩展group by字句提供了丰富的 ...

  8. XtraGrid使用心得(折叠式主细档、分组统计)

    XtraGrid的关键类就是:GridControl和GridView.GridControl本身不显示数据,数据都是显示在GridView/CardView/XXXXView中.GridContro ...

  9. 使用awk进行日志信息的分组统计

    起因 这是今天我线上出了一个bug,需要查看日志并统计一个我需要的信息出现的频率,可以叫做分组统计. 日志文件部分内容 00:09:07.655 [showcase_backend][topsdk] ...

随机推荐

  1. Spark(十二)【SparkSql中数据读取和保存】

    一. 读取和保存说明 SparkSQL提供了通用的保存数据和数据加载的方式,还提供了专用的方式 读取:通用和专用 保存 保存有四种模式: 默认: error : 输出目录存在就报错 append: 向 ...

  2. JavaScript设计模式,单例模式!

    单例设计模式:保证一个类仅有一个实例,并且提供一个访问它的全局访问点.有些对象只需要一个,这时可用单例模式. 传统的单例模式 和new 创建对象的调用不一样 调用者要调用xxx.getInstance ...

  3. 【分布式】Zookeeper客户端基本的使用

    与mysql.redis等软件一样,zookeeper的软件包中也提供了客户端程序用于对服务器上的数据进行操作.本节我们就来学习zookeeper客户端的使用方法.不过在详细讲解zk客户端的使用方法之 ...

  4. Camera、音频录制与Vitamio框架

    一.Camera 1.概述 Android框架包含了各种相机哥相机功能的支持,是你可以在应用中捕获图像和视频. 在应用能使用设备上的相机之前,先想一想将来会如何使用此硬件: (1)Camera  应该 ...

  5. MySQL 迁移到 Redis 记

    前些日子,一个悠闲又不悠闲的下午,我还在用 Node.js 写着某个移动互联网应用的 API 服务端.那时还是用 MySQL 作为数据库,一切都很好,所有功能正常运行.可是有很多问题让人不安: 频繁的 ...

  6. Google Guava 常用集合方法

    /** * Author: momo * Date: 2018/6/7 * Description: */ public class ListTest { public static void mai ...

  7. 什么是maven(一)

    转自博主--一杯凉茶 我记得在搞懂maven之前看了几次重复的maven的教学视频.不知道是自己悟性太低还是怎么滴,就是搞不清楚,现在弄清楚了,基本上入门了.写该篇博文,就是为了帮助那些和我一样对于m ...

  8. SSM框架整合后使用pagehelper实现分页功能

    一.导入pagehelper-5.1.10.jar和jsqlparser-3.1.jar两个jar包 二.配置pagehelper 2.1 在mybatis配置文件中配置 <plugins> ...

  9. Linux 目录结构及详细操作

    目录 Linux 目录结构及详细操作 目录结构 目录结构的特点 目录结构挂载 目录结构发展 关闭selinux(了解) 重要目录说明(etc目录说明) 1.网卡配置文件 2.解析配置文件 3.主机名称 ...

  10. Firebug: Net Panel 使用详解

    Introduction to Firebug: Net Panel Since there is not much user documentation related to Firebug fea ...