ลิงก์ลิสต์แบบสองทาง
ลิงก์สองทิศทาง
ลิงก์ลิสต์แบบสองทาง เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
ตัวเชื่อมโยงสองทาง
รายการเชื่อมโยงแบบสองทางให้ตัวชี้แก่แต่ละโหนดสองตัว ได้แก่ ตัวหนึ่งชี้ไปยังโหนด next และอีกตัวชี้ไปยังโหนด prev (โหนดก่อนหน้า)
วิธีนี้ทำให้เดินรายการได้ทั้งสองทิศทางและทำให้การลบง่ายขึ้น
#include <stdio.h>
struct Node {
int value;
struct Node *prev;
struct Node *next;
};
int main(void) {
printf("Each node links forward and backward\n");
return 0;
}การกำหนดโหนด
โครงสร้างจะเพิ่มตัวชี้ prev ควบคู่กับ next โดยทั้งสองค่าจะเป็น NULL ที่ปลายทั้งสองด้านของรายการ
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
int main(void) {
struct Node *n = malloc(sizeof(struct Node));
n->value = 1; n->prev = NULL; n->next = NULL;
printf("%d\n", n->value);
free(n);
return 0;
}ตัวช่วยสร้าง
เช่นเดียวกับก่อนหน้านี้ ตัวช่วยจะรวมการจัดสรรหน่วยความจำไว้ในที่เดียว และกำหนดทั้ง prev และ next เป็น NULL
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v) {
struct Node *n = malloc(sizeof(struct Node));
n->value = v; n->prev = NULL; n->next = NULL;
return n;
}
int main(void) {
struct Node *n = make(42);
printf("%d\n", n->value);
free(n);
return 0;
}เชื่อมโหนดทั้งสองทิศทาง
เมื่อเชื่อมโหนดสองโหนด คุณต้องปรับปรุงการเชื่อมโยงทั้งสองทิศทาง ได้แก่ next ของโหนดแรกและ prev ของโหนดที่สอง
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}
int main(void) {
struct Node *a = make(1), *b = make(2);
a->next = b;
b->prev = a;
printf("forward %d, back %d\n", a->next->value, b->prev->value);
free(a); free(b);
return 0;
}แทรกที่ด้านหน้า
การเพิ่มโหนดไว้ด้านหน้า: next ของโหนดใหม่คือหัวรายการเดิม prev ของหัวรายการเดิมคือโหนดใหม่ จากนั้นเลื่อนหัวรายการไปยังโหนดใหม่
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}
void push(struct Node **head, int v) {
struct Node *n = make(v);
n->next = *head;
if (*head) (*head)->prev = n;
*head = n;
}
int main(void) {
struct Node *head = NULL;
push(&head, 2); push(&head, 1);
printf("%d %d\n", head->value, head->next->value);
return 0;
}การท่องไปข้างหน้า
การเดินไปข้างหน้าเหมือนกับรายการเชื่อมโยงแบบทางเดียวทุกประการ โดยติดตาม next จนถึง NULL
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}
int main(void) {
struct Node *a = make(1), *b = make(2);
a->next = b; b->prev = a;
for (struct Node *p = a; p; p = p->next) printf("%d ", p->value);
printf("\n");
free(a); free(b);
return 0;
}การท่องย้อนกลับ
ข้อได้เปรียบสำคัญคือ จากโหนดใด ๆ คุณสามารถเดินย้อนกลับได้โดยติดตามตัวชี้ prev จนถึงหัวรายการ
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}
int main(void) {
struct Node *a = make(1), *b = make(2), *c = make(3);
a->next = b; b->prev = a; b->next = c; c->prev = b;
for (struct Node *p = c; p; p = p->prev) printf("%d ", p->value);
printf("\n");
free(a); free(b); free(c);
return 0;
}การลบทำได้ง่ายขึ้น
เนื่องจากแต่ละโหนดรู้จักโหนดก่อนหน้า คุณจึงลบโหนดได้โดยไม่ต้องค้นหาโหนดก่อนหน้า
เพียงเชื่อม node->prev เข้ากับ node->next ในทั้งสองทิศทาง
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}
void del(struct Node **head, struct Node *n) {
if (n->prev) n->prev->next = n->next; else *head = n->next;
if (n->next) n->next->prev = n->prev;
free(n);
}
int main(void) {
struct Node *a = make(1), *b = make(2), *c = make(3);
a->next=b; b->prev=a; b->next=c; c->prev=b;
struct Node *head = a;
del(&head, b);
printf("%d %d\n", head->value, head->next->value);
return 0;
}ปรับปรุงโหนดข้างเคียงทั้งสอง
เมื่อนำโหนดออก ต้องแก้ไขค่า next ของโหนดก่อนหน้า และค่า prev ของโหนดถัดไปเสมอ
ตรวจสอบค่า NULL ที่ปลายแต่ละด้าน เพื่อไม่ให้ไล่ตามตัวชี้ไปยังโหนดข้างเคียงที่ไม่มีอยู่
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}
int main(void) {
struct Node *a = make(1), *b = make(2);
a->next = b; b->prev = a;
a->next = NULL;
free(b);
printf("now only %d remains\n", a->value);
free(a);
return 0;
}เก็บตัวชี้ท้ายรายการ
รายการเชื่อมโยงแบบสองทางจำนวนมากยังเก็บตัวชี้ท้ายรายการไปยังโหนดสุดท้ายด้วย ทำให้เพิ่มต่อท้ายและท่องย้อนกลับจากท้ายรายการได้ในเวลา O(1)
#include <stdio.h>
#include <stdlib.h>
struct Node { int value; struct Node *prev; struct Node *next; };
struct Node *make(int v){struct Node*n=malloc(sizeof*n);n->value=v;n->prev=NULL;n->next=NULL;return n;}
int main(void) {
struct Node *head = make(1), *tail = head;
struct Node *n = make(2);
tail->next = n; n->prev = tail; tail = n;
printf("tail = %d\n", tail->value);
free(head); free(n);
return 0;
}ข้อแลกเปลี่ยน
รายการเชื่อมโยงแบบสองทางใช้หน่วยความจำเพิ่มขึ้น โดยมีตัวชี้เพิ่มอีกหนึ่งตัวต่อโหนด และต้องปรับปรุงการเชื่อมโยงสองรายการทุกครั้งที่มีการเปลี่ยนแปลง
สิ่งที่ได้กลับมาคือการท่องรายการสองทิศทางและการลบโหนดที่ทราบตำแหน่งได้ในเวลา O(1) ให้เลือกใช้ตามความต้องการของคุณ
#include <stdio.h>
int main(void) {
printf("Singly: less memory, one-way\n");
printf("Doubly: more memory, two-way + easy delete\n");
return 0;
}ตรวจสอบความเข้าใจอย่างรวดเร็ว
ทดสอบความเข้าใจเกี่ยวกับรายการเชื่อมโยงแบบสองทาง
สรุปทบทวน
คุณได้เรียนรู้รายการเชื่อมโยงแบบสองทางแล้ว:
- แต่ละโหนดมีตัวชี้ทั้ง
prevและnext - การเชื่อมโหนดต้องปรับปรุงการเชื่อมโยงทั้งสองทิศทาง
- คุณสามารถท่องไปข้างหน้าและย้อนกลับ และลบโหนดที่ทราบตำแหน่งได้ในเวลา O(1)
- ข้อเสียคือใช้หน่วยความจำเพิ่มและต้องปรับปรุงตัวชี้มากขึ้น ส่วนตัวชี้ท้ายรายการช่วยให้เพิ่มต่อท้ายได้ในเวลา O(1)
คำถามที่พบบ่อย
บทเรียน “ลิงก์ลิสต์แบบสองทาง” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ลิงก์ลิสต์แบบสองทาง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ลิงก์ลิสต์แบบสองทาง”
ลิงก์สองทิศทาง คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ลิงก์ลิสต์แบบสองทาง” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม
ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ลิงก์ลิสต์แบบทางเดียว
- การแทรกและการลบ
- การท่องผ่านและการค้นหา
- ลิงก์ลิสต์แบบสองทาง