連結リスト(基本操作)
ノードとポインタで構成される動的データ構造の基本操作を学ぼう
O(1)〜O(n)
時間計算量
O(n)
空間計算量
上級
難易度
動的
データ構造
🔧 操作設定
現在の連結リスト:
1 → 2 → 3 → null
選択した操作:
insertTail(4)
リストサイズ:
3 ノード
先頭:
1
末尾:
3
🔗 動的構造: ノード → ノード → ... → null
📚 推奨操作例
🔗
連結リスト操作を実行してください
左側の設定パネルから操作を選択し、「連結リスト操作実行」ボタンを押してください
💻 実装例(JavaScript)
// ノードクラス
class ListNode {
constructor(value) {
this.value = value;
this.next = null;
}
}
// 連結リストクラス
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
// 先頭に挿入 - O(1)
insertHead(value) {
const newNode = new ListNode(value);
newNode.next = this.head;
this.head = newNode;
this.size++;
return this.size;
}
// 末尾に挿入 - O(n)
insertTail(value) {
const newNode = new ListNode(value);
if (!this.head) {
this.head = newNode;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = newNode;
}
this.size++;
return this.size;
}
// 指定位置に挿入 - O(n)
insertAt(index, value) {
if (index < 0 || index > this.size) {
throw new Error("インデックスが範囲外です");
}
if (index === 0) {
return this.insertHead(value);
}
const newNode = new ListNode(value);
let current = this.head;
for (let i = 0; i < index - 1; i++) {
current = current.next;
}
newNode.next = current.next;
current.next = newNode;
this.size++;
return this.size;
}
// 先頭を削除 - O(1)
deleteHead() {
if (!this.head) {
throw new Error("リストが空です");
}
const deletedValue = this.head.value;
this.head = this.head.next;
this.size--;
return deletedValue;
}
// 末尾を削除 - O(n)
deleteTail() {
if (!this.head) {
throw new Error("リストが空です");
}
if (!this.head.next) {
const deletedValue = this.head.value;
this.head = null;
this.size--;
return deletedValue;
}
let current = this.head;
while (current.next.next) {
current = current.next;
}
const deletedValue = current.next.value;
current.next = null;
this.size--;
return deletedValue;
}
// 値を検索 - O(n)
find(value) {
let current = this.head;
let index = 0;
while (current) {
if (current.value === value) {
return index;
}
current = current.next;
index++;
}
return -1; // 見つからない場合
}
// リストの内容を配列で表示
toArray() {
const result = [];
let current = this.head;
while (current) {
result.push(current.value);
current = current.next;
}
return result;
}
// リストの構造を文字列で表示
toString() {
if (!this.head) {
return "空のリスト";
}
return this.toArray().join(" → ") + " → null";
}
// リストのサイズを取得 - O(1)
getSize() {
return this.size;
}
// リストが空かどうかを確認 - O(1)
isEmpty() {
return this.head === null;
}
}
// 使用例
const list = new LinkedList();
// 要素の挿入
list.insertHead(2); // [2]
list.insertHead(1); // [1, 2]
list.insertTail(4); // [1, 2, 4]
list.insertAt(2, 3); // [1, 2, 3, 4]
console.log(list.toString()); // "1 → 2 → 3 → 4 → null"
// 要素の検索
console.log(list.find(3)); // 2 (インデックス)
console.log(list.find(5)); // -1 (見つからない)
// 要素の削除
console.log(list.deleteHead()); // 1
console.log(list.deleteTail()); // 4
console.log(list.toString()); // "2 → 3 → null"
// 状態の確認
console.log(list.getSize()); // 2
console.log(list.isEmpty()); // false
🎯 連結リストの特徴
基本特性
- • 動的にサイズが変更可能
- • ノードとポインタによる構造
- • 先頭操作は高速(O(1))
- • 検索は線形時間(O(n))
実世界での応用
- • ウェブブラウザの履歴管理
- • 音楽プレイヤーのプレイリスト
- • メモリ管理システム
- • スタック・キューの実装基盤
💡 ポイント: 連結リストは動的データ構造の基本で、ポインタ操作の理解に重要です。 配列とは異なる利点と制約を理解しましょう。