冬期講習 2026-2027、募集中。総復習は売りません。90分×完全1対1で、穴だけを塞ぎます 詳しく →
電話 0422-27-7828チャットで質問無料相談を予約

武蔵野個別指導塾の特徴

高校情報I 配列の走査と更新—最大値と位置を分けて記録し同点の規則を決める|武蔵野個別指導塾

学習のイメージ写真 武蔵野個別指導塾
X LINE Facebook

観測値の最大と最小を探し、同点のときに先頭を残す条件と末尾へ更新する条件を比べて位置を追えます。

よくあるのは、観測値の最大値を求めた高校生が、その値を最大の位置として答える場面です。観測値が 9 であっても、その観測が並びの 9 番目とは限りません。値と位置を別の情報として持ち、同じ最大値が複数あるときの選び方まで決めると、答えの意味がはっきりします。

何を返すかを先に決める

問いには、配列を順に読みながら変数の変化を追う型、最大値とその位置を返す手順を作る型、同点の規則を変えて比較する型があります。どの型でも、入力の並び、添字の起点、答えの形を先に確認します。ここでは Python のリストを配列として使い、添字は先頭を 0 とします。値は比較できる整数で、配列は空ではないという前提です。

出力は「最大値、添字」の順の組です。同じ最大値が複数あれば、先頭優先では小さい添字、末尾優先では大きい添字を選びます。最小値を扱うときも組の順序は同じです。位置は要素そのものではなく、配列の中の住所です。見つからない場合を返す探索とは異なり、空でない入力の最大値は必ず存在します。

問題の場面に戻すと、添字 1 の観測値が 9 なら、返す組は (9, 1) です。人に何番目かを伝える場合は、0 始まりの添字に 1 を足して「2 番目」と言い換えます。添字と番目を混ぜると、値が正しくても位置の説明がずれます。

候補の位置を持ち続ける

走査とは、要素を一定の順序で調べることです。初めに添字 0 を候補の位置にします。次の要素から順に候補と比べ、より大きければ候補の位置をその添字に更新します。候補の値は、その位置から取り出せます。値と位置を別々の変数にする方法もありますが、片方だけを更新すると両者が食い違うため、ここでは位置を基準にします。

図1 候補の位置から対応する値を取り出す関係

図1のように、候補位置 1 は値 9 を指します。候補の位置を 9 とするのではありません。先頭優先なら、新しい値が候補より大きいときだけ更新します。同値では古い位置を残すため、同じ値の最初の位置が残ります。末尾優先なら同値でも更新し、後に現れた位置へ移します。

初期値を 0 という数値の最大候補にする方法には注意が必要です。入力が負の数ばかりなら、配列に存在しない 0 が最大値として残りかねません。先頭要素を候補にすれば、負の数でも候補は必ず実際の要素です。その代わり、空配列には先頭要素がないので、この手順の前提から除きます。

基本例題:観測値の最大位置

観測値を [4, 9, 6, 9] とします。最大値とその 0 始まりの位置を組で返し、同点なら先頭を優先してください。配列は空でなく、値は整数です。手で確認すると最大値は 9、該当する添字は 1 と 3 なので、期待する組は (9, 1) です。

図2 観測値を順に比べて先頭の最大位置を残す

図2のように、候補位置は最初 0、値 9 を見たとき 1 に変わります。6 は 9 より小さく、最後の 9 は同値なので、どちらも位置 1 を維持します。次の関数は最大と最小、先頭優先と末尾優先を選べます。通常の入力は空でない整数のリスト、オプションは真偽値とします。空なら ValueError を出し、値を作って返しません。

def extremum(a, last=False, minimum=False):
    if not a:
        raise ValueError('empty')
    p = 0
    for i in range(1, len(a)):
        better = a[i] < a[p] if minimum else a[i] > a[p]
        if better or (last and a[i] == a[p]):
            p = i
    return a[p], p

関数の1行目は入力と規則を受け取ります。last が False なら先頭、True なら末尾を優先し、minimum が False なら最大、True なら最小です。空を調べる行の次は、空の場合に処理を中断する行です。p に 0 を入れる行で、最初の要素を候補にします。for の行は添字 1 から長さの直前までを順に扱います。長さが 1 なら反復は 0 回です。

better を作る行は、最小を求めるときは小さいか、そうでなければ大きいかを調べます。if の行は、よりよい値か、末尾優先かつ同値かを判断します。p を変える行は、その条件が真のときに現在の位置を新しい候補にします。最後の行は候補位置から値を取り、値と位置を組にして返します。入力リスト自体の要素は書き換えません。

この例の処理表は次のとおりです。比較は候補値と現在値の大小を調べることを意味し、同値判定はその説明から分けます。

時点      現在の添字  現在値  候補位置  候補値
初期化    なし        なし    0         4
比較後    1           9       1         9
比較後    2           6       1         9
比較後    3           9       1         9

Python 3.14.8 でこの関数を実行し、入力 [4, 9, 6, 9]、last と minimum はともに False とした結果は (9, 1) でした。期待した組と一致します。位置 1 に戻ると値は 9 で、ほかの 4、6、9 も 9 以下です。比較は3回で、要素数から1を引いた回数です。

同点と最小値で条件を変える

同じ観測値 [4, 9, 6, 9] で末尾優先にすると、最後の 9 でも候補を更新します。期待値は (9, 3)、実行結果も (9, 3) です。位置 3 の値が 9 で、位置 1 にも 9 がありますが、より後ろはありません。更新条件の同値部分が結果を変えたと説明できます。

次は最小値です。[7, 2, 2, 5] で minimum を True にすると、小さい値を候補にします。先頭優先なら期待値と実行結果は (2, 1)、末尾優先ならどちらも (2, 2) です。位置 1 と 2 の値はともに 2 で、7 と 5 はそれ以上です。最大を最小に変えるには大小の向きだけでなく、同値で更新する規則も残す必要があります。

端の条件も調べます。[8] では反復がなく、期待値と実行結果は (8, 0) です。[-3, -8, -3] の最大を先頭優先で求めると、期待値と実行結果は (-3, 0) です。負数の並びでも候補は要素に由来します。いずれも返った位置の値が返った値と一致します。

なぜ一般に成立するのでしょうか。初期化後、調べた範囲は先頭だけで、p はその範囲の最大位置です。各反復の前に、p が調査済み範囲の最大位置であり、同値の優先規則も守ると仮定します。新しい値が大きければその位置に変え、同値なら規則に従い、小さければ維持します。すると調査済みの範囲が1要素増えても条件は保たれます。添字は有限の範囲を1ずつ進むため反復は終わり、その時点で全要素を調べ終えています。最小値は比較の向きを反転して同様に考えます。実行例は実装の不具合を見つける手掛かりですが、この説明の代わりに一般的な正しさを保証するものではありません。

値を位置にしてしまう誤り

基本例で、候補を更新する際に p に現在値 9 を入れるとどうなるでしょうか。位置として使えるのは 0 から 3 です。9 は範囲外なので、次の比較で a[p] を読もうとすると IndexError が出ます。結果の 9 をそのまま位置として返すだけの誤りなら例外が出ず、値は正しいのに位置が誤ることもあります。

図3 値を位置に入れた誤りと添字への修正

図3のように、現在値 9 と現在の添字 1 の役割を分けます。誤った代入を p = i に修正し、同じ入力を再実行すると (9, 1) です。さらに末尾優先で (9, 3) になることも確認し、修正が同点の仕様を壊していないか調べます。単に例外が消えたことではなく、返された位置が実際に最大値を指し、優先規則も満たすことが合格条件です。

失敗と例外をどう試すか

入力が前提外なら、誤った組を正常な答えとして扱わないことが必要です。空リストは明示的に ValueError とします。空以外の壊れた入力には、関数の入口で型や要素を検査する追加設計が必要です。上の関数は空の検査以外を実装していないので、文字や None、真偽値、比較できない要素が混じる入力を受け付ける設計とは考えません。Python では True も整数と似た振る舞いをするため、真偽値を除外したい場合は明示的な型検査が必要です。

失敗試験を正常試験と同じ重さで設計するには、空、型違い、混在、規則指定の型違い、外部入力の途中切断、取得失敗、時間切れ、巨大入力、途中の予期しない例外、誤った位置の出力をそれぞれ区別します。この小さな関数は通信や外部ツールを呼ばず、時間制限も設定していません。したがって時間切れや取得失敗をこの関数が検知したと主張せず、呼出し側の責任として設計します。

たとえば呼出し側が観測値を外部から受け取るなら、取得失敗と空の観測結果を別に報告し、途中まで受け取ったデータを完成した配列として渡さないようにします。時間切れの際も古い結果を今回の最大値として表示しない仕様にします。取得処理を模した部品が例外を出す試験と、時間切れを返す試験を用意し、関数が呼ばれないことと結果が保存されないことを検証します。これは外部処理を持つシステムの設計案であり、ここで実行した関数単体の結果ではありません。

検査する入力の上限を設ける場合は、上限以下の長い配列で終了と正しい位置を調べ、上限を超える入力では検査側が拒否することを調べます。途中で例外が起きた場合は、部分的な候補を完成結果として返さず失敗と記録します。試験では、意図的に比較時に例外を出す値を使うか、比較処理を差し替えられる設計にして発生箇所を確かめます。環境が停止した場合の再実行も、最初から同じ入力と規則で行い、途中候補を引き継ぐならその保存手順を別途定めます。

次の失敗試験は、上の関数について実際に Python 3.14.8 で確認したものです。空リストでは期待どおり ValueError とメッセージ empty が出ます。混在する整数と文字列 [1, ‘x’] は比較時に TypeError となります。None は長さを調べる前の空判定で ValueError となり、空リストと区別されません。文字列 ‘abc’ はこの実装では拒否されず (‘c’, 2) を返します。これらは入力検証が不十分であることを示す結果で、壊れた入力を安全に受け付ける保証ではありません。

さらに [True, 2] は (2, 1)、last に文字列 ‘yes’ を渡した [4, 4] は (4, 1) を返します。どちらも本来の入力条件に反しますが、Python の扱いによって処理が進みます。入力検査を追加するなら、リストか、各要素が真偽値ではない整数か、両オプションが真偽値かを先に調べ、違反を明確な例外にします。これらの試験は実装の現在の挙動を示すもので、検査追加後には拒否されることを再試験します。

練習:先に自分で位置を追う

以下は互いに独立した問題です。いずれも整数の空でない配列を使い、添字は 0 始まり、答えは値と添字の組とします。

  1. 記録 [5, 1, 5] の最大値を末尾優先で求めてください。
  2. 記録 [6, 3, 6, 2] の最小値を先頭優先で求めてください。
  3. 記録 [2, 7, 7, 1] の最大値を先頭優先で求めてください。
  4. 記録 [9, 4, 4] の最小値を末尾優先で求めてください。
  5. 記録 [12] の最大値を先頭優先で求め、反復回数も答えてください。

練習の答えと照合

  1. (5, 2) です。候補位置は 0、0、2 と進みます。最後の 5 は位置 0 と同値なので、末尾優先により位置 2 に移します。位置 2 の値は 5 で、残る値も 5 以下です。実行結果は (5, 2) です。
  2. (2, 3) です。候補位置は 0、1、1、3 です。位置 3 の値 2 は 6、3、6 のいずれよりも小さく、実行結果も (2, 3) です。
  3. (7, 1) です。候補位置は 0、1、1、1 です。位置 2 の 7 では同値のため更新しません。位置 1 の値は 7 で、最大値の位置 1 と 2 のうち先頭です。実行結果も (7, 1) です。
  4. (4, 2) です。候補位置は 0、1、2 です。位置 1 と 2 に最小値 4 があり、後ろの位置 2 を選びます。実行結果も (4, 2) です。
  5. (12, 0)、反復 0 回です。先頭を候補にした時点で全要素を調べています。位置 0 の値は 12 で、実行結果も (12, 0) です。

これらの答えは値の大小だけでなく、選んだ位置の値と優先規則に戻して照合しました。反復中に候補を更新しなかった行も記録すると、同点の規則を読み違えた箇所が見えます。

覚えておきたいこと

手が止まったときに見る場所

位置だけがずれるときは、候補を更新する行に値と添字のどちらを代入したか、処理表の1行ずつを指で追って説明してみてください。同点の例だけがずれるときは、比較に等号を含めるか、同値のとき候補が残るかを確認します。値もずれるときは、最初の候補が配列の要素か、最後の添字まで比較しているかを点検します。

個別指導で確かめるなら、まず本人に「候補位置が指す値」と「今見ている値」を別々に示してもらい、次に同点の行で更新する理由を言葉にしてもらいます。最後に空入力や失敗を正常な組と混同していないかを確認します。最大値とその位置は、同じ記録を違う角度から表す2つの答えです。

読んで終わりにするか、ここから変えるか。

武蔵境駅徒歩30秒、講師1人に生徒1人の完全1対1。授業のあいだ、先生は隣を離れません。いまの詰まりを、無料相談でそのまま話してください。

まず15分だけ電話で話したい方は、無料電話相談(15分)から。塾からお電話を差し上げます。

本気になった日が、入塾の日。

お子様の教育、迷ったら「丸投げ」してください。必ず、期待以上の結果で返します。武蔵野で育む、武蔵境で学ぶ。

電話は年中無休。365日、24時間、お電話可能。

チャットで質問チャット
無料相談を予約する 電話 0422-27-7828電話 LINE チャット
で質問