백준 웹사이트 "2108번 - 통계학" 문제풀이입니다.
언어는 C언어입니다. (제출 언어: C99)
문제
소스 코드
#include <stdio.h>
#include <math.h>
int arith_mean(int *arr, int N);
int median(int *counting, int N);
int mode(int *counting, int N);
int range(int *counting, int N);
int main(void){
int N;
scanf("%d", &N);
int arr[N];
for(int i=0; i<N; i++){
scanf("%d", &arr[i]);
}
//정렬(카운팅 정렬)
int counting[8001]; //0~8000이 -4000~+4000을 의미
for(int i=0; i<8001; i++){
counting[i]=0;
}
for(int i=0; i<N; i++){
counting[arr[i]+4000]++; //0~8000 -> -4000~4000
}
//각 통계값 출력
printf("%d\n", arith_mean(arr, N));
printf("%d\n", median(counting, N));
printf("%d\n", mode(counting, N));
printf("%d\n", range(counting, N));
}
int arith_mean(int *arr, int N){ //산술 평균
double sum=0;
for(int i=0; i<N; i++){
sum += arr[i];
}
return (int) round(sum/N);
}
int median(int *counting, int N){ //중앙값
// N은 홀수: (N+1)/2 번째 수가 중앙값
int num=0;
for(int i=0; i<8001; i++){
num+=counting[i];
if(num>=(N+1)/2){
return i-4000;
}
}
return 0;
}
int mode(int *counting, int N){ //최빈값
//counting 값이 가장 큰 값
int max=0; //가장 높은 빈도
int num=0; //최빈값의 개수
int mode=0; //최빈값
for(int i=0; i<8001; i++){
if(counting[i]>max){
max=counting[i];
num=1;
mode=i-4000;
}
else if(counting[i]==max){
if(num==1){
num++;
mode=i-4000;
}
else{ //이미 2개 이상의 최빈값
num++;
}
}
}
return mode;
}
int range(int *counting, int N){ //범위
int max=0;
int min=0;
for(int i=8000; i>=0; i--){
if(counting[i]!=0){
max=i;
break;
}
}
for(int i=0; i<8001; i++){
if(counting[i]!=0){
min=i;
break;
}
}
return max-min;
}
문제 풀이
입력된 수들의 네 가지 기본 통계값을 구하는 코드입니다. main 함수에서는 수들을 입력받아 'arr' 배열에 저장하고, 카운팅 정렬을 시행합니다. 이를 위해 크기 8001의 'counting' 배열을 선언하는데, 이 배열은 0~8000의 인덱스를 가지게 되겠죠? 각각의 인덱스가 -4000~4000을 의미한다고 생각해줍시다. 즉, counting[0]은 값이 -4000인 수의 개수, counting[1]은 값이 -3999인 수의 개수, ... counting[8000]은 값이 4000인 수의 개수가 됩니다. "인덱스 - 4000" 이 해당 카운팅 배열이 의미하는 숫자가 되는 셈이죠. 마지막으로 산술평균, 중앙값, 최빈값, 범위를 각각 계산하는 함수를 호출하여 네 가지 기본 통계값을 구합니다.
그러면, 각각의 함수를 자세히 한 번 봅시다. 'arith_mean'은 '산술평균'을 계산하는 함수입니다. arith_mean은 'arr'과 'N'을 입력으로 받습니다. arr에 저장된 모든 수들의 합 'sum'을 구한 후, N으로 나누어 산술평균을 구합니다. 이때 소수 첫째짜리에서 반올림하기 위해, <math.h>의 'round' 함수를 이용합니다. 'round' 함수의 입력, 출력이 모두 double형이므로, 이에 알맞게 자료형 변환을 시킵니다.
'median'은 '중앙값'을 계산하는 함수입니다. median은 'counting'과 'N'을 입력으로 받습니다. N은 홀수이므로, (N+1)/2 번째로 작은 수가 됩니다. 정렬된 'counting' 배열은 중앙값 구하는 것을 매우 편리하게 해주는데, 각 수의 개수가 기록되어 있기에 가장 작은 수부터 개수를 기록하여 (N+1)/2 번째 수에 도달하면 그 값을 반환합니다. 참고로 Line 51의 'return 0'은 해주지 않아도 return이 항상 보장되기에 무관하지만, 컴파일러 쪽에서 warning이 뜰 수 있어 해주는 것이 좋습니다.
'mode'는 '최빈값'을 계산하는 함수입니다. 최빈값은 곧 counting 배열의 값이 가장 높은 수를 찾는 것인데, 최빈값이 여러 개일 경우 두 번째로 작은 값을 구하는 것이 조금 복잡하게 만듭니다. 세 변수 'max', num', 'mode'를 선언하여, '가장 높은 빈도', '최빈값의 개수', '최빈값'이란 의미를 부여합니다. 나머지는 소스코드를 보고 따라가면 쉽게 이해가 될 것입니다.
마지막으로 'range'는 '범위'를 계산하는 함수입니다. 최댓값 'max'와 최솟값 'min'을 counting 배열로 구하고, 둘의 차를 반환하면 원하는 범위가 얻어집니다.
'코딩 > 백준 BOJ' 카테고리의 다른 글
[백준/C언어] 11650번 - 좌표 정렬하기 (0) | 2022.02.15 |
---|---|
[백준/C언어] 1427번 - 소트인사이드 (0) | 2022.02.14 |
[백준/C언어] 10989번 - 수 정렬하기 3 (0) | 2022.02.12 |
[백준/C언어] 2751번 - 수 정렬하기 2 (0) | 2022.02.11 |
[백준/C언어] 2750번 - 수 정렬하기 (0) | 2022.02.10 |