Xiaobai入門データ構造とアルゴリズムの基礎を学ぶ「1」

目次

導入する

初挑戦

アルゴリズムの提案

アルゴリズムの概念

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

2回目の試行

アルゴリズム効率測定

実行時間はアルゴリズムの効率を反映します

時間の価値だけでも絶対に信頼できますか?

時間計算量と「BigO表記」

「ビッグO表記」の理解方法

最悪の時間計算量

時間計算量のいくつかの基本的な計算規則

スペースの複雑さ

アルゴリズムの分析

一般的な時間計算量

一般的な時間計算量の関係

Python組み込み型のパフォーマンス分析

timeitモジュール

リストの動作テスト

リスト組み込み操作の時間計算量

dict組み込み操作の時間計算量

データ構造

概念

アルゴリズムとデータ構造の違い

抽象データ型


導入する

最初に質問を見てみましょう:

a + b + c = 1000、およびa ^ 2 + b ^ 2 = c ^ 2(a、b、cは自然数)の場合、a、b、およびcのすべての可能な組み合わせを見つける方法は?

初挑戦

import time

start_time = time.time()

# 注意是三重循环
for a in range(0, 1001):
    for b in range(0, 1001):
        for c in range(0, 1001):
            if a**2 + b**2 == c**2 and a+b+c == 1000:
                print("a, b, c: %d, %d, %d" % (a, b, c))

end_time = time.time()
print("elapsed: %f" % (end_time - start_time))
print("complete!")

演算結果:

a, b, c: 0, 500, 500
a, b, c: 200, 375, 425
a, b, c: 375, 200, 425
a, b, c: 500, 0, 500
elapsed: 214.583347
complete!

実行時間に注意してください:214.583347秒

アルゴリズムの提案

アルゴリズムの概念

コンピュータプログラムは本質的に、指定されたタスクを実行するための正確な手順をコンピュータに伝えるアルゴリズムであるため、アルゴリズムはコンピュータ処理情報の本質です。一般に、アルゴリズムが情報を処理しているとき、アルゴリズムは入力デバイスまたはデータのストレージアドレスからデータを読み取り、後で呼び出すために結果を出力デバイスまたは特定のストレージアドレスに書き込みます。

アルゴリズムは、問題を解決するための独立した方法とアイデアです。

アルゴリズムの場合、実装の言語は重要ではなく、重要なことは考えられます。

アルゴリズムには、さまざまな言語記述実装バージョン(C記述、C ++記述、Python記述など)を含めることができます。現在、Python言語を使用して実装を記述しています。

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

  1. 入力:アルゴリズムに0個以上の入力があります
  2. 出力:アルゴリズムには少なくとも1つ以上の出力があります
  3. 有限抵抗:制限されたステップのアルゴリズムが無限ループなしで自動的に閉じられた後、各ステップは許容可能な時間内に完了することができます
  4. 確実性:アルゴリズムのすべてのステップには特定の意味があり、あいまいさはありません
  5. 実現可能性:アルゴリズムの各ステップは実行可能です。つまり、各ステップを限られた回数実行して完了することができます。

2回目の試行

import time

start_time = time.time()

# 注意是两重循环
for a in range(0, 1001):
    for b in range(0, 1001-a):
        c = 1000 - a - b
        if a**2 + b**2 == c**2:
            print("a, b, c: %d, %d, %d" % (a, b, c))

end_time = time.time()
print("elapsed: %f" % (end_time - start_time))
print("complete!")

演算結果:

a, b, c: 0, 500, 500
a, b, c: 200, 375, 425
a, b, c: 375, 200, 425
a, b, c: 500, 0, 500
elapsed: 0.182897
complete!

実行時間に注意してください:0.182897秒

アルゴリズム効率測定

実行時間はアルゴリズムの効率を反映します

同じ問題に対して、同じ問題に対して2つの解決策を示しました.2つのアルゴリズムの実装では、プログラムの実行時間を測定し、2つのプログラムの実行時間が非常に異なることを発見しました(0.182897と比較して214.583347秒)これから結論を導き出すことができます。アルゴリズムプログラムの実行時間は、アルゴリズムの効率、つまりアルゴリズムの長所と短所を反映できます。

時間の価値だけでも絶対に信頼できますか?

2回目の試行のアルゴリズムプログラムを、古い構成でパフォーマンスの低いコンピューターで実行するとします。どうなりますか?実行時間は、コンピューターでアルゴリズム1を実行した214.583347秒よりもそれほど速くない可能性があります。

アルゴリズムの長所と短所を比較するために実行時間に依存するだけでは、必ずしも客観的で正確であるとは限りません。

プログラムの動作をコンピュータ環境(ハードウェアやオペレーティングシステムを含む)から切り離すことはできません。これらの客観的な理由は、プログラムの速度に影響を与え、プログラムの実行時間を反映します。では、アルゴリズムの長所と短所を客観的に判断するにはどうすればよいでしょうか。

時間計算量と「BigO表記」

コンピューターがアルゴリズムの各基本操作を実行する時間は固定時間単位であると想定しているため、基本操作の数は、それにかかる時間の単位を表します。明らかに、マシン環境が異なれば、正確な単位時間も異なりますが、アルゴリズムの基本操作の数(つまり、必要な時間単位の数)は桁違いに同じであるため、マシン環境の影響は次のようになります。無視されます。アルゴリズムの時間効率を客観的に反映します。

アルゴリズムの時間効率のために、「ビッグO表記」を使用して表現できます。

「ビッグO表記」:単調整数関数fの場合、整数関数gと実定数c> 0がある場合、十分に大きいnの場合、常にf(n)<= c * g(n)が存在します。 、関数gはfの漸近関数(定数を無視)であり、f(n)= O(g(n))として表されます。つまり、無限の限界の下では、関数fの成長率は関数gによって制約されます。つまり、関数fと関数gの特性は類似しています。

時間計算量:関数gがあるとすると、アルゴリズムAがnのスケールで問題を処理するのにかかる時間はT(n)= O(g(n))であり、O(g(n))は次のようになります。アルゴリズムAの漸近解析と呼ばれます。時間計算量と呼ばれ、T(n)で表されます。

「ビッグO表記」の理解方法

アルゴリズムの特に詳細で詳細な分析を行うことは非常に良いことですが、実際の実際の値は限られています。アルゴリズムの時間と空間の性質にとって、最も重要なことはその大きさと傾向であり、これらはアルゴリズムの効率を分析する主要な部分です。測定アルゴリズムの基本操作量のスケール関数の定数係数は無視できます。たとえば、3n2と100n2は同じ桁数に属すると見なすことができます。同じスケールのインスタンスを処理するための2つのアルゴリズムのコストがそれぞれこれらの2つの関数である場合、両方とも効率が「類似」していると見なされます。そのうちn2です。

最悪の時間計算量

アルゴリズムを分析する場合、いくつかの考慮事項が考えられます。

  • アルゴリズムが作業を完了するために必要な基本操作の数、つまり最適な時間計算量
  • アルゴリズムが作業を完了するために必要な基本操作の数、つまり、最悪の時間計算量
  • アルゴリズムが作業を完了するために必要な基本操作の平均数、つまり平均時間計算量

最適な時間計算量の場合、有用な情報を提供せず、最も楽観的で理想的な状況のみを反映し、参照値がないため、その値は大きくありません。

最悪の時間計算量に対しては、アルゴリズムがこのレベルの基本操作で作業を完了できなければならないことを示す保証が提供されます。

平均時間計算量はアルゴリズムの包括的な評価であるため、アルゴリズムの性質を完全かつ包括的に反映しています。ただし、その一方で、この測定は保証されておらず、この基本的な操作ですべての計算を完了できるわけではありません。さらに、平均的なケースの計算では、適用されたアルゴリズムのインスタンス分布が均一でない可能性があるため、計算も困難です。

したがって、主にアルゴリズムの最悪のケース、つまり最悪の時間計算量に焦点を当てます。

時間計算量のいくつかの基本的な計算規則

  1. 基本的な操作、つまり定数項のみがあり、時間計算量はO(1)と見なされます。
  2. シーケンスストラクチャ、時間の複雑さがされて計算によってさらに
  3. ループ構造、時間計算量は乗算によって計算されます
  4. ブランチ構造、最大時間計算量
  5. アルゴリズムの効率を判断する際には、演算数の最上位項目のみに注意を払う必要があり、その他のマイナー項目や定数項目は無視できます。
  6. 特に明記されていない限り、分析したアルゴリズムの時間計算量は、最悪の時間計算量を指します。

スペースの複雑さ

時間計算量の説明と同様に、アルゴリズム空間計算量S(n)は、アルゴリズムによって消費されるストレージ空間として定義されます。これは、問題サイズnの関数でもあります。

漸近的な空間の複雑さは、単に空間の複雑さと呼ばれることがよくあります

Space Complexity(SpaceComplexity)は、アルゴリズムが操作中に一時的に占有するストレージスペースの量の尺度です。

アルゴリズムの時間計算量と空間計算量は、まとめてアルゴリズムの複雑度と呼ばれます。

アルゴリズムの分析

  1. 最初の試行のアルゴリズムのコア部分
for a in range(0, 1001):
    for b in range(0, 1001):
        for c in range(0, 1001):
            if a**2 + b**2 == c**2 and a+b+c == 1000:
                print("a, b, c: %d, %d, %d" % (a, b, c))

時間計算量:

T(n)= O(n * n * n)= O(n3)

  1. 2回目の試行のアルゴリズムのコア部分
for a in range(0, 1001):
    for b in range(0, 1001-a):
        c = 1000 - a - b
        if a**2 + b**2 == c**2:
            print("a, b, c: %d, %d, %d" % (a, b, c))

時間計算量:

T(n)= O(n * n *(1 + 1))= O(n * n)= O(n2)

私たちが試した2番目のアルゴリズムの時間計算量は、最初のアルゴリズムの時間計算量よりもはるかに優れていることがわかります。

一般的な時間計算量

実行頻度関数の例 注文 非公式用語
12 O(1) 一定の順序
2n + 3 オン) 線形順序
3n2 + 2n + 1 O(n2) スクエアオーダー
5log2n + 20 O(ログ) 対数順序
2n + 3nlog2n + 19 O(nlogn) nlogn注文
6n3 + 2n2 + 3n + 4 O(n3) キュービックオーダー
2n O(2n) 指数関数的な順序

log2n(2を底とする対数)はしばしばlognと省略されることに注意してください

一般的な時間計算量の関係

小さいものから大きいものへと費やした時間

O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)

演習:時間計算量の演習(アルゴリズムの効率ルールの判断を参照)
O(5)
O(2n + 1)
O(n²+ n + 1)
O(3n³+ 1)

 

Python組み込み型のパフォーマンス分析

timeitモジュール

timeitモジュールを使用して、Pythonコードの小さな部分の実行速度をテストできます。

class timeit.Timer(stmt = 'pass'、setup = 'pass'、timer = <timer function>)

タイマーは、小さなコードの実行速度を測定するクラスです。

stmtパラメーターは、テストされるコードステートメント(ステートメント)です。

セットアップパラメータは、コードを実行するときに必要な設定です。

タイマーパラメータはタイマー機能であり、プラットフォームに関連しています。

timeit.Timer.timeit(number = 1000000)

ステートメントの実行速度をテストするためのTimerクラスのオブジェクトメソッド。numberパラメーターは、コードをテストするときのテストの数であり、デフォルトは1,000,000回です。このメソッドは、コードを実行するための平均時間、floatタイプの秒数を返します。

リストの動作テスト

def t1():
   l = []
   for i in range(1000):
      l = l + [i]
def t2():
   l = []
   for i in range(1000):
      l.append(i)
def t3():
   l = [i for i in range(1000)]
def t4():
   l = list(range(1000))

from timeit import Timer

timer1 = Timer("t1()", "from __main__ import t1")
print("concat ",timer1.timeit(number=1000), "seconds")
timer2 = Timer("t2()", "from __main__ import t2")
print("append ",timer2.timeit(number=1000), "seconds")
timer3 = Timer("t3()", "from __main__ import t3")
print("comprehension ",timer3.timeit(number=1000), "seconds")
timer4 = Timer("t4()", "from __main__ import t4")
print("list range ",timer4.timeit(number=1000), "seconds")

# ('concat ', 1.7890608310699463, 'seconds')
# ('append ', 0.13796091079711914, 'seconds')
# ('comprehension ', 0.05671119689941406, 'seconds')
# ('list range ', 0.014147043228149414, 'seconds')

ポップ動作テスト

x = range(2000000)
pop_zero = Timer("x.pop(0)","from __main__ import x")
print("pop_zero ",pop_zero.timeit(number=1000), "seconds")
x = range(2000000)
pop_end = Timer("x.pop()","from __main__ import x")
print("pop_end ",pop_end.timeit(number=1000), "seconds")

# ('pop_zero ', 1.9101738929748535, 'seconds')
# ('pop_end ', 0.00023603439331054688, 'seconds')

ポップ操作のテスト:結果からわかるように、ポップの最後の要素の効率は、ポップの最初の要素の効率よりもはるかに高くなっています。

リストのappend(value)とinsert(0、value)を自分で試すことはできますか?つまり、後ろに1つ、前に1つ挿入しますか?

リスト組み込み操作の時間計算量

dict組み込み操作の時間計算量

データ構造

Pythonで型を使用して、クラスに生徒の情報を保存するにはどうすればよいですか?生徒の名前から生徒に関する情報をすばやく取得したい場合はどうすればよいですか?

実際、この問題について考えるとき、私たちはすでにデータ構造を使用しています。リストと辞書の両方にクラスの生徒情報を保存できますが、リスト内のクラスメートの情報を取得する場合は、リストをトラバースする必要があります。時間計算量はO(n)であり、辞書を使用する場合保存する学生名を辞書のキーとし、学生情報を値とします。照会時にトラバースすることなく、学生情報をすばやく取得できます。時間計算量はO(1)です。

この問題を解決するためには、データを保存し、データの保存方法に応じて処理するアルゴリズムを設計する必要があります。そうすると、データの保存方法が異なると、処理するアルゴリズムも異なります。問題を解決するためのアルゴリズムの効率ができるだけ速くなることを望んでいるので、データを保存する方法を検討する必要があります。これがデータ構造です。

上記の質問では、Pythonでリストまたは辞書を選択して、学生の情報を保存できます。リストと辞書は、それらをカプセル化するのに役立つPythonに組み込まれた2つのデータ構造です。

概念

データは抽象的な概念です。データを分類すると、プログラミング言語の基本的な型が取得されます。例:int、float、charなど。データ要素は独立しておらず、特定の関係があり、これらの関係は構造です。データ構造とは、データオブジェクト内のデータ要素間の関係を指します。

Pythonは、多くの既製のデータ構造タイプを提供します。これらのシステムが自身で定義し、定義する必要のないデータ構造は、リスト、タプル、辞書など、Pythonの組み込みデータ構造と呼ばれます。また、一部のデータ編成方法はPythonシステムで直接定義されていないため、これらのデータの編成方法を自分で定義する必要があります。これらのデータ編成方法は、スタックやキューなどのPython拡張データ構造と呼ばれます。

アルゴリズムとデータ構造の違い

データ構造は、データ要素間の関係を静的に記述するだけです。

効率的なプログラムでは、データ構造に基づいてアルゴリズムを設計および選択する必要があります。

プログラム=データ構造+アルゴリズム

概要:アルゴリズムは実際の問題を解決するように設計されており、データ構造はアルゴリズムが対処する必要のある問題のキャリアです。

抽象データ型

抽象データ型(ADT)の意味は、数学モデルと、この数学モデルで定義された一連の操作を指します。つまり、データ型とデータ型に対する操作がバンドルされてカプセル化されます。抽象データ型を導入する目的は、データ型の表現とデータ型に対する操作の実現を、プログラム内のこれらのデータ型と操作の参照から分離し、それらを互いに独立させることです。

最も一般的に使用されるデータ操作は5つあります。

  • インサート
  • 削除
  • 変更する
  • 検索
  • ソート

 

 

おすすめ

転載: blog.csdn.net/weixin_45293202/article/details/114707875