본문 바로가기

C_Data Structure_Algorithm/C telephone v2.0

C 전화번호부 v2.0_2)

4) add


자. 여기서부터는 이제 위에서 설명한 ' 정렬' 을 반영해서 할 건데, 왜 load 함수에서는 저러한 것들을 반영 안했어 ? 왜냐하면, 우리는 파일을 불러올 때, 이미 그 파일이 정렬되었다고 가정하기 때문이다.

당연히 add 할 때는, 우리가 새로운 사람을 추가하는 것이니까,

add 할 사람의 이름과 번호를 buf1, buf2 에 입력받는다.

이제 이 사람을 전에는 그냥 맨 뒤에 추가했는데, 정렬을 반영해서 넣는 것이다.

처음에 i = n - 1;

즉, i 가 맨 마지막 사람을 뜻하는 것이다.

그 다음 strcmp( names[ i ] , buf1 )

i 번째 사람의 이름과, 내가 추가할 사람의 '이름'을 비교하는 것이다.

strcmp( names[ i ] , buf1 )

두 문자열이 같으면 0 을 반환한다.

만일 names[ i ] 가 buf1 보다 크면, ( 첫번째 문자열이, 두번째 문자열보다 더 크면 )

즉, 사전식 순서로 더 뒤쪽에 나오면, 음수를 반환하고

names[ i ]가 buf1보다 작으면

즉, 사전식 순서로 더 앞쪽에 나오면 , 양수를 반환한다.

( 즉, strcmp 는 단순히, 두 문자열이 같냐, 아니냐. 만 보는 것이 아니라, 사전식 순서로 누가 더 앞에 있느냐. 까지 반환해주는 함수이다 )

그러므로 strcmp( names[i], buf1 ) > 0 라는 것은,

names[ i ] 에 위치한 사람이 새로 입력한 사람보다 더 크다.

즉, 사전식 순서에서 더 뒤에 있다.

그렇다면 shift

즉, 한칸 뒤로 옮기는 작업을 진행한다.

names[ i + 1 ] = names[ i ] # i번째 방에 있는 사람을 i+1 번째 방으로 옮기기

numbers[ i + 1] = numbers[ i ] # i번째 방에 있는 번호를 i+1 번째 방으로 옮기기

이러한 일을 언제까지 해야해 ?

2가지 경우

1) 나보다 작은, 즉 , 사전식 순서에서 나보다 앞선 애, 혹은 같은 애가 나오거나

strcmp( names[i], buf1 ) ≤ 0

2) 맨 왼쪽으로 빠져나가버리는 경우, 즉, 모~ 든 기존의 이름보다, 사전식 순서에서 더 앞에 위치 할때 ( ex. 저 위에서 A 가 B ~ P 보다 더 알파벳 순서상 빨라서, 끝문자, 즉, P 부터 비교하기 시작해서, 점차 앞으로 비교를 해가고, 그 결과 B . 즉, 배열의 맨 처음 위치에 있는 글자보다도 앞이어서, B 보다 한칸 더 왼쪽으로 가서 비교가 되는 경우, 즉, 배열 index[ 0 ] 에 위치하는 B 보다 더 왼쪽으로 가버리는 경우 )

i < 0

>> while( i ≥ 0 && strcmp( names[ i ] , buf1 ) > 0 )

자, 이제 비교가 끝났어, 값을 넣어야 돼. 어떻게 ??

names [ i + 1 ] = strdup ( buf1 )

numbers [ i + 1 ] = strdup ( buf2 )

즉,

나보다 작거나 같은 애가 나왔을 때도, 그 애가 i 번째에 위치하고 있으면 i+1 번째에 내가 입력한 값을 넣기

ex. E 를 넣고 싶은데, D 가 i 번째에 위치한다면 E 는 i+1 번째에 넣어진다.

A 를 넣을 때처럼 i가 -1이 되는 값으로 , 내가 입력한 값이 빠지더라도,

i +1 , 즉, index [ 0 ] 에 값을 넣게 되는 것.

이제, 새로운 사람이 1명, 전화번호부에 추가되었으므로,

n++ 를 해주는 것이다.

그 이후, 성공했다는 메시지 출력해주기

5) remove


1번째와 달리, 내가 입력한 값과, 저장되어 있는 값을 찾는 기능은 remove 자체가 아니라, 그 안에 search 라는 별도의 함수를 따로 만들어서 진행한다.

먼저, search ( buf ) > 즉, 우리가 삭제할 사람의 정보를 buf 에 입력받고, 그 사람이 전화번호부에 어디에 있는지를 검색하는 기능을 수행하는데,

그 사람이 전화번호부에 있으면, 그 사람의 위치, 즉, index 를 반환해주고

만약 그 사람이 전화번호부에 존재하지 않으면 -1 을 return 하도록 해준다.

search 가 return 해주는 값이 index 이고, 그것이 -1 이면, 그런 사람은 없다 ! 라고 출력하고 끝내기

그런 이름을 가진 사람이 있다면 ??

첫번째 version에서는, 그 사람의 정보를 삭제하고 그 칸을 빈칸 혹은 공백으로 남겨두는 것이 아니라, 맨 마지막에 있는 사람의 정보를 그 칸에 넣었다

하지만, 여기서는 그렇게 할 수 없다.

왜냐하면 우리는 사람들을 이름의 알파벳 순으로 정렬 유지를 해야하기 때문이다.

그래서 다른 방식을 진행한다.

만일 B C D E F K M P 라면,

E 를 삭제한다고 했을 때,

F ~ P 를 모두 한칸씩 앞으로 옮겨주는 방법 밖에는 없다.

이 일을 하는 것이 바로,

int j = index for ( ; j < n - 1 ; j ++) { names[ j ] = names[ j +1 ]; numbers[ j ] = numbers [ j + 1 ] ; }

이다.

j는 현재 비어있는 자리이다.

j 를 증가시켜 가면서 j + 1 번째의 사람을 j 번째에 넣는 것이다.

왜 j < n 이 아니라

j < n - 1 일까 ??

n -1 까지 가버리면, n 까지 가는데, 애초부터 names [ n ]은 빈칸이다. 값이 없다.

왜냐하면 n 명의 정보를 저장한다면 배열 index 상으로는 n - 1 이 되기 때문이다.

6) find


첫번째와 거의 유사하다

다만, search 를 통해 반환값이 -1 이면, 현재 전화번호부에 그 사람이 없다는 의미이므로, 그대로 종료한다.

만일 존재한다면, 그 전화번호를 출력해준다.

7) Search


최종코드

#include<stdio.h>
#include<string.h>

#define CAPACITY 100
#define BUFFER_SIZE 20

char *names[CAPACITY];
char *numbers[CAPACITY];

int n = 0;

void add();
void find();
void status();
void remove();
void load();
void save();

int search( char *name){
	int i ;
	
	for ( i  = 0 ; i< n ; i++){
		if( strcmp( name, names[i]) == 0 ) {
			return i;
		}
		
		return -1;
	}
}

int main(){
	
	char buffer[BUFFER_SIZE];
	
	while(1){
		printf("$ ");
		scanf("%s",buffer);
		
		if( strcmp( buffer, "read") == 0)
			load();
		if( strcmp( buffer, "add") == 0 )
			add();
		if( strcmp( buffer, "find") == 0 )
			find();
		if( strcmp( buffer, "status") == 0 )
			status();
		if( strcmp( buffer, "delete") == 0 )
			remove();
		if( strcmp( buffer, "save") == 0 )
			save();
		if( strcmp( buffer, "exit") == 0 )
			break;
	}
	return 0;
} 

void add(){
	
	char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE];
	scanf("%s", buf1);
	scanf("%s", buf2);
	
	int i = n-1;
	while( i > 0 && strcmp( names[i], buf1 ) > 0 ) {
		// strcmp( names[i] , buf1 ) > 0 의 의미 ??
		// names[i]에 위치한 사람이 새로 입력한 사람보다 더 크다
		// 즉, 사전식 순서에서 더 뒤에 있다.  
		names[i+1] = names[i];
		numbers[i+1] = numbers[i];
		i--;
	} 
	
	// 만일, 입력한 이름이 알파벳 순서상, 이미 존재하고 있는 애보다 뒤에 있을 때. 
	names[i +1 ] = strdup(buf1);
	numbers[i+1] = strdup(buf2);
}

void find(){
	
	char buf[BUFFER_SIZE];
	scanf("%s", buf);
	
	int index = search(buf);
	if( index == -1)
		printf("No person named '%s' exists\n");
	else 
		printf("%s\n", numbers[index]); 
}

void status(){
	
	int i ;
	for( i = 0 ; i < n ; i++){
		printf("%s %s\n", names[i], numbers[i]);
	}
	
	printf("Total %s people\n", n);
}

void remove(){
	
	char buf1[BUFFER_SIZE];
	scanf("%s", buf1);
	
	int index = search(buf1);
	if( index == -1 ){
		printf("No person named '%s' exists\n", buf1);
		return ;
	} 
	
	// if 문을 거치지 않았다는 것은, 찾는 이름이 전화번호부에 있다는 것.  
	int j = index;
	
	for( ; j < n-1; j++){
		names[j] = names[j+1];
		numbers[j] = numbers[j+1];
	}
	// E 를 삭제한다고 했을 때, F ~ P를 모두 한칸씩 앞으로 옮겨주는 방법 !! 
	// j 에 아예 새로운 값을 입력하기.  
}

void load(){
	
	char fileName[BUFFER_SIZE];
	char buf1[BUFFER_SIZE];
	char buf2[BUFFER_SIZE];
	
	scanf("%s", fileName);
	
	FILE *fp = fopen(fileName, "r");
	if( fp == NULL ){
		printf("Open failed\n");
		return ;
	}
	
	while( fscanf(fp, "%s", buf1 ) != EOF ){
		
		fscanf(fp, "%s", buf2);
		names[n] = strdup(buf1);
		numbers[n] = strdup( buf2);
		n++;
	}
	
	fclose( fp );
}

void save(){
	
	int i;
	char fileName[BUFFER_SIZE];
	char tmp[BUFFER_SIZE];
	
	scanf("%s", tmp);
	scanf("%s", fileName);
	
	FILE *fp = fopen(fileName, "w");
	// 파일에 쓰기 위해, 파일을 열고, 아래와 같이, 이름과 번호를 입력한다.  
	if( fp == NULL ) {
		printf("Open failed\n");
		return ;
	}
	
	for( i = 0; i < n ; i++){
		fprintf(fp, "%s %s\n", names[i], numbers[i]);
	}
	
	fclose(fp);
}

int search( char *name){
	
	int i;
	for (i = 0 ; i < n ; i++){
		if ( strcmp( name, names[i] == 0 )) {
			return i;
		}
	}
	
	return -1;
}

 

'C_Data Structure_Algorithm > C telephone v2.0' 카테고리의 다른 글

C 전화번호부 v2.0_1)  (0) 2020.02.28