もともと、これは合法かどうかを判断する問題でした(英語版ページ113)。当初、エラーの原因はbeg + endがベクトルの範囲を超えたためだと思いました。コンパイル後、エラーは実際には操作+がまったく定義されていなかったことがわかりました。これは、手作業でコーディングしたプログラムの重要性を体現しています。
私の二分中央値の定義は本と同じではなく、本は実際には中央値または2つの中央値の右です。中央値または2つの中央値の左側としてそれを定義するのに問題があります(左側を好むため)。その結果、プログラムの34〜49行目で問題のある議論が発生しました(間違っている、midの定義を変更したくない)。
#include <iostream>
#include <vector>
#include <algorithm>
using std::cin;
using std::cout;
using std::cerr;
using std::endl;
using std::vector;
using std::sort;
int main()
{
vector<int> vint;
int i;
int seek;
cout << "Please input the number you seek:" << endl;
cin >> seek;
cout << "Please input numbers from where you want to seek a certain number:" << endl;
while (cin >> i)
vint.push_back(i);
sort(vint.begin(),vint.end());
// The next three lines are used for test in terms of the numbers after sorting.
cout << endl;
for (auto c : vint) cout << c << " "; // show the contents of 'vint'
cout << endl;
auto beg = vint.cbegin();
auto end = vint.cend(); // Remember that 'end' is one off the end.
auto mid = beg + (end - beg + 1) / 2 - 1; // 'mid' is at the middle or the first (left) one of the two middle ones.
cout << beg - vint.cbegin() << " " << mid - vint.cbegin() << " " << end - vint.cbegin() << endl;
cout << "*mid= " << *mid << endl;
while (mid != end && *mid != seek)
{
// This 'if' aims to move 'mid' to the next place as when there are only 2 elements, 'mid' remains still.
if (end - mid != 2)
{
if (seek < *mid) end = mid;
else beg = mid + 1;
mid = beg + (end - beg + 1) / 2 - 1;
}
else
{
if (*(mid + 1) == seek) // move 'mid' to the next place
mid += 1;
else
{
cerr << "Sorry, there is no " << seek << "." << endl; // to indicate there's no that number
return -1;
}
}
// The next two lines are used for test in terms of the current place and value of 'mid'.
cout << beg - vint.cbegin() << " " << mid - vint.cbegin() << " " << end - vint.cbegin() << endl;
cout << "*mid= " << *mid << endl;
}
// Check whether the one we find is the first of all. If not, move to the number to its left.
while (*(mid - 1) == seek && (mid - vint.cbegin()) != 0)
mid -= 1;
// The next line is used for test in terms of the final place and value of 'mid'.
cout << "*mid, &mid= " << *mid << "," << mid - vint.begin() << '\n' << endl;
// The place needs to plus one as the place in vector begins at 0, while we need it at 1.
cout << "The number " << seek << " is in No." << mid - vint.cbegin() + 1 << " place." << endl;
return 0;
}
ここにいくつかの間違った経験があります:
38行目でmidを再定義するのを忘れました
実際、これは一貫性のない思考の問題です。whileループの2回目のラウンドに入るときは、物乞い、中間、および終了のすべてを準備する必要があります。(識字の問題)
II Lines 33-49は分類と議論を忘れている
プログラムにはまだ問題があるので、ドラフトペーパーに状況を記載しました。2つの値の範囲内でロックすると、midは同じ位置に留まり、動かなくなる(静止したままになる)ため、実験中にときどき致命的な状態に陥ることがあります。サイクル。したがって、ifステートメントでパッチを適用しました。
ただし、プログラムにはまだ問題があります!!!
III 42行目での++の誤った使用
この問題の発見は、中間結論を出力する中間テストの恩恵を受け、1つのテストで、物乞い、中間、および終了位置が6 6 8から6 8 8に直接ジャンプすることがわかりました。奇妙なことですが、mid + = 1であることは明らかです。なぜ、2つの場所を一度に取得するのでしょうか。
調べたところ、if文で++の使い方が間違っていたことがわかり(これは間違いで印象的です)、判決文でしたが、中段は確かに変わりました。
(実際には、C ++ Primer 4.5のインクリメント演算子とデクリメント演算子で詳細な説明があります。)
IV行55の誤った使用-
同様に、-でも動作します。
Vライン60の出力は+1を忘れます
これも非常に深刻な問題です。理由は、ベクターの位置が0から始まりますが、1からカウントを開始するため、mid-vint.begin()によってカウントされる位置が1悪くなり、結果が間違っているためです。(実験的な中間データからも問題が見つかりました)
結論
1.もっと考えることは有益です。バグを見つけるまでに少し時間がかかりましたが、改善のプロセスでもありました。
2.論理的リテラシーは非常に重要です。構造は明確で無秩序でない必要があります。そうでない場合、頭の中にあるものはプログラムに反映されません。
3.中間結論の出力を最大限に活用します。これは、特定のパラメータが予想とは異なる現象に対処するための適切な薬を処方するための適切なエラーメッセージです。同時に、いくつかの実験により、エラーを指摘できるルールをまとめることができます。
4.概念は明確である必要があります。C ++ Primerの本にはまだ多くの概念分析がありますが、これを完全に理解し、記憶することで、コンパイラが検出できない致命的なミスを犯さないようにすることができます(++や--hereなど)。
こちらもご覧ください
テディヴァンジェリーのナビゲーションページ
[C ++ Primer(5th Edition)Exercise]演習プログラム-第3章(第3章)