qsortの[compare]をC++として使用するには

[戻る]
クリリン 2002/02/18(月) 17:52:55
いつも質問ばかりしてすいません。
早速質問します。
CArrayを使って構造体を配列にしておりまして、その配列を「qsort」を使ってクイックソート
したいのです。
ですが、「qsort」はCで記述されている為か、「compare」を
int Cxxx::f_Compare(const void *pFirst, const void *pSecond){
  …比較内容
}
のようなクラスとしてコンパイルしたとき、
{'qsort' : 4 番目の引数を 'int (const void *,const void *)' から 'int (__cdecl 
*)(const void *,const void *)' に変換できません。}
のエラーメッセージが出ます。
やはり、「compare」および構造体はクラスの外に記述しないといけないのでしょうか?

ちなみに、ソートのコーディングは
void Cxxx::DataSort(){
  int DataCount = m_DataArray.GetSize();
  
  qsort(&m_DataArray, DataCount, sizeof(Data), f_Compare);
}
と記述し、「m_DataArray」はCArray宣言の変数、「Data」は構造体です。

皆様方は動的配列のクイックソートはどのようにされているのでしょうか?
ご教授願います。

kazuma 2002/02/18(月) 18:13:39
> やはり、「compare」および構造体はクラスの外に記述しないといけないのでしょうか?

compare を static なメンバ関数にすればできます。

しかしそれ以前に、qsort の一番目の引数に CArray のポインタを渡してもだめです。
CArray::GetData の戻り値を渡せばできるかもしれませんが、
試したことないのでうまくいくかはわかりません。

それよりも CArray ではなくて STL の vector を使うとソートも簡単にできますよ。

クリリン 2002/02/18(月) 18:55:46
>compare を static なメンバ関数
はどう記述したらいいのでしょうか?

YuO [E-Mail] 2002/02/18(月) 20:05:12
……とりあえず,MFCの前にC++を勉強すべきかと……。

class foo {
public:
static int func (const void * , const void *);
};

クリリン 2002/02/18(月) 22:48:47
早速の回答、ありがとうございます。
>static int func (const void * , const void *);
static は定義のところだけでいいのですね!
私は関数側にも記述しないといけないと思い、悩んでました。すいません m(__)m
で、検討の結果、STL を使ってみようと思います。
本当は、CArray を使ってクイックソートをやりたかったのですが、
勉強時間と納期が無い為に、とりあえず、妥協します。
とりあえず、STL が使えるようになったら、解決いたしますので、
それまで、お付き合いください。
よろしく御願いします。

YuO [E-Mail] 2002/02/19(火) 03:42:05
sort, partial_sort, nth_element, stable_sort, partition, stable_partition
必要に応じて選んで下さい。
・stable_sort
一般的なソート。安定。
・sort
一般的なソート。不安定。
・partial_sort
先頭から指定位置までが,小さい(大きいetc)方から並んでいるようにする。不安定。
指定位置より後ろはソートされていない。
・nth_element
指定位置より前に,より小さい(大きいetc)ものが,後により大きい(小さいetc)ものが並
んでいるようにする。不安定。指定位置より前および後ろはソートされていない。
・stable_partition
ある条件を満たす要素を先頭に持ってくる。安定。
・partition
不安定なstable_partition#後ろ三つはソートとはちょっと違うけどソートの目的次第で
はこれらで代用可能
下の方が通常速いです。
あと,(完全に)ソートしたコンテナへの代入はpush_backの後ソートよりも,
lower_boundとかupper_boundとinsertを組み合わせた方が効率的です。

クリリン 2002/02/19(火) 17:44:20
見事に、配列に格納、ソート、データ所得ができました!
ですが、データの件数を取得することができません。
やはり、
for( i = m_Data.begin(), i != m_Data.end(), i++ ) DataCount++;
みたいにしないといけないのでしょうか?
それとも、メソッドがあるのでしょうか?
申し訳ありませんが、教えてください。

YuO [E-Mail] 2002/02/19(火) 17:49:45
m_Data.size()
で一発ですよ。

クリリン 2002/02/19(火) 17:58:47
[[解決]]
できました。あと、出来ているのですが、こういうコードを記述しているのですが、

int CxxxData::gDataNo(int &Index)
{
  vector<Data>::iterator p;
  p = m_Data.begin();        // 先頭ポインタの取得
  p = p + Index;             // ポインタの移動
  return ( p->GetDataNo() ); // データ取得
}

Dataクラスの public のところに
int GetDataNo(){ return (DataNo); } // データ番号

と記述していますが、やはり、iteratorを使って取得しないと無理ですか?
もっとすっきりした方法は無いのでしょうか?

差支えが無ければ、教えてください。


とりあえず、解決としておきます・・・

クリリン 2002/02/19(火) 18:01:22
>出来ているのですが、こういうコードを記述しているのですが、
ちょっと、文章がおかしかったですね・・・すいません。
―>出来ているのですが、こういうコードの記述をしています。
に訂正。

kazuma 2002/02/19(火) 22:57:38
vector にも operator [] が定義されているので、
return m_Data[index].GetDataNo();
と出来ます。at() ってのもあります。
(index の範囲はチェックしたほうがいいと思います。)

CxxxData::gDataNo の引数 Index を参照にする必要があるんでしょうか?

クリリン 2002/02/21(木) 11:00:50
kazuma さん、ありがとうございます。
すっきりしたコードが書くことができました。
>CxxxData::gDataNo の引数 Index を参照にする必要があるんでしょうか?
リストビューにfor文を使って、格納するのに必要なのです・・・よって、Indexの範囲もfor文
の前にチェックしているので大丈夫です。
ご心配をかけてすいません。

古いスレッドには追加発言できません。