반응형

What is selection sort?

총 N개의 value 중에서 j가 0 부터 N - 2 까지

  1. minimum을 찾고

  2. j와 min을 swap 해주고 j++ 후 '1.'부터 반복.

 

매우 간단한 소팅으로 눈으로 보는 편이 빠르다. {3, 5, 6, 1, 2} 라는 array를 정렬하게 되면,

3 5 6 1 2
1 5 6 3 2
1 2 6 3 5
1 2 3 6 5
1 2 3 5 6

앞에서부터 순서대로 정렬(빨간색은 정렬 완료를 의미)되는 것을 확인할 수 있습니다.

void select_sort(int *a, int N)
{
	int min, min_idx;
	int x, y;

	for (y = 0; y < N - 1; y++)
	{
		min_idx = y;
		min = a[y];

		for (x = y + 1; x < N; x++)
		{
			if (min > a[x])
			{
				min = a[x];
				min_idx = x;
			}
		}

		a[min_idx] = a[y];
		a[y] = min;
	}
}

 

 

여기서 끝나면 재미가 없기 때문에 generalized version을 만들 것입니다.

gen version이란 value의 type에 구애받지 않고 어떤 변수형이든 소팅할 수 있도록 void pointer로 선언하는 것인데,

표로 설명하겠습니다.

1. value init. (int key) void *min = malloc(width)
2. array element (a[y]) *(type)((char*)base + y*width)
3. comparison (min > a[x]) fcmp(min, (char*)base + x*width) > 0
4. assign value (a[y] = min) memcpy((char*)base + y*width, min, width)

오른쪽 코드들은 왼쪽의 의미를 코드로 나타낸 것인데 하나씩 설명해보자면,

첫 번째, 값은 선언할 때 int형으로 선언했던 것을 void pointer로 선언하고 메모리를 할당해준 것입니다.

    * void pointer와 memory alloc에 대해서는 나중 게시글에 업로드

두 번째, 배열 요소를 나타낼 때 포인터의 형태로 나타낸 것인데 간단히 설명하자면 void pointer이기 때문에 사용할 때는 앞에 type casting을 해주는 것입니다.

여기서 모든 변수형에 대한 소팅이라면서 왜 (char*)을 이용했나?라는 의문이 생길 수 있는데, 이는 각 변수들의 size를 알면 간단하게 파악할 수 있습니다. 

char 1 byte
int 4 bytes
float 4 bytes
double 8 bytes

간단하게 4가지 변수형만 가져와서 보자면, 메모리 크기를 1byte기준으로 4배나 8배를 하면 다른 변수형의 크기를 맞추기 쉽기 때문에 char*을 이용하는 것입니다.

세 번째, 기존에 없는 함수 fcmp가 나왔는데 이는 compare function으로 사용자가 직접 정의하는 함수로서 정렬을 할 data의 변수에 따라 customize를 해주면 됩니다. 예를 들어 int형의 data를 다룰 것이라면

int intcmp(const void *a, const void *b)
{
	return (*(int *)a - *(int *)b);
}

을 이용해서 비교해줍니다.

네 번째, value를 pointer의 형태로 주었기 때문에 값을 이동시킬 때는 단순히 '=' 연산자로 가능한 것이 아니라 memory의 copy를 통해서 실현할 수 있기 때문에 memcpy()함수를 사용했습니다.

 

위의 4가지 규칙을 이용해서 selection sort를 generalize 시켜보면,

void gen_select_sort(void *base, size_t nelem, size_t width, int(*fcmp)(const void *, const void *))
{
    void *min;
    int min_idx;
    int x, y;

    min = malloc(width);

    for (y = 0; y < nelem - 1; y++)
    {
        min_idx = y;
        memcpy(min, (char *)base + y*width, width);

        for (x = y + 1; x < nelem; x++)
        {
            if (fcmp(min, (char *)base + x*width) > 0)
            {
                memcpy(min, (char *)base + x*width, width);
                min_idx = x;
            }
        }

        memcpy((char *)base + min_idx*width, (char *)base + y*width, width);
        memcpy((char *)base + y*width, min, width);
    }

    free(min);
}

쉽게 변환이 되었습니다. (memory를 할당해주었기 때문에 꼭 free(min)을 통해서 메모리 free를 시켜줘야 합니다.)

굳이 왜 generalized version을 사용해야 하는가?라는 의문이 생길 수 있는데, 속도면에서는 변수형을 지정해준 sort가 빠르겠지만 실제로 사용할 때 value의 type에 따라 int_selection, string_selection... 모두 만들어주는 것은 매우 비효율적이기 때문에 generalized를 통해 이를 간편하게 만들 수 있습니다.

 

질문은 댓글로

반응형

'Electronic_Engineering > Embedded_Structure' 카테고리의 다른 글

[Sorting] 3. Insertion Sort  (0) 2020.07.02
[Sorting] 2. Bubble Sort  (0) 2020.07.02
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기