リンクされたリストは、配列とは異なり、連続したメモリ空間を必要としません。図に示すように、「ポインタ」を使用して、分散したメモリブロックのグループを連結します。
単一リンクリスト
リンクリストには多くの種類があります。最も単純なのは、単一のリンクリストです。単一のリンクリストは、最もオリジナルのリンクリストです。その構造を図に示し
ます。最初のノードと最後のノードという2つのノードが特別なリンクリストにあります。 。通常、最初のノードをヘッドノード、最後のノードをテールノードと呼びます。
その中で、ヘッドノードはリンクリストのベースアドレスを記録するために使用され、これを使用して、リンクリスト全体を取得できます。テールノードの特別な場所は次のとおりです。ポインタは次のノードを指さず、空のアドレスNULLを指しています。これは、これがリンクリストの最後のノードであることを示しています。
単一リンクリストの場合、理論的には、ノードの挿入と削除の時間の複雑さはO(1)であり、ノードのクエリの時間の複雑さはO(n)です。
循環リスト
次に、単一のリンクリストに基づいて拡張された循環リンクリストもあります。循環リンクリストと単一リンクリストの違いは、テールノードがヘッドノードを指しているため、ヘッドとテールが接続されており、ヘビのようなものであり、「ジョセフリング」の問題を解決するために使用できます。循環リンクリストの構造を図に示します。
二重リンクリスト
さらに、より一般的な二重リンクリストがあります。名前が示すように、二重リンクリストと単一リンクリストの違いは、次のノードへのポインターに加えて、前のノードへのポインターもあるため、O(1)複雑さは前のノードを見つけます。二重リンクリストは、単一リンクリストよりもノードの挿入と削除の方が効率的であるのはこのノードのためです。単一リンクリストの挿入と削除の時間の複雑さはすでにO(1)であると既に述べましたが、これは考慮されていませんが、挿入操作と削除操作自体については、削除を例にとります。ノードを削除した後、その前駆ノードのポインターを削除されたノードの次のノードにポイントする必要があります。このようにして、単一リンクリストで取得されるその前駆ノードも取得する必要があります。先行ノードの時間の複雑さはO(n)であるため、単一リンクリストの削除および挿入操作の全体的な時間の複雑さもO(n)ですが、二重リンクリストはそうではありません。前のノードへのポインターがあるため、その挿入そして、削除時間の複雑さが本当のO(1)です。
さらに、順序付けられたリンクリストの場合、二重リンクリストのクエリ効率は単一リンクリストのクエリ効率よりも明らかに高くなりますが、時間の複雑さは、スペースの複雑さの悪さと交換されます。二重リンクリストは、常に単一リンクリストの2倍のスペースを必要とします。ただし、前述したように、Webアプリケーションでは時間効率が優先されるため、通常は時間をスペースで使用してパフォーマンスを向上させます。JavaのLinkedHashMapは、下部にある二重リンクリストを使用します。
二重リンクリストの構造を図に示します。
二重循環リンクリスト
最後に紹介するのは、循環リストと二重リンクリストを組み合わせた二重循環リストです。
実際には、二重リンクリストの先頭と末尾をポインタで結びます。
配列関数シミュレーションにより単一リンクリストを実現
PHPにはポインターがないため、配列next、current、keyなどの関数を使用して、リンクリストのデータ構造を実現できます。
<?php
/**
* 通过 PHP 数组模拟实现单链表
*/
class LinkedList
{
private $list = [];
// 获取链表指定位置的元素值,从0开始
public function get($index)
{
$value = NULL;
while (current($this->list)) {
if (key($this->list) == $index) {
$value = current($this->list);
}
next($this->list);
}
reset($this->list);
return $value;
}
// 在链表指定位置插入值,默认插到链表头部
public function add($value, $index = 0)
{
array_splice($this->list, $index, 0, $value);
}
// 从链表指定位置删除元素
public function remove($index)
{
array_splice($this->list, $index, 1);
}
public function isEmpty()
{
return !next($this->list);
}
public function size()
{
return count($this->list);
}
}
$linkedList = new LinkedList();
$linkedList->add(4);
$linkedList->add(5);
$linkedList->add(3);
print $linkedList->get(1); # 输出5
$linkedList->add(1, 1); # 在结点1的位置上插入1
print $linkedList->get(1); # 输出1
$linkedList->remove(1); # 移除结点1上的元素
print $linkedList->get(1); # 输出5
print $linkedList->size(); # 输出3
PHPでは、配列はすべてのデータ構造(配列、リスト、ハッシュテーブル、マップなど)を統合します。PHPはポインターをサポートしていないため、実際のリンクリストを実装することはできません。たとえば、挿入または削除時にポインター挿入の変更を行うことはできません。要素の挿入と削除は、一般にarray_splice関数を介してのみ実行でき、一方向リンクリスト、双方向リンクリスト、循環リンクリストを区別する方法はありません。ただし、PHPの最下層で提供されるSPLライブラリには、二重リンクリストの実装が含まれています。http://php.net/manual/zh/class.spldoublylinkedlist.php