-
C++でクイックソートを実装するプログラム|ランダム化で最悪ケースO(n²)を回避
クイックソート(Quick Sort)は「分割統治法(divide-and-conquer)」に基づく高速な整列アルゴリズムです。平均時間計算量は O(n log n) と非常に効率的ですが、ピボットの選び方次第では最悪ケースで O(n²) まで計算量が悪化する可能性があります。 そこで本記事では、乱数を用いてピボットをランダムに選択する「ランダム化クイックソート」をC++で実装し、最悪ケースが発生する確率を大幅に下げる方法を解説します。 アルゴリズム Partition(int a[], int l, int h) 配列 a の範囲 [l, h] を、ピボットより小さいグループと大きい
-
C++による二分探索と線形探索の比較プログラム
コンピュータプログラミングにおいて、特定の要素を探すために二分探索と線形探索(シーケンシャル探索)の2つのアルゴリズムが広く用いられます。二分探索の計算量はO(log n)、線形探索はO(n)であり、データがソート済みであれば二分探索の方が高速です。 アルゴリズムの概要 二分探索 ソート済みの配列に対して、探索範囲を半分ずつ絞り込んでいく手法です。 BinarySearch(配列 arr, 要素数 n, 開始インデックス, 終了インデックス, 反復回数, 探索値) 反復回数をインクリメント 中央インデックス mid = start + (end - start + 1) / 2 を計
-
自己組織化リストを用いて検索を実行するC++プログラム
自己組織化リスト(Self-Organizing List)とは、直前に検索された要素をきっかけに、リスト内の要素の並び順を動的に入れ替えるデータ構造です。探索には逐次探索(線形探索)が用いられ、見つかった要素をリストの先頭へ移動させることで、頻繁に検索される重要なデータほど先頭付近に集まるようにします。この探索手法の計算量は O(n) です。アルゴリズムBegin 関数 SearchItem() を呼び出す。 目的の要素が先頭ノードと一致すれば、結果を出力して終了する。 一致しなければ、リストを順にたどりながら各ノードの値と比較する。 要素が見つかったら、その
-
C++で実装する二分探索アルゴリズム:配列内の特定の検索シーケンスを見つける方法
本プログラムでは、二分探索(バイナリサーチ)を用いて、配列の中に指定した検索シーケンス(連続する値の並び)が存在するかどうかを調べる方法を実装します。二分探索の計算量は O(log n) であり、大規模なデータセットに対しても非常に高速に動作する点が大きな特徴です。 処理の手順と擬似コード 全体の流れは以下のとおりです。 開始 BinarySearch() 関数は、引数としてデータ配列 arr、 要素数 n、探索範囲の start(開始)と end(終了)の インデックス、反復回数カウンタ、および探索対象となる 最初の要素 b[0] を受け取る。 反復カウンタを増やし、探索対象の値を
-
C++で二分探索木の要素を検索するプログラム
本記事では、C++を使って二分探索木(Binary Search Tree、BST)の中に特定の要素が存在するかどうかを検索するプログラムを紹介します。二分探索木は「左の子 < 親 < 右の子」という大小関係を保つデータ構造で、この性質を利用することで効率的な探索が可能です。探索の最悪ケースの計算量はO(n)ですが、平均ケースではO(log n)となり、バランスの取れた木であれば非常に高速に動作します。アルゴリズム探索処理の手順は以下の通りです。Begin 未ソートのデータ配列から、データを1つずつ木に挿入して二分探索木を構築する 探索対象のデータを入力として受け取る
-
【C++】最大ヒープを使ってシーケンス内のk番目に大きい要素を検索するプログラム
このプログラムでは、数列(シーケンス)の中からk番目に大きい要素を取り出す方法を解説します。単純なソートを用いる代わりに最大ヒープ(max-heap)を利用することで、処理時間を大幅に短縮できます。 本プログラムの計算量は O(n + k*log(n)) です。ヒープの構築に O(n)、k回の最大値抽出と再ヒープ化にそれぞれ O(log n) かかるためです。 アルゴリズム 開始 ヒープの最大値をシーケンスの末尾に移動する 残りのシーケンスを再度ヒープ化(heapify)する この処理を「k」回繰り返す 配列の最終状態を出力する k回目の反復でヒープから取り出された最大値を
-
フィボナッチ数を活用した分割統治法でソート済み配列を検索するC++プログラム
このC++プログラムでは、フィボナッチ数を利用した分割統治法(Divide and Conquer)による探索を実装します。フィボナッチ数を使ってデータ配列の中間位置(mid)を計算し、目的の要素を効率よく検索します。この手法の時間計算量はO(log n)です。 フィボナッチ探索とは フィボナッチ探索は、二分探索と同じくソート済み配列を対象とする探索アルゴリズムです。二分探索が配列の中央を基準に検索範囲を半分ずつ絞り込むのに対し、フィボナッチ探索はフィボナッチ数列(0, 1, 1, 2, 3, 5, 8, 13, ...)を利用して比較位置を決定します。除算を使わず加算だけで比較位置を求められ
-
C++で均一二分探索(一様二分探索)を実装する方法とサンプルコード
均一二分探索では、あらかじめ作成しておいたルックアップテーブルを使って二分探索を実装します。シフト演算と加算を繰り返す従来の二分探索に比べ、テーブル参照のほうが高速に行えるため、二分探索の改良版と位置づけられています。この手法の時間計算量は O(log n) です。 均一二分探索の仕組み ポイントとなるのは、配列長 n に対して「n/2, n/4, n/8, …」という差分(デルタ)を格納したテーブルです。探索は必ず配列のほぼ中央から始まり、キーが現在の要素より小さければテーブルの次の差分だけ左へ、大きければ右へ移動します。これにより、ループ内での除算やシフト計算を省き、単純な加減算とテーブル
-
C++で線形探索を使って配列の最小要素を求めるプログラム
本記事では、線形探索(リニアサーチ)の手法を用いて、配列内の最小要素を求めるC++プログラムを紹介します。このプログラムの計算量はO(n)です。線形探索は配列の先頭から順に要素を一つずつ確認していくシンプルなアルゴリズムであり、配列がソートされている必要がないため、どのような配列にも適用できるのが特徴です。 アルゴリズム 開始 データ要素を配列に格納する。 インデックス「0」の値を最小値変数に代入する。 最小値を他のデータ要素と順番に比較する。 最小値がそのインデックスの値より大きい場合は、値を更新する。 最小値を出力する。 終了 サンプルコード #includ
-
C++で二分探索木(BST)を使って配列の最大要素を検索する方法
本記事では、二分探索木(Binary Search Tree:BST)を利用して、配列の中から最大要素を検索するC++プログラムを紹介します。二分探索木の構造的な性質を活かすことで、最大値の探索は右側のノードを辿るだけで完了し、このプログラムの計算量は O(log n) に抑えられます。アルゴリズム開始 与えられたデータ要素をもとに二分探索木を構築する。 ルートポインタを、存在する限り最も右側の子ノードへ辿り続ける。 そのノードのデータ部分を、データ集合の最大要素として出力する。 最大データの深さ(ルートからの距離)を出力する。 終了仕組みのポイント二分探索木では、「左
-
二分探索木を使って配列の最小要素を求めるC++プログラム
本記事では、二分探索木(Binary Search Tree)を活用して、ソートされていない配列の中から最小要素を効率的に見つけるC++プログラムを紹介します。このアプローチの時間計算量は O(log(n)) であり、全要素を順に調べる線形探索の O(n) と比べて、大規模なデータセットで大きな高速化効果が期待できます。アルゴリズムの考え方二分探索木には「左の子ノード < 親ノード < 右の子ノード」という重要な性質があります。そのため、根(ルート)から出発してひたすら左側の子ノードをたどり続ければ、必ず最小値を持つノードに到達できます。処理の手順Begin 与えられた未ソートのデータ配列
-
【C++】二分探索法で配列のピーク要素を効率的に見つける方法
本記事では、C++プログラムにおいて二分探索(バイナリサーチ)のアプローチを用いて、配列内のピーク要素(隣接する要素より大きい値を持つ要素)を一つ見つける方法を解説します。このアルゴリズムは、最初に見つかったピークを結果として返し、計算量はO(log(n))と非常に効率的です。線形探索では最悪の場合O(n)の時間がかかりますが、二分探索を活用することで、探索範囲を半分ずつ絞り込みながら高速にピークを特定できます。アルゴリズムの手順開始 PeakElement()関数は、データ配列「arr」、開始インデックス、終了インデックスを引数として受け取る。 配列の対象範囲の中間インデックス(mi
-
指定した辺の数からランダムな有向非巡回グラフ(DAG)を生成するC++プログラム
この記事では、指定した辺の数 e に基づいて、ランダムな有向非巡回グラフ(DAG:Directed Acyclic Graph) を生成するC++プログラムを紹介します。有向非巡回グラフとは、方向性のある辺(矢印)で頂点同士を結びながらも、どこを起点にしても元の頂点へ戻ってくる閉路(サイクル)が一切存在しないグラフのことです。本プログラムの時間計算量は O(e×v×e) です。 アルゴリズム 開始 関数 GenerateRandomGraphs() は、引数として辺の数 e を受け取る。 2つの乱数の間に接続(辺)を生成する。動作確認用の小さなケースでは、頂点数を20に制限する。
-
指定した次数列からグラフを生成するC++プログラムの実装方法
本記事では、与えられた次数列(degree sequence)をもとに無向グラフを構築するC++プログラムを紹介します。このアルゴリズムの時間計算量は O(v²) であり、自己ループや多重辺は含まれません。生成したグラフの構造は、隣接行列として出力されます。 アルゴリズムの手順 各頂点「i」を走査する外側のループを作成します。 頂点「i」より後ろにある各頂点「j」を調べる内側のループ(ネストされたループ)を作成します。 頂点「i」と頂点「j」の残り次数がどちらも0より大きい場合、両者を結ぶ辺を追加し、それぞれの次数を1ずつ減らします。 PrintMatrix() 関数を呼び出して、隣接行列を
-
C++でインシデンスリストを用いてグラフを表現するプログラムの作り方
本記事では、インシデンスリスト(incidence list)を用いてグラフを表現するC++プログラムを紹介します。このアルゴリズムの計算量はO(e)(eは辺の数)であり、辺の数に比例した時間でグラフの構成を表現できるのが特徴です。 インシデンスリストとは、グラフの各辺に対して、その辺が接続する2つの頂点を記録していくデータ構造です。「頂点を基準に隣接頂点を管理する」隣接リストとは異なり、「辺を基準に両端の頂点を管理する」点が大きな違いです。 アルゴリズム Begin グラフの頂点数「v」と辺数「e」を入力として受け取る 与えられたグラフの「e」組の頂点ペアを edge[e][2]
-
C++で2次元配列(隣接行列)を使ってグラフを表現する方法
本記事では、2次元配列(隣接行列)を使用してグラフを表現するC++プログラムを紹介します。隣接行列を用いることで、グラフの頂点同士の接続関係をシンプルかつ直感的に管理できるようになります。 このアルゴリズムの時間計算量はO(v×v)です(vは頂点数)。メモリ使用量が頂点数の2乗で増加するため、辺の数が比較的多い「密なグラフ」の表現に適した手法と言えます。 隣接行列とは 隣接行列とは、グラフの構造を v×v の正方行列で表現するデータ構造です。頂点 i と頂点 j が直接つながっている場合には行列の (i, j) 成分を 1 とし、つながっていない場合は 0 を格納します。無向グラフの場合、行
-
【C++】行列の転置を求めるプログラムの作り方を解説
この記事では、入力された行列の転置行列(transpose)を求めて出力するC++プログラムを紹介します。転置行列とは、元の行列の行と列を入れ替えた行列のことで、m×n の行列の転置は n×m の行列になります。 転置行列とは? 転置行列では、元の行列の第 i 行が第 i 列へ、第 j 列が第 j 行へと入れ替わります。数式で表すと、元の行列 A の要素 A[i][j] は、転置行列では A[j][i] の位置に移動します。 例えば、3×3 の行列の場合、次のように行と列が入れ替わります。 元の行列: 転置行列: 6 7 1 6 3 9 3 2
-
C/C++の条件演算子(三項演算子)の使い方をわかりやすく解説
C/C++における条件演算子(?:)は、別名三項演算子(Ternary Operator)とも呼ばれています。名前の由来は、この演算子が3つのオペランド(項)を必要とするためです。条件演算子の基本構文Exp1 ? Exp2 : Exp3;ここで、Exp1・Exp2・Exp3はそれぞれ式を表します。コロンの位置と使い方に注目してください。評価の流れ? 演算子を含む式の値は、以下のように決定されます。まず Exp1 が評価されます。Exp1 が true(真) の場合 → Exp2 が評価され、その結果が式全体の値になります。Exp1 が false(偽) の場合 → Exp3 が評価され、その結
-
C・C++・Java・C#における前置インクリメントと後置インクリメント演算子の動作の違い
インクリメント演算子(++)には、「前置インクリメント」と「後置インクリメント」の2種類があり、どちらも変数の値を1増加させるために使われます。しかし、式の中で評価されるタイミングが異なるため、結果が大きく変わる場合があります。この記事では、両者の違いをC、C++、Java、C#の4つの言語のサンプルコードとともに詳しく解説します。 前置インクリメント(++b)とは 前置インクリメント演算子は、変数の値を式で使用する前に1増加させます。つまり、まず値が1増やされ、その新しい値が式の中で使われます。 例えば、a = ++b; という式で変数 b の初期値が5だった場合、まず b が6になり、その
-
【C++】コピーコンストラクタと代入演算子の違いを徹底解説
C++には、あるオブジェクトをもとに別のオブジェクトを初期化・設定するための仕組みとして、「コピーコンストラクタ」と「代入演算子」の2つがあります。一見似ていますが、両者には重要な違いがあります。最大の違いはメモリの扱いです。コピーコンストラクタは、新しいオブジェクトに対して独立したメモリ領域を新たに作成します。一方、代入演算子は新しいメモリ領域を確保せず、すでに存在するオブジェクト同士の間で値を受け渡すだけです。コピーコンストラクタとはコピーコンストラクタは、同じクラスの既存オブジェクトをもとに新しいオブジェクトを初期化するための特殊なコンストラクタです。実体としては、引数に自分自身のクラス