그냥 게임개발자

struct 본문

내 개인적인 공부/자료구조

struct

sudoju 2024. 4. 14. 17:50

구조체!

C배우면서 많이들 보셨을 겁니다.

커스텀하게 데이터를 만들 수 있는 자료구조를 의미하는데,

 

아래 사진을 봐보죠.

 

C에서 struct는 structure tag를 달아서 사용합니다.

그 안에는 멤버 구조들이 짜여져있습니다.

멤버 변수들이 있다는 것이죠.

 

멤버 변수라는 것은 클래스나 구조체 내부의 변수를 뜻합니다.

 

한번 만들어봅시다.

#incldue <iostream>

using namespace std;

struct Santos
{
    int a, b;
    double c, d, e;
};

void print(Santos santos)
{
    cout << santos.a << " " << santos.b << " " << santos.c << " " << santos.d << " " << snatos.e << '\n';
}

int main()
{
    Santos santos = { 1, 1, 1, 1, 1 };
    print(santos);
    vector<Santos> ret;
    
    ret.push_back({ 1, 2, 3, 4, 5 });
    ret.push_back({ 1, 2, 3, 4, 6 });
    ret.push_back({});
    ret.push_back({ 1, 3 });
    
    for (Santos santos : ret)
    {
        print(santos);
    }
    
    return 0;
}

 

이렇게 구조체를 만들어 놓고 값을 집어넣고 테스트 해보았습니다.

결과물은

값을 정하지 않은 것들은 0으로 초기화가 되는 것을 확인할 수 있습니다.

int라서 그렇지 문자열이었으면 빈 문자열이 들어갔을 것입니다.

 

말 그대로 커스텀 데이터형태죠.

그러면 여기서 간단한 구조체를 집어넣은 vector를 정렬한다면 어떻게 해야할까요?

구조체 안에 있는 멤버 변수 중 a를 1순위, b를 2순위로 오름차순으로 정렬하고 싶다면 어떻게 해야 할까요?

또한 초기화를 하지 않을 경우 0 또는 빈 문자열이 들어가는데 초기값을 설정하고 싶다면 어떻게 해야할까요??

 

이런 요구사항이 struct에 많아지면 복잡한 struct를 구축해야 합니다.

 

Point라는 구조체를 정의해보죠.

 

struct Point
{
    int y, x;
    Point(int _y, int _x) : y(_y), x(_x) {}
    Point() { y = -1; x = -1; }
	
    bool operator < (const Point& a) const
    {
        if (x == a.x)
            return y < a.y;

        return x < a.x;
    }
}

 

어우 어렵다 그죠?

 

차근 차근 해석해보면 됩니다.

저도 이런 구조체 데이터는 자주 사용해보지 않아서 저랑 같이 이해해보시죠.

 

구조체의 멤버 변수 y와 x를 정의한 부분입니다.

int y, x;

 

y와 x를 받아 멤버 변수를 생성한다는 의미인데,

Point(int _y, int _x) : y(_y), x(_x) {}

이는 C++의 생성자 초기화 방식인데

매개변수의 y와 x를 값을 집어넣는데 있어 초기화를 진행하는데 그값을 멤버 변수 y에 인자로 받은 _y로 값을 초기화 하겠다라는 의미입니다.

 

그다음 또다른 생성자를 보면

Point() { y = -1; x = -1; }

이는 매개변수를 받지 않고 생성했을 때 초기화 값은 -1, -1로 설정한다는 의미입니다.

 

 

참 이 부분이 많이 헷갈리더라구요 저는 많이 사용 안해봐서그런가

    bool operator < (const Point& a) const
    {
        if (x == a.x)
            return y < a.y;

        return x < a.x;
    }

operator를 만들어준 것인데요.

연산자(operator)를 오버로딩 하는 것인데

<, >, ==, != 등 이런 연산자들을 하위 클래스에서 재정의가 아니라 새로운 것으로 확장하신다라고 보면 되겠습니다.

 

오버라이딩이 아니라 왜 오버로딩인지 설명을 드리자면,

int, float의 형태로 확인하는 것이 아닌 복잡한 어떠한 객체 즉, struct를 기반으로 비교하게 되니 어떠한 확장적인 기능이 필요하고 또한 이러한 구조체를 서로 비교해야 하는 상황이 있을수도 있습니다.

그렇다면 우리는 커스텀으로 복자합 데이터 객체를 만들었으니 연산자도 그에 맞는 확장적인 연산자 오버로딩으로 만들어줘야 합니다.

 

저 operator는 이렇게 사용하겠죠?

Pointer1 pointer1;
Pointer2 pointer2;

pointer1 < pointer2;

그렇다면 이 operator는 오른쪽(pointer2)의 구조체가 매개변수로 들어가게 됩니다.

그러면 이 부분을 보죠.

 

if (x == a.x)
    return y < a.y;

pointer1.x와 pointer2.x를 비교해 서로 같으면 y를 비교해서 pointer1.y와 pointer2.y를 비교해 true false 값을 반환하죠.

 

만약 처음 조건문 x == a.x에서 같지가 않다면

그냥 바로 pointer1.x와 pointer2.x를 비교해서 값을 반환합니다.

 

return x < a.x;

 

그럼 여기서 설명했듯이 1순의는 x로 기준을 잡아서 비교하고 2순위는 y를 기반으로 잡아 크고 작음을 판단하죠.

이 코드를 기반으로 정렬하게 되면 오름차순으로 정렬이 됩니다.

x가 1순위고 y가 2순위이기 때문이죠

 

이해가 안간다면 조금만 더 설명해보죠.

Point pointer1 = Point(1, 2);
Point pointer2 = Point(2, 3);
pointer1 > pointer2;

 

이와 같이 코드를 작성했다면 서로 비교를 했을 때 어떨까요?

처음에 pointer1은 y = 1, x = 2가 됩니다.

pointer2는 y = 2, x = 3이구요.

그렇다면 비교를 했을 때 x를 먼저 비교하니

2와 3을 비교합니다.

그러면 pointer1의 x가 2니 pointer2의 x 보다 작으니 if문의 조건은 넘어가게 되면서 바로 return으로 넘어가 x를 비교해서 pointer1의 x가 더 작으니 pointer1이 더 작다라는 결론이 나오게되요!

최대한 자세하게 설명을 했는데 더 어려우신가요....

정말 차근차근 읽어보면 아! 할 때가 있을겁니다.

그러면 결론은 이렇습니다.

pointer1 > pointer2 		// pointer1이 더 작은 결론이 나옴

 

구조체 기반 sort를 사용할 때의 주의할점은

우리가 코드를 작성했던 것처럼 < operator 기준으로 struct가 구축되었는데, 이를 기반으로 이러한 struct를 구현한 변수들을 sort하는 상황이 생길수도 있습니다.

그렇다면 operator는 >이게 아닌 <로 기준으로 오버로딩이 되어야 합니다.

sort() 함수 자체가 < oepratoar를 기준으로 정렬을 하기 때문이죠.

 

아 또 struct 내에서 operator를 오버로딩 하지 않고 Compare라는 함수를 만들어서 사용할수도 있습니다.

이 때 sort를 사용한다면 똑같이 동일하게 < operator를 기준으로 Compare함수를 정의해줘야 합니다.

 

그러면 Compare함수도 만들어보죠.

#include <iostream>

using namespace std;

bool Compare(string a, string b)
{
    if (a.size() == b.size())
        return a < b;
        
    return a.size() < b.size();
}

int main()
{
    string arr[3] = { "aaa", "bbb", "cc" };
    sort(arr, arr + 3, Compare);
    
    for (string str : arr)
    {
        cout << str << " ";
    }
    
    return 0;
}

 

결과는 잘 나왔습니다.

일단 size를 검색하고 그다음 ASCII코드 순으로 비교합니다.

예를 들어 "aaa"와 "bbb"를 비교할 때 왼쪽에서부터 ASCII코드 순으로 비교하기 때문에

97 98로 비교하기 때문에 "aaa"가 더 작은 숫자로 인식합니다.

그러나 "aaa"와 "cc"를 비교하면 97 99라는 숫자를 비교하기 때문에 "cc"가 더 큰 숫자로 인식하게 됩니다.

그래서 size로 크기를 비교하는 구문을 넣어준 겁니다.

때문에 사이즈 확인 로직을 넣는 것이 중요합니다.

 

그럼 Compare함수는 어찌저찌 이해했으니 struct를 compare 함수를 통해서 정렬하는 코드를 만들어 봅시다.

 

#include <iostream>

using namespace std;

struct Santos
{
    int a, b;
}

bool Compare(Santos A, Santos B)
{
    if (A.a == B.a) return A.b < B.b;
    return A.a < B.a;
}

int main()
{
    Santos sa[3] = { { 1, 2 }, { 1, 3 }, { 0, 4 } };
    sort(sa, sa + 3, Compare());
    for (Santos Sa : sa)
    {
        cout << Sa.a << " : " << Sa.b << '\n';
    }
    
    return 0;
}

1순위로 a를 오름차순 2순위로 b를 오름차순으로 정렬되는 코드입니다.

이제 어느정도 이해가 가셨나요?

ex) 1 < 2 그러면 true니 이대로 => 결과물 1, 2

2 < 1 그러면 false니 서로 바꿔줌 => 결과물 1, 2

 

이래서 오름차순입니다.

 

어우 너무 설명할 게 많은데 일단 너무 길어졌으니 다음포스팅으로 넘어가죠.

이번엔 조금 진지하게 썼네요.

끄틍

'내 개인적인 공부 > 자료구조' 카테고리의 다른 글

priority queue  (0) 2024.04.14
vector에 struct 정렬  (0) 2024.04.14
deque  (0) 2024.04.14
queue  (0) 2024.04.14
stack  (0) 2024.04.14