Circular Singly Linked List เป็นลิงค์ลิสต์ที่ Node สุดท้ายชี้กลับไปที่ Head (Node แรก) สร้างวงกลม
ลักษณะเฉพาะ
- Node แต่ละตัวมี
data และ next เท่านั้น (เหมือน Singly)
- Node สุดท้าย
next ชี้ไป Head ไม่ใช่ NULL
- สามารถเริ่มเดินจาก Node ใดก็ได้ และวนกลับมาเดิม
- ไม่มี "ปลาย" ชัดเจน - ต้องระวัง Infinite Loop
โครงสร้าง Node
struct Node {
int data;
Node* next;
};
Node* head = nullptr;
โค้ดโปรแกรม Circular Singly Linked List
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
};
Node* head = nullptr;
// เพิ่มที่หน้า (Insert at Front)
void insert(int newData) {
Node* newNode = new Node();
newNode->data = newData;
newNode->next = head;
if (head != nullptr) {
// หา Node สุดท้าย (ที่ชี้ไป head)
Node* ptr = head;
while (ptr->next != head)
ptr = ptr->next;
ptr->next = newNode; // Node สุดท้ายชี้ไป Node ใหม่
} else {
// ลิสต์ว่าง: Node ชี้ตัวเอง
newNode->next = newNode;
}
head = newNode; // Head ชี้ไป Node ใหม่
}
// เพิ่มที่ท้าย (Append)
void append(int newData) {
Node* newNode = new Node();
newNode->data = newData;
if (head == nullptr) {
newNode->next = newNode;
head = newNode;
return;
}
Node* ptr = head;
while (ptr->next != head)
ptr = ptr->next;
ptr->next = newNode;
newNode->next = head;
}
// แสดงข้อมูล (ใช้ do-while เพราะต้องรันอย่างน้อย 1 รอบ)
void display() {
if (head == nullptr) {
cout << "List is empty" << endl;
return;
}
Node* ptr = head;
cout << "Circular List: ";
do {
cout << ptr->data << " ";
ptr = ptr->next;
} while (ptr != head);
cout << endl;
}
// ลบ Node แรก (Delete Front)
void deleteFront() {
if (head == nullptr) return;
if (head->next == head) { // มีแค่ 1 Node
delete head;
head = nullptr;
return;
}
// หา Node สุดท้าย
Node* ptr = head;
while (ptr->next != head)
ptr = ptr->next;
Node* temp = head;
ptr->next = head->next; // Node สุดท้ายชี้ไป Node ที่ 2
head = head->next; // Head ชี้ไป Node ที่ 2
delete temp;
}
// ลบ Node ตามค่า (Delete by Value)
void deleteValue(int key) {
if (head == nullptr) return;
Node* curr = head;
Node* prev = nullptr;
// หา Node ที่ต้องการลบ
do {
if (curr->data == key) break;
prev = curr;
curr = curr->next;
} while (curr != head);
if (curr->data != key) {
cout << "Value not found" << endl;
return;
}
// กรณีมีแค่ 1 Node
if (curr->next == curr) {
delete curr;
head = nullptr;
return;
}
// กรณีลบ Head
if (curr == head) {
// หา tail
Node* tail = head;
while (tail->next != head)
tail = tail->next;
tail->next = head->next;
head = head->next;
delete curr;
return;
}
// กรณีลบ Node กลาง/ท้าย
prev->next = curr->next;
delete curr;
cout << key << " deleted." << endl;
}
int main() {
insert(3);
insert(1);
insert(7);
insert(2);
insert(9);
cout << "Circular Linked List:" << endl;
display();
append(99);
cout << "After append(99):" << endl;
display();
deleteFront();
cout << "After deleteFront():" << endl;
display();
deleteValue(7);
cout << "After deleteValue(7):" << endl;
display();
return 0;
}
ผลลัพธ์ตัวอย่าง
Circular Linked List:
Circular List: 9 2 7 1 3
After append(99):
Circular List: 9 2 7 1 3 99
After deleteFront():
Circular List: 2 7 1 3 99
After deleteValue(7):
Circular List: 2 1 3 99
จุดสำคัญในการเขียน Circular List
จุดระวัง
คำอธิบาย |
| Infinite Loop | ใช้ do-while หรือตรวจสอบ ptr != head |
| Empty List | head = nullptr หรือ head->next == head |
| Single Node | head->next == head (ชี้ตัวเอง) |
| Update Tail | ทุกครั้งที่ insert/delete head ต้อง update tail->next |
การประยุกต์ใช้
- Round Robin Scheduling (CPU scheduling)
- Circular Buffer / Ring Buffer
- Playlist ที่เล่นวนรอบ
- Game loop - จัดการผู้เล่นแบบวนรอบ
เปรียบเทียบ Singly / Doubly / Circular
| ประเภท |
Next |
Prev |
Last→First |
Traversal |
| Singly | ✓ | ✗ | ✗ | Forward only |
| Doubly | ✓ | ✓ | ✗ | Both ways |
| Circular Singly | ✓ | ✗ | ✓ | Forward (circular) |
| Circular Doubly | ✓ | ✓ | ✓ | Both ways (circular) |