データ構造とアルゴリズム (1) 複雑さの分析 (その 2): さまざまな状況での複雑さの変化

最良および最悪のケースの時間計算量

// n表示数组array的长度
int find(int[] array, int n, int x) {
    
    
  int i = 0;
  int pos = -1;
  for (; i < n; ++i) {
    
    
    if (array[i] == x) {
    
    
       pos = i;
       break;
    }
  }
  return pos;
}

最良の場合の時間計算量は, 最良の場合, このコードを実行する時間計算量です. 最良の場合, 検索される変数 x がたまたま配列の最初の要素であり, プログラムは直接中断します. この対応する時間複雑度は、最良のケースの時間複雑度です。
最悪の場合の時間計算量は、最悪の場合、このコードを実行する時間計算量です配列内に変数 x がない場合は、配列全体をトラバースする必要があるため、この最悪のケースに対応する時間計算量が最悪の時間計算量になります。

平均ケース時間の複雑さ

検索する変数 x は、配列内にあるか、配列内にないかのいずれかです。これら 2 つの状況の対応する確率を計算するのは面倒なので、便宜上、配列に含まれる確率と配列に含まれない確率を 1/2 と仮定します。また、検索対象データが 0 から n-1 までの n 個の位置に出現する確率は同じで、1/n です。したがって、確率乗法規則によれば、検索対象のデータが 0~n-1 の任意の位置に出現する確率は 1/(2n) となります。
平均時間複雑度の計算プロセスは次のようになります。

1*1/(2n) + 2*1/(2n) + 3*1/(2n) +···+ n*1/(2n) + n*1/2 = (3n+1)/4

この値は、確率論における加重平均であり、期待値とも呼ばれます。そのため、平均時間計算量の正式名称は、加重平均時間計算量または期待時間計算量と呼ばれる必要があります
確率を導入すると、前のコードの加重平均は (3n+1)/4 になります。大きな O 表記で表現すると、このコードの加重平均時間複雑度は、係数と定数を削除した後でも O(n) です。

償却時間の複雑さ

償却された時間計算量は、平均時間計算量に少し似ています。初心者にとって、これらの 2 つの概念は非常に混同しやすいものです。
平均複雑度はいくつかの特殊なケースでのみ使用され、償却時間複雑度が適用されるシナリオはそれよりも特殊で限定的です。

 // array表示一个长度为n的数组
 // 代码中的array.length就等于n
 int[] array = new int[n];
 int count = 0;
 
 void insert(int val) {
    
    
    if (count == array.length) {
    
    
       int sum = 0;
       for (int i = 0; i < array.length; ++i) {
    
    
          sum = sum + array[i];
       }
       array[0] = sum;
       count = 1;
    }

    array[count] = val;
    ++count;
 }

このコードは、配列にデータを挿入する関数を実装しています。配列がいっぱいの場合、つまり、コードで count == array.length の場合、for ループを使用して配列をトラバースして合計し、配列をクリアして、合計の後の合計値を最初の位置に配置します。配列、次に新しいデータを挿入します。ただし、配列の先頭に空き領域がある場合、データは配列に直接挿入されます。
各 O(n) 挿入操作の後に n-1 O(1) 挿入操作が続くため、より多くの時間がかかる操作は、より少ない時間を消費する次の n-1 操作に均等に分散されます。この連続操作のグループは O(1) です。これが償却分析の一般的な考え方です。あなたはすべてを理解していますか?
今日、複雑さの分析に関連するいくつかの概念、つまり、最良のケースの時間の複雑さ、最悪のケースの時間の複雑さ、平均的なケースの時間の複雑さ、および償却された時間の複雑さを学びました。これらの複雑さの概念が導入された理由は、同じコード片が異なる入力条件の下では異なるレベルの複雑さを持つ可能性があるためです。
思考の問題
次の add() 関数の時間計算量を分析してみましょう。

// 全局变量,大小为10的数组array,长度len,下标i。
int array[] = new int[10]; 
int len = 10;
int i = 0;

// 往数组中添加一个元素
void add(int element) {
    
    
   if (i >= len) {
    
     // 数组空间不够了
     // 重新申请一个2倍大小的数组空间
     int new_array[] = new int[len*2];
     // 把原来array数组中的数据依次copy到new_array
     for (int j = 0; j < len; ++j) {
    
    
       new_array[j] = array[j];
     }
     // new_array复制给array,array现在大小就是2倍len了
     array = new_array;
     len = 2 * len;
   }
   // 将element放到下标为i的位置,下标i加一
   array[i] = element;
   ++i;
}

おすすめ

転載: blog.csdn.net/weixin_44339850/article/details/107470023