C++/기초

C++ 기초 : tree (5)

시플마 2024. 4. 27. 15:51

이제 find 함수를 통해 

찾은 노드에 실질적으로 저장된

데이터를 출력하기 위한 코드를 작성합시다.

 

61번째 줄에 있는 if 문에 걸리지않아 

else 구문으로 넘어갔다면 find 함수를 통해

찾은 노드가 존재한다는 의미겠죠?

 

 

67 ~ 68번째 줄에서 

find 함수가 찾은 노드를 iterator로 반환합니다.

이를 기존에 있던 iterator에 대입하였으니

이제 iterator는 찾은 노드를 가리키게 되죠.

 

해당 노드에는 pair가 들어 있으며

pair의 두 번째 멤버에는 학생 정보가 들어 있습니다.

이 학생 정보에는 이름이 들어 있죠.

그래서 iterator가 가리키는 pair에 접근하고 

여기서 학생 정보가 들어 있는 두 번째 멤버에 접근합니다.

그 학생 정보에 들어 있는 이름을 출력하는 것이죠.

 

 

마찬가지로 나이 또한 학생 정보에 들어 있는

나이를 출력하는 것입니다.

 

 

성별은 define 지시문을 통해 

1이면 남자, 2면 여자로 설정해줬죠?

그래서 바로 출력하면 1 또는 2가 출력될 것입니다.

우리는 성별은 문자로 출력하고 싶습니다.

iterator가 가리키는 pair에 접근하여 

학생 정보가 들어 있는 두 번째 멤버에 접근한 후

gender라는 멤버 변수의 값과 MAN과 같은지, 

즉 1과 같은지 비교합니다. 맞다면 "남자"라는 문자열을 출력하죠.

 

 

만약 위에 해당하지 않는다면

iterator가 가리키는 pair에 접근하여 

학생 정보가 들어 있는 두 번째 멤버에 접근한 후

gender라는 멤버 변수의 값과 WOMAN과 같은지, 

즉 2와 같은지 비교합니다. 맞다면 "여자"라는 문자열을 출력하죠.

 

 

위 두 경우에 해당하지 않는다면

성별이 잘못 입력된 것으로 간주하고 

성별을 알 수 없다는 문자열을 출력합니다.

 

 

참고로 한글을 표현하기 위해 이름을

문자 하나를 2Byte로 보는 와이드 문자열로 

받기도 하였고 출력되는 안내 문자열이 

모두 한글이기 때문에 wcout를 통해 유니코드

문자열을 출력할 수 있게 하는 겁니다.

 

또한 59번째 코드를 추가하여 

지역 설정을 "korean"으로 해 줘야

wcout을 사용하여 와이드 문자열 출력 시

한글이 제대로 출력됩니다.

 

 

 

 


 

 

 

 

const wchar_t 포인터는 문자열의 주솟값을

저장하는 자료형이죠?

 

map의 첫 번째 typename을

const wchar_t 포인터로 하였습니다.

이는 문제가 있습니다.

 

첫 번째 typename에 지정된

자료형을 키-값으로 하여

트리를 구성하게 될텐데, 이 키-값의

자료형을 const wchar_t 포인터로 하면

주솟값을 비교하여 더 큰 주솟값을 가진

데이터를 오른쪽에 더 작은 주솟값을 가진

데이터를 왼쪽에 배치하게 될 겁니다.

 

이는 이름(문자열)을 비교하여

트리를 구성하려고 했던 의도와는 다르죠.

 

 

문자열을 비교하여 트리를 구성하려면

map의 키-값의 자료형을 결정하는

첫 번째 typename을 wstring으로 해줘야 합니다.

 

std라는 namespace에 구현되어 있어 

범위 지정 연산자 없이 바로 사용하기 위해

using std::wstring; 코드를 추가해 줍니다.

 

 

그럼 우선 wstring에 대해서 알아 보죠.

 

wstring은 클래스로 객체를 하나 만들 수 있습니다.

 

그리고 와이드 문자열을 대입할 수 있죠.

 

여기서 중요한 점은 wchar_t형 포인터처럼

ROM(Read-Only Memory)에 있는 문자열을

가리키는 게 아니라 문자열을 직접 복사하여 저장한다는 것이죠.

(이때 wstring형 객체 안에 큰 공간이

미리 할당되어 있는 게 아니라 데이터가 들어갈 공간이

필요할 때마다 동적 할당하는 것이겠죠?)

그래서 const를 붙일 필요가 

없습니다. 필요에 따라 수정할 수도 있거든요.

 

덕분에 문자열을 수정할 수도 있고

문자열을 이어 붙일 수 있도록

+ 연산도 가능한 겁니다.

 

마치 배열처럼 인덱스 번호로

접근하여 값을 대입하는 것도 가능하고요.

 

또한 wstring형 객체끼리 서로 

비교할 수 있는 비교 연산자도 제공되어

같은지 다른지, 어느 쪽이 더 크고 작은지 

비교할 수도 있습니다.

 

객체가 저장하고 있는 문자를 하나씩,

사전순을 기준으로 비교할 겁니다.

 

 

이러한 wstring을 map에 첫 번째 typename으로

하면 어떤 동작이 발생할까요?

 

처음에 "이민수"라는 문자열과 학생 정보가

하나의 pair로 묶이고 이것이 

트리의 루트 노드가 될 것입니다.

 

다음에는 "최유리"라는 문자열과 학생 정보가

하나의 pair로 묶이고 이것을 삽입하려는 순간,

기존에 있던 루트 노드의 키-값 "이민수"와

현재 삽입하려면 노드의 키-값 "최유리"와

비교 연산을 진행하겠죠. 비교하여 

"최유리"가 더 크면 오른쪽의 자식 노드로 

더 작으면 왼쪽의 자식 노드로 배치되겠죠.

 

이 경우 '이'보단 '최'가 사전순으로 뒤에 있기 

때문에 문자열 "최유리"가 더 크다고 판단하여

오른쪽 자식 노드로 배치되겠군요.

 

 

 


 

 

그러면 직접 만든 클래스도 map으로 

트리를 구성할 때의 키-값 자료형으로 사용할 수 있지 않을까

라는 생각이 들어 클래스를 하나 만들고 진행해 보겠습니다.

 

위와 같은 간단한 클래스를 하나 만들고

 

 

typename을 방금 만든 클래스와 학생 정보를 

담는 클래스로 지정하고 노드를 삽입하려고 하자

 

오류가 발생합니다. 

 

< 연산자가 없다는 내용입니다.

 

MyClass라는 클래스로 만든 객체를

비교하여 트리를 구성해야 하죠?

MyClass는 기본 자료형이 아니기 때문에 

비교 연산자를 오버로딩해 줘야 비교 시에

어떤 기준으로 비교할지 인지가 가능합니다.

 

그래서 아래 코드처럼 

 

< 연산자를 오버로딩해 줘야

MyClass형 객체를 비교할 수가 있겠죠.

 

비교만 하면 되기 때문에 const MyClass형 레퍼런스로 

객체를 받아 < 연산자를 호출한(왼쪽 객체) 객체보다

인자로 받은(오른쪽 객체)가 더 크면 true를 반환하고

아니면 false를 반환하는 함수입니다. 완벽하지는 않지만

저런 동작을 하는 연산자를 오버로딩해 줘야 

노드의 배치가 이루어질 수 있겠죠.

 

 

해당 함수를 추가하면

오류가 발생하지 않는 것을 확인할 수 있습니다.

 

 

 

 

강의 출처 : https://www.youtube.com/watch?v=PFc4g8mxOiI&list=PL4SIC1d_ab-aOxWPucn31NHkQvNPHK1D1&pp=iAQB