C++ のループ内の値の変更を比較するのは良い形式ですか?
-
12-09-2019 - |
質問
皆さんの中には、すべて同じプログラムに関する私の最近の投稿を見たことがある人もいるでしょう。私はそれに関して常に問題に遭遇しています。繰り返します:まだ学習中、あまり高度ではない、ポインタをよく理解していない、クラスを受講していない、OOP の概念をまったく理解していないなど。このコードは、2 つのソートされたベクトル、farray と sarray を 1 つのソートされたベクトルにマージするだけです。少なくとも、そうであることを願っています。教えて:
//int num is to find the size of the original vector and
//build up farray and sarray; not used in the merge process
int num = original.size()
std::vector<int> final;
std::vector<int>::iterator it = farray.begin();
std::vector<int>::iterator iter = sarray.begin();
//farray.size() == (0 thru (num / 2))
//sarray.size() == ((num / 2) thru num)
for (;it != farray.end() && iter != sarray.end();) {
if (*it > *iter) {
final.push_back(*it);
it++;
}
else
{
final.push_back(*iter);
iter++;
}
if (it == farray.end()) {
for (int i = 0; iter < sarray.end(); i++) {
final.push_back(*iter);
}
}
if (iter == sarray.end()) {
for (int i = 0; it < farray.end(); i++) {
final.push_back(*iter);
}
}
}
マージ・ソート関数のマージ部分を書き直して、機能するようにしました。実はこのコードに関していくつか質問があります。
- for ループが次のパスでステートメントを変更する可能性がある場合、最後の 2 つの if ステートメントを std::vector::iterators it && iter と比較するのは良い形式ですか?
- このループの最後のパスで iter と it の値が変更され、コードが台無しになりますか?最後の if ステートメントを *it と *iter の比較の前に置きますか?
- end() メンバー関数は、それを呼び出しているものの最後の値を参照しますか?なんとなくそれを超えて伸びそうな気がします。
編集:すべての返信には明日返信させていただきますので、さらに詳しく知りたい場合は、そのときにもう一度確認してください。もう真夜中を過ぎました。おやすみ。
解決
1。これは、ループ条件と同じコンテナからあるイテレータを比較するの罰金ですが、あなたはループのためのif文やループ自体のための身体の増分部分のいずれか1つのまたは他のイテレータを移動している場合にのみ意味があります。この中でループのために、あなたはiter
に対するsarray.end()
を比較したが、forループiter
を変更することはありません。これはどちらか何回の反復または終了することはありませんforループがないことを意味します。また、あなたはおそらく!=
を使用し、比較のために<
ないようにしたいです。すべてのイテレータのための==
と!=
仕事、<
はしていません。
for (int i = 0; iter != sarray.end(); i++) {
final.push_back(*iter);
}
あなたはループを開始したいiter
を開始するとして、あなたはこのような何かをしたいことがあり
for (; iter != sarray.end(); ++iter) {
final.push_back(*iter);
}
(私たちはすべてではないですが!)あなたはまだ学んでいるとしては、このようなアルゴリズムを介して動作するために、おそらく有益ですが、あなたはおそらく、あなたが何をしたいんstd::merge
に注意する必要があります。
std::merge( farray.begin(), farray.end(), sarray.begin(), sarray.end(), std::back_inserter( final ) );
(あなたは#include <iterator>
と<algorithm>
する必要があります。)
2。私はさておき1に、ループのために、後にポイントをロジックを無効forループの外でそれをITERインクリメントまたは表示されません。
3。コンテナの最後過去1にend()
ポイント、あなたがループ終了チェックのためにそれを使用することができますが、「==
」に「.end()
」でイテレータを逆参照しようとはならないようにします。
他のヒント
アルゴリズムの実装はチェックしませんでした。次の 3 つの質問についてのみ言及します。
- イテレータは、コンテナの値へのポインタによく似ています。これは、for ループで size_t i を使用してから ++i を使用するのとまったく同じです。farray[i] と sarray[i] を比較するのは問題があると思いますか?おそらくそうではないので、大丈夫です。
- ここのコードで行っていることは、 *it と *iter の値を読み取るだけで、実際には値を変更していないため、値は変更されないということです。
- end() が無効な場所を指しています。最後の値を指すのではなく、「その後」を指します。これは "NULL" のようなものなので、 if(iter == sarray.end()) が true の場合、 *iter と記述するとクラッシュします。これは、 end() と等しいイテレータを逆参照できないためです。
いくつかの一般的なアドバイス:あなたは変数名を考える必要があります。あなたのイテレータを呼び出す「は」と「ITERは、」いくつかの点であなたを混乱させるために起こっています。あなたが密接に見れば実際に、それはすでに持っています。 「farray」と「sarrayは、」どのように「fiter」と「ピンチ・シッター」について意味のある名前、している場合。
また、マージソートが何をしているかによってだと思います。これらの最後の二つのブロックは、ちょうど左のいくつかのものを持っている方イテレータ「ドレイン」することがあります。そこで、彼らは最初のループである必要はありません。
私は多分としてそれを記述します(擬似コード):
while not (list1.empty and list2.empty):
if list1.empty:
result.push(list2.pop)
else if list2.empty:
result.push(list1.pop)
else if list1.top > list2.top:
result.push(list2.pop)
else:
result.push(list1.pop)
または多少さび貨物culted C ++での
std::vector<int>::iterator fiter = farray.begin();
std::vector<int>::iterator siter = sarray.begin();
while (fiter != farray.end() || siter != sarray.end()) {
if (fiter == farray.end()) final.push_back(*siter++);
else if (siter == sarray.end()) final.push_back(*fiter++);
else if (*fiter > *siter) final.push_back(*siter++);
else final.push_back(*siter++);
}
ここで考えるべきことがいくつかあります。
まず、2 つの範囲を結合する場合は、 std::マージ 自分で開発するのではなく、関数を作成してください。
インデントや中括弧の削除にさまざまなスタイルを使用しているため、コードは少し読みにくくなっています。スタイルを選択し、それに固執します。
for ループの最初の部分は、マージの正しい実装であるようです。
for (;it != farray.end() && iter != sarray.end();) {
if (*it > *iter) {
final.push_back(*it);
it++;
}
else
{
final.push_back(*iter);
iter++;
}
...仕事を完了するために必要なのはこれだけです。
ループの 2 番目の部分にはいくつかの問題があります。
for (;it != farray.end() && iter != sarray.end();) {
: :
if (it == farray.end()) {
for (int i = 0; iter < sarray.end(); i++) {
final.push_back(*iter);
}
}
if (iter == sarray.end()) {
for (int i = 0; it < farray.end(); i++) {
final.push_back(*iter);
}
}
}
まず、for() 条件文は、両方の条件が一致するように記述されています。 it
そして iter
を指してはなりません end()
そうでない場合はループが終了します。それで it
決して指すことはできない sarray.end()
, iter
決して指すことはできない farray.end()
, 、そしてどちらでもない if
ステートメントはいつでも起動できます。どちらもデッド (到達不能) コードです。
しかし、たとえデッドコードではなかったとしても、バグは存在します。の条件式 for(...)
イテレータがコレクションの末尾を指すとループが中断されますが、このイテレータは決して移動されないため、無限ループが発生します。
やはりこの両方とも for(...)
反復子はベクトルの終わりを指すことができないため、 は不要なデッドコードです。
一つの簡単なコメント:なぜwhile (condition)
の代わりfor(; !condition; )
を使用しない
後者の建設が理解し、非標準と難しいです!