お気に入りに「埃をかぶる」良いもの – 「お気に入りは決して止まらず、行動は決して始まらない」

方向 1: 集めた良い質問を共有する

Xiao Yalan が最初にデータ構造とアルゴリズムを学んだとき、学ぶのが本当に難しかったです。リンク リストは本当に難しいと感じました。次の知識を学んだ後、リンク リストが徐々に簡単になっていくことがわかりました。今なら、シャオヤランは今でも、リンクされたリストの知識ポイントと OJ の質問は非常に意味があると考えています。

これは、リンク リストの知識ポイントに関連する Xiao Yalan によって書かれたブログです:単一リンク リスト - 「データ構造とアルゴリズム」

二重リンクリスト - 「データ構造とアルゴリズム」

配列表(更新版) - 「データ構造とアルゴリズム」

 


struct ListNode* reverseList(struct ListNode* head){
    if(head==NULL)
    {
        return NULL;
    }
    struct ListNode*n1=NULL;
    struct ListNode*n2=head;
    struct ListNode*n3=n2->next;
    while(n2!=NULL)
    {
        n2->next=n1;
        //迭代
        n1=n2;
        n2=n3;
        if(n3!=NULL)
        {
             n3=n3->next;
        }
    }
    return n1;
  
}

 

 

 

 

 

 

 

 

 

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    if (headA == NULL || headB == NULL) {
        return NULL;
    }
    struct ListNode *pA = headA, *pB = headB;
    while (pA != pB) {
        pA = pA == NULL ? headB : pA->next;
        pB = pB == NULL ? headA : pB->next;
    }
    return pA;
}

 

 

 

 

このトピックで使用される主なアイデアは、高速ポインタと低速ポインタのアイデアです。

 

bool hasCycle(struct ListNode* head) {
    if (head == NULL || head->next == NULL) {
        return false;
    }
    struct ListNode* slow = head;
    struct ListNode* fast = head->next;
    while (slow != fast) {
        if (fast == NULL || fast->next == NULL) {
            return false;
        }
        slow = slow->next;
        fast = fast->next->next;
    }
    return true;
}

方向性 2: 集めた便利なテクニックを共有する

リンク リストは、物理ストレージ ユニット上の非順次および非順次のストレージ構造であり、データ要素の論理的順序は、リンク リスト内のポインタのリンク順序を通じて実現されます。リンク リストは一連のノードで構成され (リンク リストの各要素はノードと呼ばれます)、ノードは実行時に動的に生成できます。各ノードは 2 つの部分で構成されます。1 つはデータ要素を格納するデータ フィールドで、もう 1 つは次のノードのアドレスを格納するポインタ フィールドです。線形リスト逐次構造に比べて演算が複雑になります。順序どおりに格納する必要がないため、リンク リストは挿入時に O(1) の複雑さに達する可能性があり、他の線形リスト シーケンス テーブルよりもはるかに高速ですが、ノードの検索またはアクセスに O(n) かかります。特定の番号が付けられたノード時間、および線形テーブルと順序テーブルの対応する時間計算量はそれぞれ O(logn) と O(1) です。
リンクリスト構造を使用すると、配列リンクリストのデータサイズを事前に知る必要があるという欠点を克服でき、リンクリスト構造はコンピュータのメモリ空間を最大限に活用し、柔軟なメモリの動的管理を実現できます。しかし、リンクリストは配列のランダム読み取りの利点を失い、同時にノードのポインタフィールドの増加により比較的大きなスペースオーバーヘッドを持ちます。リンク リストの最も明白な利点は、従来の配列が関連する項目を配置する方法が、メモリまたはディスク上のこれらのデータ項目の順序と異なる可能性があり、データのアクセスを異なる配置順序に変換する必要があることが多いことです。 。リンク リストでは、リスト上の任意の位置でノードの挿入と削除が可能ですが、ランダム アクセスは許可されません。リンク リストには、単一リンク リスト、二重リンク リスト、循環リンク リストなど、さまざまなタイプがあります。リンク リストは多くのプログラミング言語で実装できます。Lisp や Scheme などの言語の組み込みデータ型には、リンク リストへのアクセスと操作が含まれます。C、C++、Java などの手続き型言語またはオブジェクト指向言語は、リンク リストを生成するために可変ツールに依存しています。

線形テーブルのリンクされたストレージ表現の特徴は、線形テーブルのデータ要素を格納するために任意のストレージ ユニットのグループを使用することです (このストレージ ユニットのグループは連続または不連続にすることができます)。したがって、各データ要素とその直接の後続データ要素との間の論理的関係を表現するには、データ要素について、それ自体の情報を格納することに加えて、その直接後続者を示す情報(すなわち、直接後継の場所のストレージ)。「ノード」はこれら 2 つの情報部分で構成され、線形テーブル内のデータ要素を表します。線形テーブルの連鎖ストレージ表現の欠点の 1 つは、数値を見つけるには最初から開始する必要があり、非常に面倒なことです。
状況に応じて、リンク リストの他の拡張を自分で設計することもできます。ただし、リンクされたリストの点と辺は基本的に 1 対 1 に対応するため、一般に辺にはデータが付加されません (最初または最後のノードを除きますが、特別な場合はありません)。ただし、リンク リストがリンク リストのセクション内の前後のポインタの反転をサポートしている場合、横に反転マークを追加した方が便利な場合があるという特殊なケースがあります。
非線形リンク リストの場合は、ツリーやグラフなどの他の関連データ構造を参照できます。さらに、複数の線形リンク リスト (ジャンプ リスト) に基づいたデータ構造があり、挿入、削除、検索などの基本操作の速度は平衡二分木と同じ O(nlogn) に達します。
データ要素情報を格納するドメインをデータドメイン(ドメイン名をデータとする)、直後の格納場所を格納するドメインをポインタドメイン(ドメイン名を次とする)と呼びます。ポインタフィールドに格納される情報は、ポインタまたはリンクとも呼ばれます。
それぞれ ,,…, を表す N 個のノードで構成されるリンク リストは、線形リストのリンク ストレージ表現と呼ばれます。このタイプのリンク リストの各ノードにはポインタ フィールドが 1 つだけ含まれるため、単一リンク リストとも呼ばれます。線形リンクリスト。 

構造的に、リンク リストは、単一リンク、二重リンク リスト、および循環リストに分類できます。リスト)、ほとんどの対数の場合、次の 3 つのリンク リストのみを使用します。

単一リンク

単結合リストの記憶構造は比較的単純であり、記憶に関しては、任意の記憶単位のセットを使用して線形リストのデータ要素を記憶できます (この記憶単位のセットは連続でも不連続でも可能です)。各要素には 2 つのフィールドが含まれており、データ要素情報を格納するフィールドはデータ フィールドと呼ばれ、すぐ後の格納場所を格納するフィールドはポインタ フィールドと呼ばれます。ポインタフィールドに格納される情報をポインタまたはリンクと呼びます。以下の図に示すように、リンクはリスト内の次のノードを指しますが、最後のノードは null 値を指します。

 

二重リンクリスト

二重リンクリストの記憶構造は、単一リンクリストの記憶構造よりも複雑です。二重リンク リストでは、各ノードに 2 つのポインタ フィールドがあり、1 つは直接の後続ノードを指し、もう 1 つは直接の先行ノードを指します。接続が最後の接続である場合、NULL 値または空のリストを指します。以下に示すように:

循環リンクリスト (Circular List)

循環リンク リストは、リンク ストレージ構造の別の形式です。その特徴は、リストの最後のノードのポインタ フィールドが先頭ノードを指しており、リンクされたリスト全体がリングを形成していることです。したがって、次の図に示すように、テーブル内の任意のノードから開始して、テーブル内の他のノードを見つけることができます。

 

同様に、二重リンク リストは循環リンク リストを構築することもできます。循環リンクリストには 2 つの特徴があり、1 つはリンクリスト内に NULL ポインタが存在しないこと、2 つ目はリンクリストの記憶容量を増やす必要がないことです。 

  • メモリセルは連続していても不連続であってもよい
  • 各ノードには 2 つの部分、つまりデータ要素フィールドとポインター フィールドが含まれます。
  • ノードはポインタフィールドを介して接続されます 

方向性 3: 長い間塵が積もっていましたが、あなたが集めたものは今も役に立っていますか?

リンクリストの目的

  • ファイル システムの実現: リンク リストを使用してファイル システム内のファイル ディレクトリ構造を実現できます。各ノードはファイルまたはディレクトリを表すことができ、ファイル システム全体を複数のノードを含むリンク リスト構造とみなすことができます。
  • 並べ替え: リンク リストを使用して、マージ ソートやクイック ソートなどの並べ替えアルゴリズムを実装できます。これらのアルゴリズムでは通常、実行時にノードの動的な作成と削除が必要ですが、これがリンク リストの強みです。
  • 動的データの管理: リンク リストは、ノードを自由に追加および削除できる動的データ構造であるため、ファイル システム、オペレーティング システムのメモリ管理、ネットワーク プロトコルなど、動的にサイズ変更されたデータ コレクションを管理するためによく使用されます。
  • スパース データの保存: リンク リストは、スパース行列などのスパース データ構造を保存するために使用することもできます。リンク リストは、順序付けされていないデータのコレクションを効率的に管理および保存できるため、スパース データを保存する効率的な方法です。
  • さまざまなデータ構造を実装する: テーブルは、キュー、スタック、ハッシュ テーブルなどの他の効率的なデータ構造を実装するためによく使用されます。リンク リストは、O(1) 時間で実行できる効率的な挿入および削除操作を提供しますが、配列などの他のデータ構造では大量のデータの再配置が必要になります。

リンク リストで実装できるデータ構造:

  1. 線形データ構造: リンク リストを使用して、スタック、キュー、チェーン キューなどの線形データ構造を実装できます。リンク リストに基づくスタックとキューは動的に拡張できるため、配列ベースの実装よりも柔軟性が高くなります。
  2. ハッシュ テーブル: ハッシュ テーブルは、リンク リストを使用してハッシュの衝突 (Hash Collision) の問題を解決できます。リンク リストを使用してハッシュ バケットを形成できます。ハッシュの衝突が発生した場合、競合するデータが最後に追加されます。リンクされたリストの。
  3. グラフとツリー: リンク リストを使用して、複雑なグラフおよびツリー データ構造を記述および実装できます。また、各ノードはリンク リストを使用して、子ノードまたは隣接するノードを格納できます。
  • 効率的なメモリ アロケータの実現: リンク リストを使用してファイル システム内のファイル ディレクトリ構造を実現できます。各ノードはファイルまたはディレクトリを表すことができ、ファイル システム全体を複数のノードを含むリンク リスト構造とみなすことができます。

リンク リストは主に長さや量が不定なデータの管理を容易にするために使用され、配列に比べてこの種のデータを処理する際にメモリを節約できます。動的言語のインタプリタがメモリを管理するため、通常、動的言語ではリンク リストは必要ありませんが、スペース効率や挿入アクションの効率に特別な要件がある場合は、動的言語でリンク リストを使用することもできます。

リンク リストは、プログラム内で一連の可変長線形データを一時的に保存するためによく使用されます。

このような特性を持つデータはリンク リストに保存できます。

1. データは徐々に増加しています

2. データの長さは不定であり、最初のデータを格納する前に、今後どのくらいのデータを格納する必要があるか上限を決定することが困難、または上限が決定できても、上限が大きくなる多くの場合、可能なデータ長を超えてしまうため、一度に上限に従ってスペースを割り当てるのはコスト効率が良くありません。リンクされたリストは、新しいデータを追加する必要があるたびにメモリを適用できるため、無駄が発生せず、1 つのアプリケーションが不十分であるためにデータ量が制限されることもありません。

3. シリアル番号に応じてデータにランダムアクセスする必要がありません。

リスト コンテナーは、リンク リストである C++ STL で提供されます。同時に、STL は、上記の特性を持つデータを処理するために使用できるベクター コンテナも提供します。また、ベクターはランダム アクセスもサポートします (つまり、上記の 3 番目の要件は無視できます)。ただし、vector がデータを追加するとき、最初に割り当てられた連続メモリが使い果たされている場合、メモリを再割り当てして元のデータをコピーする必要があり、このとき、データ挿入の時間計算量は O(1) ではありません (定数時間ではありません)。起きています)。したがって、リンク リストが処理に適しているデータは、上記の特性に加えて、次の 4 番目の特性を備えているため、リンク リストが最適な選択となります。

4. データの追加とデータの削除の各アクションの時間計算量は O(1) (一定時間) であることが望まれます。


さて、Xiao Yalan の今日の共有はこれで終わりです。引き続き頑張りましょう!

 

 

おすすめ

転載: blog.csdn.net/weixin_74957752/article/details/132263682