본문 바로가기
C++, MFC

[C++/MFC] qsort를 이용하여 배열 정렬하기 (int[], CStringArray, CPtrArray)

by dev_drive 2022. 10. 5.
반응형

1. int 배열 정렬

int numArr[10]{ 10, 332, 30, 4, 55, 63, 77, 28, 49, 810 };
qsort (numArr, sizeof(numArr) / sizeof(int), sizeof(int), SortAscending);

 

int SortAscending(const void* n1, const void* n2)
{
	if (*(int*)n1 > *(int*)n2)	return 1;
	else if(*(int*)n1 < *(int*)n2)	return -1;
	else return 0;
}

int SortDescending(const void* n1, const void* n2)
{
	if (*(int*)n1 > *(int*)n2)	return -1;
	else if (*(int*)n1 < *(int*)n2)	return 1;
	else return 0;
}

오름차순 정렬 결과입니다.  내림차순을 적용하려면 qsort를 호출할때 SortDescending을 사용하면 됩니다. 

 

qsort에 사용된 sort함수가 특별한건 아니고 반환하는 값이 음수일 경우 첫번째 요소가 두번째 요소보다 먼저 위치해야된다는 의미이고 양수면 그 반대의 의미입니다.  그리고 0이면 같다는 것이겠죠.

 

 

2. CStringArray 정렬

CStringArray list;
list.Add(_T("123"));
list.Add(_T("20"));
list.Add(_T("45"));
list.Add(_T("1005"));
list.Add(_T("205"));

qsort(list.GetData(), list.GetSize(), sizeof(CString), SortAscending);

 

int SortAscending(const void* p1, const void* p2)
{
	CString* s1 = (CString*)p1;
	CString* s2 = (CString*)p2;

	return _tcscmp(s1->GetBuffer(0), s2->GetBuffer(0));
}

int SortDescending(const void* p1, const void* p2)
{
	CString* s1 = (CString*)p1;
	CString* s2 = (CString*)p2;

	return _tcscmp(s1->GetBuffer(0), s2->GetBuffer(0)) * -1;
}

오름차순 정렬 결과입니다.  하지만 원하는 결과값은 아닌것 같죠..? 

 

이런 결과가 나온 이유를 이해하려면 문자열 비교 함수인 _tcscmp() 함수의 특성 대해 알아야됩니다. 

 

_tcscmp() 함수두 문자열을 비교해서 같으면 0, 다르면 값에 따라 1 또는 -1을 반환하는데 앞에서부터 한자리씩 문자의 아스키코드값을 비교하면서 어떤 문자가 큰지 판단합니다. 

 

1005와 123을 숫자로 비교하면 1005가 크지만 코드 값으로 비교하면 첫번째 1은 똑같고 두번째는 123의 2가 더 크니 123이 더 크다고 판단합니다.  그리고 20과 205는 끝에 널문자(\0)가 있고 이 문자는 아스키 코드상 0이라 가장 작은 값이기 때문에 20이 205보다 작은 것으로 판단합니다.  즉 앞부분이 같다면 짧은 문자열을 더 작다고 판단하게 되는것이죠. 

 

하지만 문자열에 숫자만 있으란 법이 없기때문에 정답은 없습니다.  

데이터가 숫자 위주면 _ttoi() 함수를 이용해서 CString을 int로 변환해서 위에 int 정렬하듯이 하면 될것이고

문자열 길이라든지 원하는 정렬 방법이 있다면 _tcscmp를 사용하지 않고 return값에 따라 정렬이 된다는 것을 이해하고 구현하면 될 것 같습니다.

 

 

3. CPtrArray 정렬

class CMyItem
{
public:
	CMyItem() {}
	virtual ~CMyItem() {}

	int m_nId;
	CString m_sName;
};

 

CPtrArray CItemArray;
for (int i = 0; i < 5; i++)
{
	CMyItem* newItem = new CMyItem;
	newItem->m_nId = i + 1;
	newItem->m_sName.Format(_T("이름 %d"), i + 1); 
	CItemArray.Add(newItem);
}

qsort(CItemArray.GetData(), CItemArray.GetSize(), sizeof(CMyItem*), SortDescending);

for (int i = 0; i < CItemArray.GetCount(); i++)
{
	CMyItem* myItem = (CMyItem*)CItemArray.GetAt(i);
	delete myItem;
}

 

int SortAscending(const void* p1, const void* p2)
{
	CMyItem** item1 = (CMyItem**)p1;
	CMyItem** item2 = (CMyItem**)p2;

	if ((*item1)->m_nId > (*item2)->m_nId)		return 1;
	else if((*item1)->m_nId < (*item2)->m_nId)	return -1;
	else return 0;
}

int SortDescending(const void* p1, const void* p2)
{
	CMyItem** item1 = (CMyItem**)p1;
	CMyItem** item2 = (CMyItem**)p2;

	if ((*item1)->m_nId > (*item2)->m_nId) 		return - 1;
	else if((*item1)->m_nId < (*item2)->m_nId) 	return 1;
	else return 0;
}

CPtrArray는 더블 포인터로 클래스 받아온 다음에 마찬가지로 원하는 정렬 조건으로 정렬하면 되겠습니다.  

 

반응형

댓글