MSDNライブラリを見ていたら「qsort_s」という関数を発見。
クイックソート関数qsortは昔からあったが、知らないうちにqsort_sができていた。これら2つは何が違うかと言うと...比較用関数に独自パラメータ(context)を渡せるかどうか。qsortはパラメータを渡せないため、単純なソートには使えるものの実際問題として使い物にならない関数だった。
そのため今まではクイックソートが必要な時はqsortのソースコードを元にパラメータが利用できる関数を作成しなければいけなかった。qsort_sのおかげでその手間が省けるようになった。ここではこのqsort_sを利用してCStringArrayの文字列をソートする。
#include "atlstr.h"
#include "atlcoll.h"
class CDnpSortString
{
//比較関数
static int SortStringArrayCompare(void* pContext,const void* pData1,const void* pData2)
{
if(pContext == NULL)
return 0;
return ((CDnpSortString*)pContext)->SortStringArrayCompare_(pData1,pData2);
}
//昇順か降順か
bool _bABC;
//ソート対象
CAtlArray<CAtlString>* _pastrText;
public:
CDnpSortString()
{
_bABC = true;
_pastrText = NULL;
}
//比較関数の実体
//外部からは呼ばないこと!
int SortStringArrayCompare_(const void* pData1,const void* pData2)
{
size_t nSize;
if(_pastrText == NULL)
return 0;
nSize = _pastrText->GetCount();
if(*(size_t*)pData1 >= nSize || *(size_t*)pData2 >= nSize)
return 0;
if(_bABC)
return ::_tcscmp((*_pastrText)[*(size_t*)pData1],(*_pastrText)[*(size_t*)pData2]);
else
return ::_tcscmp((*_pastrText)[*(size_t*)pData2],(*_pastrText)[*(size_t*)pData1]);
}
//
// CStringArrayのソート
//
bool SortStringArray(CAtlArray<CAtlString>& astrText,bool bABC)
{
size_t i;
size_t nSize;
size_t* pnIndex;
CAtlArray<CAtlString> astrTmp;
nSize = astrText.GetCount();
if(nSize == 0)
return false;
pnIndex = new size_t[nSize];
if(pnIndex == NULL)
return false;
astrTmp.SetCount(nSize);
for(i = 0; i < nSize; i++)
{
pnIndex[i] = i;
astrTmp[i] = astrText[i];
}
_bABC = bABC;
_pastrText = &astrText;
::qsort_s(pnIndex,nSize,sizeof(size_t),SortStringArrayCompare,this);
_pastrText = NULL;
for(i = 0; i < nSize; i++)
astrText[i] = astrTmp[pnIndex[i]];
delete pnIndex;
return true;
}
};
void Test(void)
{
///////////////////
//ダミーデータ用意
//
CAtlArray<CAtlString> astrFiles;
astrFiles.Add(_T("abc"));
astrFiles.Add(_T("aac"));
astrFiles.Add(_T("aec"));
astrFiles.Add(_T("bbc"));
///////////////////
//ソート
//
CDnpSortString cSort;
cSort.SortStringArray(astrFiles,false);
///////////////////
//結果表示
//
size_t i;
size_t nSize;
CAtlString strMessage;
nSize = astrFiles.GetCount();
for(i = 0; i < nSize; i++)
{
strMessage += astrFiles[i];
strMessage += _T("\n");
}
::MessageBox(NULL,strMessage,_T(""),MB_OK);
}
