프로그램의 기능은 Dynamic array를 구현했던 프로그램과 동일하다.
1. load_names와 compare 함수의 기능을 수정하였으며 binary search를 수행한다. |
사용된 구조체도 이전 프로그램과 동일하다.
[tNames]
typedef struct {
int len; // 배열에 저장된 이름의 수
int capacity; // 배열의 용량 (배열에 저장 가능한 이름의 수)
tName *data; // 이름 배열의 포인터
} tNames;
[tName]
typedef struct {
char name[20]; // 이름
char sex; // 성별 M or F
int freq[MAX_YEAR_DURATION]; // 연도별 빈도
} tName;
해당 프로그램에는 총 6개의 함수가 정의되어 있다.
1. create_names: 이름 구조체를 초기화해준다.(len을 0으로, capacity를 1로 초기화한 후 구조체 포인터를 return한다) 2. load_names: 입력 파일을 읽어들인다. 3. compare: bsearch를 위한 비교 함수이다. 4. print_names: 구조체 배열을 화면에 출력해준다. 5. destroy_names: 이름 구조체 메모리를 해제해준다. 6. binary_search: 이진 탐색 함수이다. key가 발견되는 경우 배열의 인덱스를 return하고 key가 발견되지 않는 경우에 key가 삽입되어야 할 배열의 인덱스가 return된다. |
수정된 함수와 새로 생긴 binary_search함수만 확인해보자.
[compare]
int compare( const void *n1, const void *n2)
{
int result;
result = strcmp((const char *)n1, (const char *)n2);
if(result)
return result;
else
{
result = (unsigned int)(*((char *)n1 + 20) - *((char *)n2 + 20));
return result;
}
}
이름을 strcmp를 이용해 비교한 뒤 만약 이름이 같다면 성별 변수에 접근하여 성별이 같은지에 대한 여부를 return하도록 수정하였다.
[binary_search]
int binary_search( const void *key, const void *base, size_t nmemb, size_t size, int (*compare)(const void *, const void *))
{
int first = 0;
int last = nmemb - 1;
int mid, check;
while(first <= last)
{
mid = (first + last)/2;
check = compare(key, base + size*mid);
if(!check)
return mid;
if(check <= 0)
last = mid-1;
else
first = mid+1;
}
return first;
}
binary search를 수행하여 이름 구조체가 삽입될 위치를 return해준다.
[load_names]
void load_names(FILE *fp, int year_index, tNames *names)
{
char *i = 0;
int *key = 0;
char tmp[100];
tName input;
int index;
while(fgets(tmp, sizeof(tmp), fp))
{
//comma -> tab
for(i = tmp; ; i++)
{
if(!*i)
break;
if(*i == ',')
*i = '\t';
}
sscanf(tmp, "%s\t%c\t%d", input.name, &input.sex, &input.freq[0]);
//compare함수에서 +20부분에 sex가 위치해야 함. -> tName 구조체 이용.
key = bsearch(input.name, names->data, names->len, 64, compare);
if(key)
{
key[year_index + 6] = input.freq[0]; //name(20) + sex(4) + freq
}
else
{
//full memory
if(names->capacity == names->len)
{
names->data = (tName*)realloc(names->data, names->capacity * 2 * sizeof(tName));
assert(names->data != NULL);
if(!names->data)
{
fprintf(stderr, "Insufficient memory capacity!");
return;
}
names->capacity *= 2;
}
index = binary_search(input.name, names->data, names->len, 64, compare);
memmove(&(names->data[index+1]), &(names->data[index]), ((names->len)-index)*64);
strcpy(names->data[index].name, input.name);
names->data[index].sex = input.sex;
memset(names->data[index].freq, 0, 40);
names->data[index].freq[year_index] = input.freq[0];
names->len++;
}
}
}
대략적인 구조는 이전과 동일하지만 bsearch함수를 사용하여 이름이 삽입될 위치를 확인하고 기존에 존재했던 이름이면 freq변수의 해당 연도 인덱스에 추가만해주고 기존에 존재하지 않았던 이름이라면 메모리 확인을 해준 후 binary_search함수를 사용해서 tName배열에 삽입될 index를 return받은 뒤 memmove로 그 뒤에 있는 리스트를 한칸씩 미룬 후 그 위치에 이름, 성별, 빈도를 저장한다.
[전체 코드&이름 파일]
'자료구조' 카테고리의 다른 글
Dynamic array 구현(동적 배열) (2) | 2020.05.26 |
---|