البحث والتحرير
اعثر على العقد وحرّر الذاكرة
البحث والتحرير درس مجاني في C Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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 لتجنب المؤشر المتدلي.
تعلم C مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 39
- الدروس
- 144
الأسئلة الشائعة
هل درس «البحث والتحرير» مجاني؟
نعم — نص درس «البحث والتحرير» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C Academy 4 دروس في المجموع.
ماذا ستتعلم في «البحث والتحرير»؟
اعثر على العقد وحرّر الذاكرة تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟
لا تُشترط خبرة سابقة. C Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «البحث والتحرير»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس C Academy هذا؟
نعم. كل درس في C Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- عُقد الشجرة وبنيتها
- الإدراج في BST
- عمليات الاجتياز
- البحث والتحرير