データ構造 - ハンズオン実用的な二重リンクリスト

個々の公共の番号でこの記事の発信元:TechFlow、オリジナリティが信者を求めて、簡単ではありません


直接的なアルゴリズムをかむには少し難しすぎるので、物品の導入前SkipListは、その中で、一部の学生は、原因意識して、リストの理解の欠如にフィードバックを言いました。プラスこのトピックを続けるリニアこのテーブルので、スタックを導入し、以前の記事では、のは約一緒にお話しましょうリスト

リストには、多くのデータ構造の基礎であり、その最大の特徴は、広く多くのシナリオデータの頻繁な変更に使用されるため、高速な挿入、削除、およびのサポートです。そして、リストの強力な拡張性は、それは広く多くのバージョンの拡大と改善に関連し、使用されています。今日は、異常な方法リンクリストの改良版であるにも二重にリンクされたリストと呼ばれるダブルエンドリストを、ご紹介し、リストが使用されることが多いです。


単独リンクリスト


リストは、(リンクリスト)、共通の基本的なデータ構造、リニアテーブルですが、線状配列にデータを格納しませんが、むしろ内の各ノードで次のノード(ポインタ)へのポインタを維持します。これらは、ウィキペディアの定義の中で、我々は、複数のノードの最初のリストを二つのことを理解することができますされ、各ノードは次のノードの位置を格納します。第二に、リンクされたリストの各ノードは、順番に格納されていません。

私たちは、あなたがについて理解深めることができ、次のチャートを見てみましょう。

図に示すように片方向リンクリストと呼ばれる唯一のリストトラバーサル方向を言うことですそれらの片方向リンクリスト、各ノードは一つだけ後続ノードのポインタを持っていることを一方向の手段、。


追加と削除の一覧


リストの学習に初心者は、アレイへの直接アクセス、配列直感的として良いとして追加および削除を完了するために、ノードのノードの内容を変更するためにポインタを移動し、そのためではないことで、リストをトラバースする必要性と比較して、頭痛にその使用を得ることができます。私はいつも、私は多くのコンタクトリスト形式でスパイシステムの仕事を見つけ、スパイゲームを見て、時間まで、リストの動作メカニズムを説明する良い例を見つけるたいと思っていました。私はシステムをスパイすることを決めたので、例えば、リストの動作原理について教えてください。

あなたが共和国あると仮定国民党の指導者の、あなたは知性のリンクを担当しています。セキュリティのために、あなたとあなたのある男性の単方向リンクがあります。あなただけの一人にリンクすることができ、男性は最終的に目標信号の手を手渡し、連絡先、他の人に行きます。あなたのコードがAであると仮定すると、あなたの手は、Bの男性はC、Cがタスクを実行するためには、Bです。B神秘的な理由は、場所を移さ時間Aをもたらし、Bのリエゾンが長くなり、この問題を解決するために、あなたはAとBの間の連絡を担当するDのスタッフを追加することにしたので、このメカニズムは、1日まで、うまく実行されています接触速度をスピードアップします。それをどのようにすればよいですか?

制約のアイデンティティだけでなく、セキュリティ上の理由ので、あなたはBの詳細を知りません あなただけの、Aにメッセージを与える接点Dに新人をしましょう、そしてBは、彼が連絡先を伝える方法ですできます。ノートへのもう一つのポイント、AとBは、正常B Dのリンクを発見した後に切断し、それまで待たなければなりません。予期しない何かがD、この全体のリンクを発生し、それ以外の場合、それが壊れました。

次のように我々は全体像を出します:

連絡先は、それぞれ、AとB破られた後、D及びBは、連絡を取るためにしてみましょう。Aの後継者はDをポイントした場合、その後、Bの位置が失われます、唯一のものであるので、しかし、問題があります。私たちは、保管場所のB、Dポイントダウンし、一時変数CURを使用して、CURを聞かせする必要がありますので。しかし、Pythonで、私たちはできませんあまりにも面倒、多変数割り当てのPythonのメソッドを使用して、我々は、コードの行を取得することができます。

コードは以下の通りであります:

def add(pos, new_node):
    new_node.next, pos.next = pos.next, new_node

同じ場所までの時間、Bバックの期間にわたって、我々はDを必要としない、とあなたは何をするか、このノードを削除したい場合は?非常に単純な、それをAに最新の連絡先情報D Bに指示します。すなわち、両端のDに対する点BにAを可能にします。

地図を見ます:

def delete(pos):
    pos.next = pos.next.next


二重リンクリスト


私たちは、道リンクリスト、二重リンクリストと非常にシンプルに理解しています。双方向の意味は、各ノードの後続ノードの位置を記録するだけでなく、非常に明確である、意志がするソースレコードノードの位置を。あなたは、双方向のポインタを持っていたら便利なだけソースノードを取得し、簡単に全体のリストや、挿入ヘッドを横断するフラッシュバックすることができないだけ。

还记得我们之前Python专题当中介绍过的deque这个库吗?通过deque我们可以实现一个双向增删元素的队列,结合双向链表的定义,很容易发现deque其实就是保留了一部分api的双向链表。换句话说deque是基于双向链表实现的,就和栈是基于list实现的一样。

和单向链表相比,由于我们多了一个指针,理解和实现起来会更加容易,因为之前需要通过顺序关系以及临时变量完成的内容现在可以通过前向指针很轻易地实现了。

下面附上双向链表增删的代码:

def add(pos, new_node):
    pos.next, new_node.next = new_node, pos.next
    new_node.pre, new_node.next.pre = pos, new_node
    
    
def delete(pos):
    pos.next = pos.next.next
    # 这个时候pos.next已经更新
    pos.next.pre = pos


总结


双向链表本身并不复杂,也没有太多变化的花样,和之前介绍的SkipList相比要简单许多。我相信即使是初学者,只要自己动手实现一遍,也足够掌握。在我初学数据结构的时候,我非常抗拒使用链表,除了觉得寻址很麻烦,需要遍历整个链表耗时很大之外。另一个根本的原因是在C++当中链表的编写很麻烦,而且很容易有内存泄漏以及野指针问题。所以我当时尽可能地使用数组作为替代,并且甚至一度认为随着内存价格的降低,总有一天我们可以抛弃链表这个结构。

直到后来我学习了操作系统之后,我找到了一个必须使用链表的理由。因为在操作系统当中,内存并不是连续的,大部分内存都是分散的。当我们创建一个数组的时候,我们其实是在想操作系统申请一块连续的内存。我们申请的数组越大,这块内存也就越大。显然越大的内存越难申请到,因为内存大多被切分成了许多碎片,在资源不够的情况下,操作系统需要做大量的工作才能将碎片搜集起来。

而链表因为通过指针寻址,所以可以避免这个问题,链表当中的元素分散在内存各处,分摊了内存消耗的压力。这也是在操作系统领域当中,链表大量使用的原因。

最后,由于篇幅限制,我们没有放上全部的代码,想要获取完整双向链表代码的同学,可以关注我的公众号,回复“双向链表”获取。

今天的文章就到这里,如果觉得有所收获,请顺手点个关注或者转发吧,你们的举手之劳对我来说很重要。

おすすめ

転載: www.cnblogs.com/techflow/p/12418305.html