[Python] pythonはさまざまなデータ構造を実装しています

データ構造は、データの論理構造と物理構造、およびそれらの間の関係を調査し、この構造に対応する操作を定義し、これらの操作の後に取得された新しい構造が元の構造タイプのままであることを確認します。

1.データ:コンピューターに入力してコンピューターで処理できるすべての記号のコレクション。これは、コンピューターによって操作されるオブジェクトの総称です。

2.データ要素:データ(コレクション)の「個人」、データと構造で説明されている基本単位

3.データ項目:データの分割できない最小単位。データ要素は、複数のデータ項目で構成できます。

4.データ型:プログラミング言語において、変数が持つデータの型。整数、浮動小数点、文字など。

5.論理構造:データ間の関係。

集合 结构中的数据元素除了同属于一种类型外,别无其它关系。
线性结构 数据元素之间一对一的关系
树形结构 数据元素之间一对多的关系
图状结构或网状结构 结构中的数据元素之间存在多对多的关系

6.物理的構造/ストレージ構造:コンピューター内のデータの表現。物理構造は、メモリ内のデータの特定のストレージ(シーケンシャル構造、チェーン構造、インデックス構造、ハッシュ構造など)などを記述することです。

7.データ構造では、線形構造と非線形構造に論理的に分けることができます。

8.データ構造の基本操作を設定するための最も重要な基準は、アプリケーションプログラムとストレージ構造の独立性を実現することです。アプリケーションの実現は「論理構造」であり、ストレージは「物理構造」です。論理構造は主に構造の動作を設定するためのものであり、物理構造はメモリ内のデータの特定のストレージ(シーケンシャル構造、チェーン構造、インデックス構造、シハ構造など)を記述するためのものです。

9.順次ストレージ構造では、線形テーブルの論理順序と物理順序は常に一貫しています。ただし、チェーンストレージ構造では、線形テーブルの論理的な順序と物理的な順序は一般的に異なります。

10.アルゴリズムの5つの特性:有限性、確実性、実現可能性、入力、出力

11.アルゴリズムの設計要件:正確性、読みやすさ、堅牢性、高効率、低ストレージ要件。(良いアルゴリズム)

12.アルゴリズムの説明には、擬似プログラム、フローチャート、NS構造図などが含まれます。ERダイアグラムはエンティティ接続モデルであり、プログラムを説明する方法ではありません。

13.設計アルゴリズムの実行時間を考慮する必要があります:アルゴリズム選択の規模と問題の規模

14.時間計算量:アルゴリズムの実行時間は、元の操作の実行回数の合計に比例します。時間計算量は、小さいものから大きいものまでさまざまです。O(1)、O(logn)、O(n)、O(nlogn)、O(n2)、O(n3)。電力時間の複雑さは、O(2n)、O(n!)、O(nn)と同じくらい小さいです。

15.スペースの複雑さ:入力データが占めるスペースが問題自体にのみ依存し、アルゴリズムとは関係がない場合、入力とプログラム以外の補助変数が占める追加のスペースのみを分析する必要があります。

線形テーブル

線形テーブルは、典型的な線形構造です。ヘッドノードには先行ノードのない後続ノードがあり、テールノードには後続ノードのない先行ノードがあります。リンクリストは順次検索のみ可能で、要素の検索時間はO(N)、要素の削除時間はO(1)です。

1.線形テーブルの順次ストレージ構造:線形テーブルのノードは、論理的な順序で連続するアドレスを持つストレージユニットのグループに格納されます。このように格納された線形テーブルは、シーケンシャルテーブルと呼ばれます。これは、ランダムアクセスストレージ構造です。シーケンシャルストレージとは、メモリアドレスが1ブロックであることを意味し、ランダムアクセスとは、アクセス時に標準を押すことでランダムにアクセスできることを意味し、ストレージとアクセスは同じではありません。ストレージの場合はシーケンシャルを意味し、アクセスの場合はランダムにすることができ、要素の添え字を使用して実行できます。配列は線形テーブルよりも高速です。順序を逆にして、中間ノードに戻り、ランダムノードを選択します。

便于线性表的构造和任意元素的访问
插入:插入新结点,之后结点后移。平均时间复杂度:O(n)
删除:删除节点,之后结点前移。平均时间复杂度:O(n)

2.線形リンクリスト:任意のストレージユニットのグループを使用して、線形テーブルのノードを順番に格納します。このストレージユニットのグループは、連続または不連続、あるいはメモリ内の任意の位置に分散することができます。したがって、リンクリスト内のノードの論理的な順序と物理的な順序は必ずしも同じではありません。ノード間の論理関係を正しく表すためには、各ノードの値を格納すると同時に、後続ノードを示すアドレスも格納する必要があります。データフィールドは、ノードの値を格納するために使用されるデータフィールドです。次はポインタフィールド(チェーンフィールドとも呼ばれます)で、ノードの直後の後続のアドレス(または場所)を格納するために使用されます。事前にストレージスペースのサイズを見積もる必要はありません。

(1)単一リンクリスト内の各ノードの格納アドレスは、先行ノードの次のフィールドに格納され、開始ノードには先行ノードがないため、ヘッドポインタヘッドは開始ノードを指すように設定する必要があります。同時に、最後のノードには後続ノードがないため、ノードのポインタフィールドは空、つまりNULLです。ヘッド補間(逆順)によるテーブル作成、およびテール補間(順序)によるテーブル作成。ヘッドノードを増やす目的は、アルゴリズムの実現を容易にすることですが、メモリのオーバーヘッドが増加します。

查找:只能从链表的头指针出发,顺链域next逐个结点往下搜索,直到搜索到第i个结点为止。因此,链表不是随机存取结构。
插入:先找到表的第i-1的存储位置,然后插入。新结点先连后继,再连前驱。
删除:首先找到ai-1的存储位置p。然后令p–>next指向ai的直接后继结点,即把ai从链上摘下。最后释放结点ai的空间.r=p->next;p->next=r->next;delete r。
判断一个单向链表中是否存在环的最佳方法是快慢指针。

(2)静的リンクリスト:1次元配列を使用して線形リンクリストを実現します。1次元配列で表されるこの線形リンクリストを静的リンクリストと呼びます。静的:表に反映されている容量は確実です。(配列のサイズ);リンクリスト:挿入と削除は、上記の動的リンクリストと同じです。静的リンクリストのポインタは、配列内の次の要素の位置を示します。

(3)静的リンクリストは、シーケンシャルストレージ構造である配列を使用して実装されます。配列は、物理アドレスで連続しており、事前に割り当てる必要があります。動的リンクリストは、メモリアプリケーション関数(Cはmalloc、C ++は新規)を使用して動的にメモリを適用するため、リンクリストの長さに制限はありません。動的リンクリストはメモリに動的に適用されるため、各ノードの物理アドレスは連続的ではなく、ポインタを介して順番にアクセスする必要があります。静的リンクリストは、挿入および削除時にポインタフィールドを変更することによっても実現されます。これは、動的リンクリストと同じです。

(4)循環リンクリスト:エンドツーエンドで接続されたリンクリストです。その特徴は、ストレージの量を増やす必要がなく、テーブルのリンク方法をわずかに変更するだけで、テーブル処理をより便利で柔軟にすることができることです。

単一リンクリストでは、端末ノードのポインタフィールドNULLがヘッドノードまたは開始ノードを指すように変更され、単一リンク循環リンクリストが取得されます。これは単に単一循環リンクリストと呼ばれます。循環リンクリストにはNULLポインタがないため、トラバーサル操作が含まれる場合、その終了条件は、非循環リンクリストのようにpまたはp-> nextが空であるかどうかではなく、ヘッドポインタやテールポインタなどの指定されたポインタ。

(5)二重リンクリスト:単一リンクリストの各ノードで、直前のノードの前にポインタフィールドを追加します。このように形成されたリンクリストには、異なる方向に2つのチェーンがあります。二重リンクリストは、通常、ヘッドポインタによって一意に決定され、ヘッドノードとテールノードがリンクされて、二重リンクリストと呼ばれる循環リンクリストを形成します。ポインタpが特定のノードを指しているとすると、二重リンクリスト構造の対称性は次の式で表すことができます。p-> prior-> next = p = p-> next-> prior。2方向からの二重リンクリストの検索は、1方向からの二重リンクリストの検索よりも分散が少なくなります。

挿入:最初に挿入されたノードの先行ノードと後続ノードを決定し、次にバックノードの先行ノードを決定し、最後に前のノードの後続ノードを決定します。
順序付けられた二重リンクリスト内の要素の検索と削除の平均時間計算量はO(n)
であり、現在のポインターが指すノードを直接削除できます。単一リンクリストのようである必要はありません。要素を削除すると、その前の要素を見つける必要があります。したがって、データを挿入する場合、単一リンクリストと二重リンクリストの操作の複雑さは同じであり、データを削除する場合、二重リンクリストのパフォーマンスは単一リンクリストよりも優れています。

スタック

スタックは、テーブルの一方の端での挿入と削除の操作に制限されている線形テーブルです。通常、挿入と削除の端はスタックの最上位と呼ばれ、もう一方の端はスタックの最下部です。最初に、最後に。top = -1の場合、それは空のスタックであり、top = 0は、スタックに要素が1つしかないことを示すだけであり、要素がスタックにプッシュされると、topは自動的に増加するはずです。

1.シーケンシャルストレージスタック:シーケンシャルストレージ構造
2.チェーンスタック:チェーンストレージ構造。挿入および削除操作は、チェーンヘッドの位置のみに制限されています。スタックのトップポインタは、リンクリストのヘッドポインタです。通常、スタックがいっぱいになることはありません。スタックがいっぱいであると判断する必要はありませんが、スタックが空であると判断する必要があります。
3. 2つのスタックは静的ストレージスペースを共有し、ヘッドの使用時にスペースオーバーフローの問題もあります。スタック1の最下部はv [1]にあり、スタック2の最下部はV [m]にあります。スタックがいっぱいになる条件はtop [1] + 1 = top [2]です。
4.基本操作:スタックの最上位要素を削除し、スタックが空かどうかを判断し、スタックを空のスタックに設定します
。5。nの各要素のスタック問題の場合、可能なスタックシーケンスはC(2n 、n)/(n + 1)1つ。
6.スタックオーバーフローは通常、大きなデータ構造のループとローカル変数の再帰的な呼び出しによって引き起こされます

    from collections import deque
    class Stack:
        def __init__(self):
            self.s = deque()
        def peek(self):
            p = self.pop()
            self.push(p)
            return p
        def push(self, el):
            self.s.append(el)
        def pop(self):
            return self.pop()

キュー

キューは、操作が制限された線形テーブルでもあります。テーブルの一方の端でのみ挿入を許可し、もう一方の端で削除を許可します。削除できる端をフロント、挿入できる端をリアと呼びます。先入先出。

1.シーケンシャルキュー:シーケンシャルストレージ構造。ヘッドポインタとテールポインタが等しい場合、キューは空です。空でないキューでは、ヘッドポインターは常にキューのヘッドの前の位置を指し、テールポインターは常にキューの最後にある要素の実際の位置を指します。

2.循環キュー。循環キューでデキューおよびエンキュー操作を実行する場合でも、ヘッドポインタとテールポインタを1増やして、先に進む必要があります。ヘッドポインタとテールポインタがベクトルの上限(MaxSize-1)を指している場合、その加算演算の結果はベクトル0の下限を指しているだけです。ベクトル空間が実際にキュー要素によって占有されていない限り、オーバーフローすることはありません。したがって、いくつかの単純なアプリケーションを除いて、真に実用的なシーケンシャルキューは循環キューです。したがって、チームが空のときとチームがいっぱいのときは、ヘッドポインタとテールポインタは等しくなります。したがって、front = Rearによって、キューが「空」であるか「満杯」であるかを判断することはできません。

3.チェーンキュー:チェーンストレージ構造。テーブルの先頭で削除され、テーブルの最後に挿入される単一リンクリストのみを制限します。明らかに、単一リンクリストのヘッドポインタだけがリストの最後に挿入するのに便利ではないため、リンクリストの最後のノードを指すようにテールポインタが追加されます。

4.キューを表すテールポインタの循環リンクリストを設定すると、エンキューアルゴリズムとデキューアルゴリズムの時間計算量は両方ともO(1)になります。キューは循環リンクリストで表され、リンクリストのヘッドノードが存在する必要があります。エンキュー操作は、リンクリストの最後に挿入され、テールポインタが指すノードの直後に挿入されます。時間の複雑さは一定です。デキュー操作はリンクリストの先頭で実行されます。ヘッダーが指すノードを削除するだけで、時間の複雑さも一定になります。

5.チームが空の状態:rear == frontですが、通常、スタックがいっぱいか空かを示すために、各位置のブール値など、新しいマークを導入する必要があります。

6.キューがいっぱいになる状態:(rear + 1)%QueueSize == front、ここでQueueSizeは循環キューの最大長です

7.キューの長さを計算します:(rear-front + QueueSize)%QueueSize

8、入队:(rear + 1)%QueueSize

9.デキュー:(front + 1)%QueueSize

10.配列A [N]が循環キューの要素を格納する容量として使用され、ヘッドポインターがフロントで、現在のキューにX個の要素があるとすると、キューのテールポインターは(front + X mod N)

    from collections import deque
    class Queue:
        def __init__(self):
            self.s = deque()
        def push(self, el):
            self.s.append(el)
        def pop(self):
            return self.popleft()

クイックソート

    def quick_sort(_list):
            if len(_list) < 2:
                return _list
            pivot_index = 0
            pivot = _list(pivot_index)
            left_list = [i for i in _list[:pivot_index] if i < pivot]
            right_list = [i for i in _list[pivot_index:] if i > pivot]
        return quick_sort(left) + [pivot] + quick_sort(right)

ソートを選択

    def select_sort(seq):
        n = len(seq)
        for i in range(n-1)
        min_idx = i
            for j in range(i+1,n):
                if seq[j] < seq[min_inx]:
                    min_idx = j
            if min_idx != i:
                seq[i], seq[min_idx] = seq[min_idx],seq[i]

挿入ソート

    def insertion_sort(_list):
        n = len(_list)
        for i in range(1,n):
            value = _list[i]
            pos = i
            while pos > 0 and value < _list[pos - 1]
                _list[pos] = _list[pos - 1]
                pos -= 1
            _list[pos] = value
            print(sql)

マージソート

    def merge_sorted_list(_list1,_list2):   #合并有序列表
        len_a, len_b = len(_list1),len(_list2)
        a = b = 0
        sort = []
        while len_a > a and len_b > b:
            if _list1[a] > _list2[b]:
                sort.append(_list2[b])
                b += 1
            else:
                sort.append(_list1[a])
                a += 1
        if len_a > a:
            sort.append(_list1[a:])
        if len_b > b:
            sort.append(_list2[b:])
        return sort

    def merge_sort(_list):
        if len(list1)<2:
            return list1
        else:
            mid = int(len(list1)/2)
            left = mergesort(list1[:mid])
            right = mergesort(list1[mid:])
            return merge_sorted_list(left,right)

ヒープソートheapqモジュール

    from heapq import nsmallest
    def heap_sort(_list):
        return nsmallest(len(_list),_list)

二分探索

    def binary_search(_list,num):
        mid = len(_list)//2
        if len(_list) < 1:
            return Flase
        if num > _list[mid]:
            BinarySearch(_list[mid:],num)
        elif num < _list[mid]:
            BinarySearch(_list[:mid],num)
        else:
            return _list.index(num)

ハッシュ表

ハッシュテーブル(ハッシュテーブル、ハッシュテーブルとも呼ばれます)は、キー値に基づいて直接アクセスされるデータ構造です。つまり、キーコード値をテーブル内の場所にマッピングしてレコードにアクセスし、検索を高速化します。このマッピング関数はハッシュ関数と呼ばれ、レコードを格納する配列はハッシュテーブルと呼ばれます。

ストレージ構造を構築すると、特定の関数(hashFunc)を使用して、要素の保存場所とそのキーコードの間に1対1のマッピング関係を確立でき、検索中に関数を介して要素をすばやく見つけることができます。

構造に
要素挿入する場合:挿入する要素のキーコードに従って、要素の保存場所がこの関数によって計算され、
検索要素がこの位置に従って保存されます:同じ計算がキーに対して実行されます要素のコードと計算得られた関数値を要素の保存場所とみなし、構造内のこの位置に従って要素を比較します。キーコードが等しい場合、検索は成功します。
この方法は次のとおりです。ハッシュ(ハッシュ)メソッド。ハッシュメソッドで使用される変換関数はハッシュ(ハッシュ)関数と呼ばれ、構築された構造はハッシュテーブル(またはハッシュテーブル)と呼ばれます。

# 两数之和(twosum)
class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        map_a = dict()
        k = len(nums)
        for i in range(0, k):#一边将列表中的数添加到字典中,一边判断两数之差是否存在于字典中
            temp = target - nums[i]  
            if temp in map_a :  # 判断步骤
                return [map_a[temp], i]
            map_a[nums[i]] =  i  # 添加步骤(切记先判断再添加,以免key冲突)

おすすめ

転載: blog.csdn.net/m0_37882192/article/details/115271643