问题与解答

问题描述

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

输入格式

输入第一行表示样例数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. Java【常用的日期操作】

    目录 1.设置时间 2.获取年月日时分秒 3.通过运算获取时间 4.和Date类转换 5.格式化时间 6.新功能LocalDate:当前日期格式化 7.示例 java.util.Calendar 类是 ...

  2. 大数据学习day36-----flume02--------1.avro source和kafka source 2. 拦截器(Interceptor) 3. channel详解 4 sink 5 slector(选择器)6 sink processor

    1.avro source和kafka source 1.1 avro source avro source是通过监听一个网络端口来收数据,而且接受的数据必须是使用avro序列化框架序列化后的数据.a ...

  3. 【Netty】最透彻的Netty原理架构解析

    这可能是目前最透彻的Netty原理架构解析 本文基于 Netty 4.1 展开介绍相关理论模型,使用场景,基本组件.整体架构,知其然且知其所以然,希望给大家在实际开发实践.学习开源项目方面提供参考. ...

  4. 如何从 100 亿 URL 中找出相同的 URL?

    题目描述 给定 a.b 两个文件,各存放 50 亿个 URL,每个 URL 各占 64B,内存限制是 4G.请找出 a.b 两个文件共同的 URL. 解答思路 每个 URL 占 64B,那么 50 亿 ...

  5. implicit declaration of function 'NSFileTypeForHFSTypeCode' is invalid in c99

    问题:implicit declaration of function 'NSFileTypeForHFSTypeCode' is invalid in c99 解决办法: 在出现该问题的函数前后加上 ...

  6. Spring(2):依赖注入DI

    依赖注入DI 当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例.但在Spring里,创建被 ...

  7. Servlet(2):通过servletContext对象实现数据共享

    一,ServletContext介绍 web容器在启动时,它会为每一个web应用程序都创建一个ServletContext对象,它代表当前web应用 多个Servlet通过ServletContext ...

  8. MySQL批量数据脚本示例

    一.建表 # 新建库 create database bigData; use bigData; #1 建表dept CREATE TABLE dept( id INT UNSIGNED PRIMAR ...

  9. MyBatis绑定Mapper接口参数到Mapper映射文件sql语句参数

    一.设置paramterType 1.类型为基本类型 a.代码示例 映射文件: <select id="findShopCartInfoById" parameterType ...

  10. Snort 入侵检测系统

    Snort 入侵检测系统 一.实验目的 1.掌握snort IDS工作原理 2.应用snort 三种方式工作 二.实验环境 系统环境:Windows环境, kali环境 三.实验原理 1.snort ...