Wangdaoビデオ-データ構造-注1:時間の複雑さと空間の複雑さ


0メモ

2020年ワンダオ大学院入試データ構造から派生。ブログの内容は、私自身のメモを書面で整理したものです。私自身の学習ニーズに応じて、必要な内容を追加する場合があります。


1基礎知識

[プログラム=データ構造+アルゴリズム]。ここで、データ構造は処理される情報であり、アルゴリズムは情報を処理するステップです。

1.1データ構造の3つの要素

(1)コレクション、線形構造、ツリー構造、グラフ構造(ネットワーク構造とも呼ばれる)を含む論理構造

(2)シーケンシャルストレージ、チェーンストレージ、インデックスストレージ、ハッシュストレージなどの物理構造(ストレージ構造とも呼ばれます)。

(3)データの操作

ストレージ構造について理解するための3つの重要なポイントもあります。

(1)シーケンシャルストレージを使用する場合、各データ要素は物理的に連続している必要があります。非シーケンシャルストレージを使用する場合、各データ要素は物理的に離散することができます。

(2)データのストレージ構造は、ストレージスペース割り当ての利便性に影響します。

(3)データの格納構造は、データ計算の速度に影響します。

1.2アルゴリズムの5つの特徴

(1)有限、アルゴリズムは有限の時間で実行することができます。

(2)決定論、同じ入力は同じ出力のみを生成します。

(3)実現可能性、アルゴリズムは既存の基本操作で実現できます。

(4)入力、アルゴリズムにデータを処理させます。

(5)出力、アルゴリズム処理の結果。

1.3設計アルゴリズムはこれらを考慮します

(1)正しさ、問題を正しく解決できます。

(2)読みやすさ、アルゴリズムの説明は他の人に理解されるべきです。

(3)堅牢性、アルゴリズムはいくつかの異常な状態を処理できます。

(4)高効率と低ストレージ要件、アルゴリズムの実行により時間、メモリ、スペースの複雑さが節約され、時間の複雑さが低くなります。


2複雑さ

2.1時間計算量

アルゴリズムの時間計算量は、アルゴリズムを推定するためのアルゴリズムの時間コストT(n)と問題サイズnの間の関係を考慮します。Big O表記を使用して、時間計算量T(n)を表します。たとえば、問題のサイズがf(n)= n 3 + n 2 +10の場合、T(n)= O(f(n))= O(n 3 + n 2 +10)。時間計算量は、最も高い次数のアイテムのみを考慮する必要があるため、T(n)= O(f(n))= O(n 3 + n 2 +10)= O(n 3)、つまり、時間時間計算量はO(n 3)です。

時間計算量の計算には、次の2つのルールがあります。

(1)加算規則:複数の項目を加算する場合、最上位の項のみが保持され、係数は1です。式は次のとおりです。
ここに画像の説明を挿入します
(2)乗算規則:複数の項目を乗算する場合、式は次
ここに画像の説明を挿入します
のとおりです。複雑度ランキング表:
ここに画像の説明を挿入します
時間計算量を計算するための3つのステップ:

(1)キーセンテンスを見つけます。ループがある場合は、最も深いループでキーセンテンスを見つけます。

(2)ステートメントxの実行回数と問題サイズnの関係を分析します。つまり、x = f(n)です。

(3)アルゴリズムの時間計算量はT(n)= O(x)= O(f(n))です。

サンプルコードスニペット1:

n = int(input()) # n为问题规模
count = 1 # 计数变量
while(count <= n): # 第一层循环执行n次
    count = count + 1
    for j in range(n): # 第二层循环
        print('helloworld') # 第二层循环执行n*n次

時間計算量を計算するときは、順番に実行されるコードを考慮する必要はありません。ループがある場合は、ループ内のキーステートメントを選択するだけで、実行回数とスケールnの関係を分析できます。深いループがある場合は、最も内側のレイヤーサイクルに注意を払うだけで済みます。上記のコードの時間計算量はO(n 2)です。

サンプルコードスニペット2:

n = int(input()) # n为问题规模
count = 1 # 计数变量
while(count <= n):
    count = count * 2 # 关键语句
    print('helloworld')

上記のコードでは、4行目がループのキーステートメントです。カウントが2、4、8、16 ... 2 x …の場合、ステートメントの実行回数は1、2、3、4です。 ..x ...キーステートメントが実行されたと仮定しますループはx回で終了し、この時点でcount = 2 x > n、つまりx> log 2 n、x = log 2 nを取り、次にT( n)= O(n)= O(log 2 n)。

サンプルコードスニペット3:

import random

n = int(input()) # n为问题规模
list1 = [i+1 for i in range(n)] # 第一层循环
random.shuffle(list1) # 打乱列表
for i in range(n): # 第二层循环
    if list1[i] == n:
        print('OK!')
        break

上記のコードには2つのループがありますが、それらは互いにネストされていないため、別々に解決してください。最初のループでは、ステートメントは1つだけです。明らかに、ステートメントはnのスケールでn回実行されます。つまり、O(n); 2番目のループでは、プログラムの入力がアルゴリズムの時間計算量に影響します。8行目が重要なステートメントです。次の3つの状況があります。①最適なのはO(1)であり、要素nは最初の位置にあります;②最悪の場合はO(n)であり、要素nは最後から2番目の位置にあります;③平均して、任意の位置でのnの確率を1 / nとすると、サイクルx =(1 + 2 +…+ n)・1 / n =(1 + n)/ 2、つまり、T(n)= O(f(n))= O((1 + n)/ 2 )= O(n)。一般的に、平均的なケースと最悪のケースのみが考慮されます。要約すると、最初のサイクルではT(n)= O(n)、2番目のサイクルではT(n)= O(n)です。したがって、コード全体の複雑さはT(n)= O(n)+ O(n)= O(n)です。

プログラムの入力がアルゴリズムの実行時間に影響を与える場合があります。このとき、平均時間計算量を考慮する必要があります。つまり、すべての入力データが同じ確率で表示されると見なされます。

2.2スペースの複雑さ

アルゴリズムのスペースの複雑さは、アルゴリズムのメモリスペース(スペース)オーバーヘッドS(n)と問題サイズnの関係を考慮し、スペースの複雑さS(n)は大きなO表記S(n)で表されます。 = O(f(n))。

スペースの複雑さを計算する3つのステップ:

(1)問題サイズnが占めるスペースのサイズに関連する変数を見つけます。一部のアルゴリズムでは、レイヤー関数ごとに異なるストレージスペースが必要であり、分析方法がわずかに異なります。

(2)占有スペースxと問題サイズnx = f(n)の関係を分析し、再帰プログラムがある場合は、再帰呼び出しの深さxと問題サイズnx = f(n)の関係を見つけます。 ;

(3)x O(x)の大きさは、アルゴリズム空間の複雑さS(n)です。

さらに、時間計算量加算規則、乗算規則、および複雑度ランキング表は、空間計算量操作にも適用できます。

サンプルコードスニペット1:

n = int(input()) # n为问题规模
count = 1 # 计数变量
while(count <= n):
    count = count + 1
    print('helloworld')

上記のコードでは、問題サイズnに関連する変数はなく、2つの変数nとcountのみです。つまり、問題サイズnがいくらであっても、アルゴリズムを実行するためのメモリスペースは固定定数です。された空間の複雑さをS(N)= O(1)であり、アルゴリズムによって必要とされるメモリ空間は、この時点で一定であり、そしてアルゴリズムがに言われている場所での作業

サンプルコードスニペット2:

n = int(input()) # n为问题规模
count = 1 # 计数变量
list1 = list(range(n))
... # 省略后续代码

上記のコードでは、問題スケールnに関連する変数はlist1であり、必要なメモリスペースはnに比例するため、スペースの複雑さはS(n)= O(n)です。

サンプルコードスニペット3:

n = int(input()) # n为问题规模
count = 1 # 计数变量
list1 = list(range(n))
list2 = [i for j in range(n) for i in range(n)]
... # 省略后续代码

上記のコードでは、問題スケールnに関連する変数はlist1、list2であり、必要なメモリスペースはn、n 2であるため、スペースの複雑さはS(n)= O(n 2 + n)= O(n 2)。

サンプルコードスニペット4:

def f(n):
    if n > 1:
        f(n-1) # 递归
    print(n)

上記のコードには再帰プログラムがありますが、問題スケールnに関連する変数はなく、再帰の深さはnであるため、S(n)= O(n)、つまり、空間の複雑さは再帰呼び出しの深さ。

サンプルコードスニペット5:

def f(n):
    list1 = list(range(n)) # 与问题规模n相关的变量
    if n > 1:
        f(n-1) # 递归
    print(n)

上記のコードには、再帰プログラムがあり、問題サイズnに関連する変数はlist1であり、再帰深度はnです。問題のサイズがnの場合、第1レベルの再帰に必要なメモリスペースはn(list(range(n))のため)であり、第2レベルの再帰に必要なメモリスペースはn-1(リストのため)です。 (range(n-1)))、再帰の3番目の層に必要なメモリスペースはn-2です(list(range(n-2))のため)...再帰のn番目の層に必要なメモリスペースは1です(list(range(1))のため)。したがって、x = f(n)=(1 + n)・n / 2、したがってS(n)= O(f(n))= O((1 + n)・n / 2)= O(n 2) 。


終わり

おすすめ

転載: blog.csdn.net/qq_40061206/article/details/112434755