資料結構入門-C語言實作環狀串列教學

更新於 發佈於 閱讀時間約 12 分鐘

前導

環狀鏈結串列是一種特殊的鏈結串列,其最後一個節點的指標指向第一個節點,而非 NULL,形成一個循環結構。如下圖所示:

raw-image

一、環狀鏈結串列的插入(Insertion)

插入新節點時,可能發生在:

  1. 空串列時的插入
  2. 頭部插入(Head insertion)
  3. 尾部插入(Tail insertion)
  4. 中間插入(After a given node)

1. 插入至空的環狀鏈結串列

當鏈結串列為空時,插入的節點既是 head 也是 tail,並且它的 next 指向自己。

  1. 創建新節點 newNode
  2. 設定 newNode->next = newNode 形成環狀
  3. head = newNodetail = newNode

2. 在頭部插入節點

  1. 創建新節點 newNode
  2. newNode->next = head(新節點指向當前頭部)
  3. tail->next = newNode(尾部節點指向新頭部)
  4. 更新 head = newNode

👉 效果:新節點變成 head,但環狀結構保持不變。

raw-image

3. 在指定節點後插入

  1. 找到目標節點 X
  2. newNode->next = X->next
  3. X->next = newNode

👉 效果:新節點插入 X 之後,環狀結構保持。

raw-image

4. 在尾部插入節點

  1. 創建新節點 newNode
  2. tail->next = newNode(當前尾部指向新節點)
  3. newNode->next = head(新節點指向 head
  4. 更新 tail = newNode
  5. 讀者可以自行思考並繪圖。

👉 效果:新節點變成 tail,環狀結構保持。


二、環狀鏈結串列的刪除(Deletion)

刪除節點時,可能發生在:

  1. 刪除頭部節點
  2. 刪除中間節點
  3. 刪除尾部節點
  4. 刪除最後一個節點(使串列變空)

1. 刪除頭部節點

  1. head = head->next(更新 head 指向下一個節點)
  2. tail->next = head(尾部保持指向新的 head

👉 效果:原head 被移除,環狀結構保持。

raw-image

2. 刪除中間節點

  1. 找到 X 的前一個節點 prev
  2. prev->next = X->next

👉 效果:節點 X 被移除,環狀結構保持。

raw-image

3. 刪除尾部節點

  1. 找到 tail 的前一個節點 prev
  2. prev->next = head
  3. 更新 tail = prev
  4. 讀者可以自行思考並繪圖。

👉 效果:新 tail 成為 prev,環狀結構保持。

C語言實作

#include <stdio.h>
#include <stdlib.h>

// 定義節點結構
typedef struct Node {
int data;
struct Node* next;
} Node;

// 創建新節點
Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
newNode->next = newNode; // 初始指向自己
return newNode;
}

// 插入到空的環狀鏈結串列
void insertEmpty(Node** head, int data) {
if (*head != NULL) return;
*head = createNode(data);
}

// 在頭部插入節點
void insertHead(Node** head, int data) {
if (*head == NULL) {
insertEmpty(head, data);
return;
}
Node* newNode = createNode(data);
newNode->next = *head;

// 找到 tail
Node* temp = *head;
while (temp->next != *head) temp = temp->next;
temp->next = newNode;
*head = newNode; // 更新 head
}

// 在尾部插入節點
void insertTail(Node** head, int data) {
if (*head == NULL) {
insertEmpty(head, data);
return;
}
Node* newNode = createNode(data);
Node* temp = *head;

while (temp->next != *head) temp = temp->next;

temp->next = newNode;
newNode->next = *head;
}

// 在指定節點後插入
void insertAfter(Node* prevNode, int data) {
if (prevNode == NULL) return;

Node* newNode = createNode(data);
newNode->next = prevNode->next;
prevNode->next = newNode;
}

// 刪除頭部節點
void deleteHead(Node** head) {
if (*head == NULL) return;

// 只有一個節點
if ((*head)->next == *head) {
free(*head);
*head = NULL;
return;
}

Node* temp = *head;
while (temp->next != *head) temp = temp->next;

Node* toDelete = *head;
*head = (*head)->next;
temp->next = *head;
free(toDelete);
}

// 刪除尾部節點
void deleteTail(Node** head) {
if (*head == NULL) return;

// 只有一個節點
if ((*head)->next == *head) {
free(*head);
*head = NULL;
return;
}

Node* temp = *head;
Node* prev = NULL;

// 找到尾部與前一個節點
while (temp->next != *head) {
prev = temp;
temp = temp->next;
}

prev->next = *head; // 讓前一個節點變成新的尾部
free(temp);
}

// 刪除指定值的節點
void deleteNode(Node** head, int key) {
if (*head == NULL) return;

Node *curr = *head, *prev = NULL;
while (curr->data != key) {
if (curr->next == *head) return; // 沒找到
prev = curr;
curr = curr->next;
}

if (curr == *head) { // 如果刪除的是頭部
deleteHead(head);
return;
}

prev->next = curr->next;
free(curr);
}

// 列印環狀鏈結串列
void printList(Node* head) {
if (head == NULL) {
printf("什麼都沒有啦~哥!!");
return;
}
Node* temp = head;
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != head);
printf("(head)\n");
}

// 主程式
int main() {
Node* head = NULL;

insertHead(&head, 10);
insertHead(&head, 20);
insertTail(&head, 30);
insertTail(&head, 40);
printList(head); // 20 -> 10 -> 30 -> 40 -> (head)

deleteHead(&head);
printList(head); // 10 -> 30 -> 40 -> (head)

deleteTail(&head);
printList(head); // 10 -> 30 -> (head)

insertAfter(head, 25); // 在 10 之後插入 25
printList(head); // 10 -> 25 -> 30 -> (head)

deleteNode(&head, 25);
printList(head); // 10 -> 30 -> (head)

deleteHead(&head); // 30 -> (head)
printList(head);

//deleteHead(&head); // 什麼都沒有啦~哥!!
//deleteTail(&head); // 什麼都沒有啦~哥!!
deleteNode(&head, 30); // 什麼都沒有啦~哥!!
printList(head);

return 0;
}

輸出:

20 -> 10 -> 30 -> 40 -> (head)
10 -> 30 -> 40 -> (head)
10 -> 30 -> (head)
10 -> 25 -> 30 -> (head)
10 -> 30 -> (head)
30 -> (head)
什麼都沒有啦~哥!!

主程式使用的函式總結

插入

  • insertHead(&head, data)在頭部插入,當鏈結串列為空時呼叫insertEmpty(&head, data)
  • insertTail(&head, data)在尾部插入
  • insertAfter(Node* prevNode, data)在指定節點後插入

刪除

  • deleteHead(&head)刪除頭部節點
  • deleteTail(&head)刪除尾部節點
  • deleteNode(&head, key)刪除指定值的節點

額外

  • printList(head)列印環狀鏈結串列
留言
avatar-img
留言分享你的想法!
avatar-img
電資鼠 - 您的學習好夥伴
10會員
215內容數
在當今數位時代,電資領域人才需求爆發式成長,不論是前端網頁設計、嵌入式開發、人工智慧、物聯網還是軟硬體整合,這些技術都在改變世界。而掌握 C/C++、Python、數位邏輯、電路學與嵌入式開發等大學電資領域的課程,正是進入這個高薪、高需求產業的關鍵!
2025/03/09
雙向串列 (Double Linked List, DLL) 是一種鏈結資料結構,本章節將以完整註解,搭配關鍵操作地方的圖示輔助學習,讓你輕鬆搞懂複雜觀念,並透過C語言實作。
Thumbnail
2025/03/09
雙向串列 (Double Linked List, DLL) 是一種鏈結資料結構,本章節將以完整註解,搭配關鍵操作地方的圖示輔助學習,讓你輕鬆搞懂複雜觀念,並透過C語言實作。
Thumbnail
2025/03/07
本章節將探討右上三角稀疏矩陣。
Thumbnail
2025/03/07
本章節將探討右上三角稀疏矩陣。
Thumbnail
2025/03/07
稀疏矩陣(Sparse Matrix)是指在大多數元素為零的矩陣。由於存儲完整的稀疏矩陣會浪費大量內存,因此通常使用特殊的數據結構來存儲和操作稀疏矩陣。在 C 語言中,可以將稀疏矩陣的非零元素以row、column、value的方式存放。 本章節將會帶領你認識此資工科中會教的重要觀念並實作程式碼。
Thumbnail
2025/03/07
稀疏矩陣(Sparse Matrix)是指在大多數元素為零的矩陣。由於存儲完整的稀疏矩陣會浪費大量內存,因此通常使用特殊的數據結構來存儲和操作稀疏矩陣。在 C 語言中,可以將稀疏矩陣的非零元素以row、column、value的方式存放。 本章節將會帶領你認識此資工科中會教的重要觀念並實作程式碼。
Thumbnail
看更多
你可能也想看
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
2025 vocus 推出最受矚目的活動之一——《開箱你的美好生活》,我們跟著創作者一起「開箱」各種故事、景點、餐廳、超值好物⋯⋯甚至那些讓人會心一笑的生活小廢物;這次活動不僅送出了許多獎勵,也反映了「內容有價」——創作不只是分享、紀錄,也能用各種不同形式變現、帶來實際收入。
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
題目敘述 Merge Nodes in Between Zeros 給定一個鏈結串列,合併非零區間的節點(以加總的方式合併),輸出合併後的鏈結串列。
Thumbnail
題目敘述 Merge Nodes in Between Zeros 給定一個鏈結串列,合併非零區間的節點(以加總的方式合併),輸出合併後的鏈結串列。
Thumbnail
Append Characters to String to Make Subsequence 給定兩個字串s和字串t。 請計算最少的字元串接數量是多少,串接在s的尾端,使得t是s的子序列。 測試範例 Example 1: Input: s = "coaching", t =
Thumbnail
Append Characters to String to Make Subsequence 給定兩個字串s和字串t。 請計算最少的字元串接數量是多少,串接在s的尾端,使得t是s的子序列。 測試範例 Example 1: Input: s = "coaching", t =
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
題目敘述 輸入給定一個鏈結串列,整體看代表一個十進位的數字,各別看每個節點代表每個digit,分別從最高位~最低位個位數。 要求我們把原本的數字乘以二,並且以鏈結串列的形式返回答案。 原本的英文題目敘述
Thumbnail
題目敘述 輸入給定一個鏈結串列的head node。 要求我們進行化簡,只要某個節點的右手邊存在比較大的節點,就刪除掉。 例如 5->2->13->3 5的右手邊有13,所以5刪除掉。 2的右手邊有13,所以2刪除掉。 13的右手邊沒有更大的節點,所以13留著。 3的右手邊沒有更大
Thumbnail
題目敘述 輸入給定一個鏈結串列的head node。 要求我們進行化簡,只要某個節點的右手邊存在比較大的節點,就刪除掉。 例如 5->2->13->3 5的右手邊有13,所以5刪除掉。 2的右手邊有13,所以2刪除掉。 13的右手邊沒有更大的節點,所以13留著。 3的右手邊沒有更大
Thumbnail
這篇文章,會帶著大家複習以前學過的 區間DP框架, 並且以回文子字串、回文子序列的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 回文字串的基本定義 s = s[::-1] 也就是說字串s的正序 和 逆序完全相同。 回文字串的基本結構 空字串"
Thumbnail
這篇文章,會帶著大家複習以前學過的 區間DP框架, 並且以回文子字串、回文子序列的應用題與概念為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 回文字串的基本定義 s = s[::-1] 也就是說字串s的正序 和 逆序完全相同。 回文字串的基本結構 空字串"
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
這篇文章,會帶著大家複習以前學過的遞回框架, 並且鏈結串列的概念與應用為核心, 貫穿一些相關聯的題目,透過框架複現來幫助讀者理解這個演算法框架。 遞回框架 尋找共通模式(common pattern),對應到演算法的General case 確立初始條件(initial conditio
Thumbnail
題目敘述 題目會給定一個鏈結串列的起始點,要求我們把其中區間總和為0的部分刪除掉。 例如 1→ 2 → -2 → 3 → 4 裡面有一段是2 → -2 區間總和為零,所以簡化刪除後變成 1→ 3 → 4 題目的原文敘述 測試範例 Example 1: Input: head
Thumbnail
題目敘述 題目會給定一個鏈結串列的起始點,要求我們把其中區間總和為0的部分刪除掉。 例如 1→ 2 → -2 → 3 → 4 裡面有一段是2 → -2 區間總和為零,所以簡化刪除後變成 1→ 3 → 4 題目的原文敘述 測試範例 Example 1: Input: head
Thumbnail
題目敘述 題目會給定一個鏈結串列 Linked List的頭部結點,要求我們根據索引的奇偶數重新排列。奇數索引的在前,偶數索引的在後。數的時候,從Head節點的索引=1開始數。 例如: 1 -> 2 -> 3 -> 4 -> 5 重新排列為 1 -> 3 -> 5 -> 2 -> 4
Thumbnail
題目敘述 題目會給定一個鏈結串列 Linked List的頭部結點,要求我們根據索引的奇偶數重新排列。奇數索引的在前,偶數索引的在後。數的時候,從Head節點的索引=1開始數。 例如: 1 -> 2 -> 3 -> 4 -> 5 重新排列為 1 -> 3 -> 5 -> 2 -> 4
Thumbnail
題目敘述 題目會給定我們一條鏈結串列Linked list的起始節點,要求我們刪除Linked List正中央的節點。 註: 正中央的節點,題目定義為索引為floor( 串列長度 / 2 ) 的節點,索引從零(Head Node)出發開始數。 例如 1 -> 2 -> 3 -> 4 鏈結
Thumbnail
題目敘述 題目會給定我們一條鏈結串列Linked list的起始節點,要求我們刪除Linked List正中央的節點。 註: 正中央的節點,題目定義為索引為floor( 串列長度 / 2 ) 的節點,索引從零(Head Node)出發開始數。 例如 1 -> 2 -> 3 -> 4 鏈結
Thumbnail
巢狀迴圈For loop介紹結構及範例說明 巢狀迴圈 巢狀迴圈是在一個迴圈內包含另一個迴圈的結構 簡單來說,就是內迴圈做完,才會在跑到外迴圈,接著在做內迴圈
Thumbnail
巢狀迴圈For loop介紹結構及範例說明 巢狀迴圈 巢狀迴圈是在一個迴圈內包含另一個迴圈的結構 簡單來說,就是內迴圈做完,才會在跑到外迴圈,接著在做內迴圈
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News