Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

โปรแกรม C++ สร้าง Circular Singly Linked List (ลิงค์ลิสต์วนแบบเดี่ยว)

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 Listhead = nullptr หรือ head->next == head
Single Nodehead->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)