リンクリストの基本概念
リンク リストは線形データ構造であり、配列とは異なり、リンク リストの要素 (ノード) はポインタを介して相互に接続されます。リンク リストには次の基本概念があります。
-
ノード: リンクされたリスト内の各データ項目はノードと呼ばれ、各ノードにはデータと次のノードへのポインタが含まれます。
-
ヘッド ノード: リンク リストの最初のノードはヘッド ノードと呼ばれ、通常、リンク リスト全体の開始位置を表すために使用されます。
-
末尾ノード: リンクされたリストの最後のノードは末尾ノードと呼ばれ、そのポインタは通常 null を指します。
単連結リストと二重連結リストの違い
リンク リストは、単一リンク リストと二重リンク リストの2 つの主なタイプに分類できます。
-
単一リンク リスト: 各ノードには、次のノードへのポインタのみが含まれます。単一リンクリストのメモリオーバーヘッドはわずかですが、簡単に逆にたどることはできません。
-
二重リンク リスト: 各ノードには、次のノードと前のノードへのポインターが含まれます。二重リンクリストでは双方向のトラバーサルが可能ですが、メモリのオーバーヘッドが大きくなります。
リンクされたリストに対する一般的な操作
リンク リストは、次の一般的な操作をサポートします。
-
ノードの挿入: リンク リストに新しいノードを挿入するには、通常、隣接するノードのポインタを更新する必要があります。
-
ノードの削除: リンク リストからノードを削除するには、通常、隣接するノードのポインタを更新する必要があります。
-
逆リンク リスト: リンク リスト内のノードの順序を逆にします。
-
リンク リストの長さを取得する: リンク リスト内のノードの数を取得します。
以下は、単一リンク リストを作成し、ノードを挿入および削除し、リンク リストの長さを取得する簡単な C++ の例です。
#include <iostream>
// 链表节点定义
struct Node {
int data; // 节点数据
Node* next; // 指向下一个节点的指针
};
int main() {
// 创建链表头节点
Node* head = nullptr;
// 插入节点
Node* newNode1 = new Node;
newNode1->data = 1;
newNode1->next = nullptr;
head = newNode1;
Node* newNode2 = new Node;
newNode2->data = 2;
newNode2->next = nullptr;
newNode1->next = newNode2;
// 删除节点
delete newNode1;
head = newNode2;
// 获取链表长度
int length = 0;
Node* current = head;
while (current != nullptr) {
length++;
current = current->next;
}
std::cout << "链表长度:" << length << std::endl;
return 0;
}
練習問題:
- 単一リンクリストと二重リンクリストの主な違いは何ですか? どのような状況で、単一リンク リストまたは二重リンク リストの使用を選択しますか?
- データの保存と管理には配列よりもリンク リストの方が適している状況について説明します。
- リンクされたリストに新しいノードを挿入するにはどうすればよいですか? この操作の時間計算量はどれくらいですか?
- リンクされたリスト内のノードを削除するにはどうすればよいですか? この操作の時間計算量はどれくらいですか?
単一リンクリストと二重リンクリストの主な違いは何ですか? どのような状況で、単一リンク リストまたは二重リンク リストの使用を選択しますか?
-
単一リンク リスト: 単一リンク リストの各ノードには、ポインターが 1 つだけ含まれます。通常は、次のノードへのポインターです。この構造はメモリのオーバーヘッドが少なくなりますが、一方向にしかトラバースできません。単一リンク リストは、メモリ オーバーヘッドが制限されている場合にデータへの一方向のアクセスが必要なシナリオに適しています。
-
二重リンク リスト: 二重リンク リストの各ノードには 2 つのポインターが含まれており、1 つは次のノードを指し、もう 1 つは前のノードを指します。これにより双方向のトラバーサルが可能になりますが、メモリのオーバーヘッドが大きくなります。二重リンク リストは、双方向のトラバーサルや、リンク リストの途中でノードを頻繁に挿入および削除する必要がある状況に適しています。
単一リンク リストを使用するか二重リンク リストを使用するかの選択は、要件によって異なります。一方向のアクセスのみが必要な場合、またはメモリが制限されている場合は、単一リンク リストの方が適切な場合があります。双方向のトラバーサルやノードの頻繁な挿入と削除が必要な場合は、二重リンク リストの方が適切な場合があります。
データの保存と管理には配列よりもリンク リストの方が適している状況について説明します。
次の状況では、配列よりもリンク リストの方が適しています。
-
動的サイズ: データ セットのサイズが実行時に変化する場合、配列のサイズは通常は固定されているのに対し、リンク リストは動的にメモリを割り当てたり解放したりできるため、より適しています。
-
頻繁な挿入と削除: データ項目の頻繁な挿入と削除が必要な場合、挿入と削除の操作の時間計算量が O(1) であるのに対し、配列での同じ操作には通常 O が必要となるため、リンク リストの方が配列より効率的です。 (n)。
-
ランダム アクセスは不要: ランダム アクセス (インデックスを使用) せずにデータに順次アクセスする必要があるだけの場合は、リンク リストが適しています。
リンクされたリストに新しいノードを挿入するにはどうすればよいですか? この操作の時間計算量はどれくらいですか?
新しいノードを挿入する手順は次のとおりです。
- 新しいノードを作成し、そのデータとポインタを設定します。
- 新しいノードのポインタを更新して、元のリンク リスト内の適切な位置にあるノードを指すようにします。
- 元のリンク リスト内の隣接ノードのポインタを、新しいノードを指すように更新します。
この操作の時間の複雑さは、挿入位置によって異なります。挿入位置がわかっている場合は、ポインターを変更するだけでよいため、時間計算量はO(1)になります。リンク リストの途中に挿入する必要があり、挿入位置を見つけるためにトラバースする必要がある場合、時間計算量はO(n)になります。ここで、n はリンク リストの長さです。
リンクされたリスト内のノードを削除するにはどうすればよいですか? この操作の時間計算量はどれくらいですか?
リンク リスト内のノードを削除する手順は次のとおりです。
- 削除するノードを見つけます。
- 隣接するノードのポインタを更新して、削除するノードをスキップします。
- 削除するノードのメモリを解放します。
この操作の時間の複雑さは、削除するノードを見つけるのにかかる時間によって異なります。削除位置がわかっている場合は、ポインタを変更するだけでよいため、計算量はO(1)となる。削除するノードを見つけるためにリンク リストを走査する必要がある場合、時間計算量はO(n)になります。ここで、n はリンク リストの長さです。
メモリ リークを避けるために、ノードを削除する前に必ずノードのメモリを解放してください。