ค้นหาและคืนหน่วยความจำ
ค้นหาโหนดและคืนหน่วยความจำ
ค้นหาและคืนหน่วยความจำ เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
การค้นหาใน BST
การค้นหาอาศัยกฎการเรียงลำดับ ในแต่ละโหนด เราจะเปรียบเทียบเป้าหมายกับค่าของโหนด แล้วไปยังต้นไม้ย่อยเพียงด้านเดียว
เนื่องจากเราไม่นำโหนดที่เหลือครึ่งหนึ่งมาพิจารณาในแต่ละขั้นตอน ต้นทุนของการค้นหาจึงขึ้นอยู่กับความสูงของต้นไม้ ไม่ใช่จำนวนโหนด
การค้นหาแบบเรียกซ้ำ
การค้นหาแบบเรียกซ้ำมีกรณีฐานสองกรณี ได้แก่ ต้นไม้ย่อยว่างหมายถึงไม่พบ และค่าที่ตรงกันหมายถึงพบ
นอกเหนือจากนั้น เราจะเรียกซ้ำไปทางซ้ายหรือขวาตามผลการเปรียบเทียบ
Node *search(Node *root, int target) {
if (root == NULL || root->value == target)
return root;
if (target < root->value)
return search(root->left, target);
return search(root->right, target);
}การค้นหาแบบวนซ้ำ
การค้นหาสามารถเขียนเป็นลูปแบบง่าย ๆ ได้เช่นกัน เพื่อหลีกเลี่ยงค่าใช้จ่ายเพิ่มเติมจากการเรียกซ้ำ
เราเดินตามพอยน์เตอร์ลงไปในต้นไม้จนกว่าจะพบเป้าหมาย หรือหลุดออกจากปลายต้นไม้ที่ NULL
Node *search_iter(Node *root, int target) {
while (root != NULL) {
if (target == root->value) return root;
root = (target < root->value)
? root->left : root->right;
}
return NULL; /* not found */
}การค้นหาในการทำงานจริง
โปรแกรมนี้สร้าง BST และค้นหาค่าที่มีอยู่กับค่าที่ไม่มีอยู่ในต้นไม้ พร้อมแสดงว่าพบแต่ละค่าหรือไม่
การส่งคืนค่าที่ไม่ใช่ NULL หมายถึงพบ ส่วน NULL หมายถึงค่านั้นไม่ได้อยู่ในต้นไม้
#include <stdio.h>
#include <stdlib.h>
typedef struct Node { int value; struct Node *left, *right; } Node;
Node *cn(int v){ Node *n=malloc(sizeof(Node)); n->value=v; n->left=n->right=NULL; return n; }
Node *insert(Node *r,int v){
if(!r) return cn(v);
if(v<r->value) r->left=insert(r->left,v);
else if(v>r->value) r->right=insert(r->right,v);
return r;
}
Node *search(Node *r,int t){
if(!r||r->value==t) return r;
return t<r->value ? search(r->left,t) : search(r->right,t);
}
int main(void){
Node *root=NULL;
int d[]={10,5,15,3,7};
for(int i=0;i<5;i++) root=insert(root,d[i]);
printf("7:%s 99:%s\n",
search(root,7)?"found":"no",
search(root,99)?"found":"no");
return 0;
}การหาค่าต่ำสุด
ใน BST ค่าที่น้อยที่สุดคือโหนดซ้ายสุด ให้เดินตาม left ต่อไปจนกว่าจะเป็น NULL
ในทำนองเดียวกัน ค่าสูงสุดคือโหนดขวาสุด ตัวช่วยเหล่านี้มีความสำคัญต่อการลบและการค้นหาตามช่วงค่า
Node *find_min(Node *root) {
if (root == NULL) return NULL;
while (root->left != NULL)
root = root->left;
return root;
}เหตุใดการคืนหน่วยความจำจึงสำคัญ
โหนดทุกโหนดมาจาก malloc ดังนั้นทุกโหนดจึงต้องคืนกลับด้วย free หากลืมคืนหน่วยความจำ จะทำให้หน่วยความจำรั่ว
แต่คุณไม่สามารถคืนหน่วยความจำของโหนดแล้วอ่านพอยน์เตอร์ของโหนดลูกได้ ดังนั้น ลำดับ การคืนหน่วยความจำจึงสำคัญมาก
คืนหน่วยความจำแบบหลัง
วิธีที่ปลอดภัยในการคืนหน่วยความจำของต้นไม้คือการทำแบบหลัง โดยคืนหน่วยความจำของโหนดลูกทั้งสองก่อน แล้วจึงคืนหน่วยความจำของโหนดเอง
วิธีนี้รับประกันว่าเราจะอ่านพอยน์เตอร์ left และ right ของโหนดก่อนที่หน่วยความจำของโหนดนั้นจะถูกคืน
void free_tree(Node *root) {
if (root == NULL) return;
free_tree(root->left);
free_tree(root->right);
free(root);
}ลำดับที่ผิดและอันตราย
หากคืนหน่วยความจำของโหนดก่อนเรียกซ้ำไปยังโหนดลูก จะทำให้เกิดพฤติกรรมที่ไม่กำหนด เนื่องจากคุณจะต้องเข้าถึงหน่วยความจำที่ถูกคืนแล้วเพื่อไปยังต้นไม้ย่อย
นี่คือข้อบกพร่องแบบใช้หน่วยความจำหลังคืนแล้ว ซึ่งพบได้บ่อย ควรคืนหน่วยความจำของโหนดลูกก่อนเสมอ
/* WRONG: use-after-free */
void bad_free(Node *root) {
if (!root) return;
free(root); /* freed here */
bad_free(root->left); /* reads freed memory! */
bad_free(root->right);
}หลีกเลี่ยงพอยน์เตอร์ห้อย
หลังจาก free_tree ส่งคืนแล้ว พอยน์เตอร์รากเดิมยังคงเก็บที่อยู่เก่าไว้ แต่หน่วยความจำนั้นหายไปแล้ว
การกำหนดค่าให้เป็น NULL อีกครั้งในผู้เรียกจะป้องกันการนำพอยน์เตอร์ห้อยกลับมาใช้โดยไม่ตั้งใจ
free_tree(root);
root = NULL; /* avoid a dangling pointer */นับโหนดที่คืนหน่วยความจำแล้ว
เราสามารถยืนยันได้ว่าการคืนหน่วยความจำทำงานถูกต้อง โดยนับโหนดระหว่างการท่องแบบหลัง แล้วจึงคืนหน่วยความจำของแต่ละโหนด
โปรแกรมนี้สร้างต้นไม้ คืนหน่วยความจำ แล้วรายงานว่ามีการคืนหน่วยความจำของโหนดไปกี่โหนด
#include <stdio.h>
#include <stdlib.h>
typedef struct Node { int value; struct Node *left, *right; } Node;
Node *cn(int v){ Node *n=malloc(sizeof(Node)); n->value=v; n->left=n->right=NULL; return n; }
Node *insert(Node *r,int v){
if(!r) return cn(v);
if(v<r->value) r->left=insert(r->left,v);
else if(v>r->value) r->right=insert(r->right,v);
return r;
}
int free_count(Node *r){
if(!r) return 0;
int c = free_count(r->left) + free_count(r->right);
free(r);
return c + 1;
}
int main(void){
Node *root=NULL;
int d[]={10,5,15,3,7};
for(int i=0;i<5;i++) root=insert(root,d[i]);
printf("freed=%d\n", free_count(root));
root = NULL;
return 0;
}ค้นหาและคืนหน่วยความจำร่วมกัน
วงจรการทำงานที่สมบูรณ์คือ สร้างต้นไม้ ค้นหาในต้นไม้ แล้วคืนหน่วยความจำ การทำทั้งสามขั้นตอนช่วยให้โปรแกรมถูกต้องและไม่มีหน่วยความจำรั่ว
เครื่องมืออย่าง Valgrind สามารถยืนยันได้ว่าการเรียก malloc ทุกครั้งมีการเรียก free ที่สอดคล้องกัน
/* lifecycle
* 1. insert values (allocate)
* 2. search as needed (read-only)
* 3. free_tree(root) (deallocate)
* 4. root = NULL (avoid dangling)
*/ตรวจสอบอย่างรวดเร็ว
วิเคราะห์การคืนหน่วยความจำอย่างปลอดภัย
สรุปทบทวน
การค้นหาใน BST จะเปรียบเทียบและเดินลงไปยังต้นไม้ย่อยหนึ่งด้านในแต่ละขั้นตอน โดยใช้เวลาเป็นสัดส่วนกับความสูง ค่าต่ำสุดอยู่ที่โหนดซ้ายสุด ส่วนค่าสูงสุดอยู่ที่โหนดขวาสุด
คืนหน่วยความจำของต้นไม้ตามลำดับแบบหลัง เพื่อให้โหนดลูกถูกคืนก่อนโหนดแม่ จากนั้นกำหนดรากเป็น NULL เพื่อหลีกเลี่ยงพอยน์เตอร์ห้อย
คำถามที่พบบ่อย
บทเรียน “ค้นหาและคืนหน่วยความจำ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ค้นหาและคืนหน่วยความจำ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- โหนดและโครงสร้างต้นไม้
- แทรกข้อมูลใน BST
- การท่องต้นไม้
- ค้นหาและคืนหน่วยความจำ