الشجرة الثنائية في بنية البيانات (مثال)
⚡ ملخص ذكي
الشجرة الثنائية في هياكل البيانات هي بنية هرمية حيث تحتوي كل عقدة على طفلين على الأكثر، يُطلق عليهما اليسار واليمين. يشرح هذا المورد الأشجار الثنائية، وشجرة البحث الثنائية، وأنواعها، وتطبيقاتها، وشرحًا كاملاً بلغة C. C++و Python التنفيذ.

ما هي الشجرة الثنائية؟
كلمة ثنائي تعني اثنين. في بنية بيانات الشجرة، تعني "الشجرة الثنائية" شجرة حيث يمكن أن تحتوي كل عقدة على عقدتين فرعيتين كحد أقصى (العقد اليسرى واليمنى). إنها شجرة ثنائية بسيطة.
ومع ذلك، هناك شجرة ثنائية أخرى تُستخدم بشكل متكرر ولها عدة حالات استخدام. تُسمى شجرة البحث الثنائية (BST). يمكن لهذه الشجرة أن تجعل خوارزمية البحث أسرع بكثير، بدقة عالية مع تعقيد زمني قدره log(n). في بنية البيانات، تعني n عدد العقد في الشجرة الثنائية.
ما هي الاختلافات بين الشجرة الثنائية وشجرة البحث الثنائية؟
الفرق بين BST والشجرة الثنائية العادية هو أن العقدة اليسرى BST لها قيمة أصغر من العقدة الجذرية، والعقدة اليمنى لها قيمة أكبر من العقدة الجذرية. لذلك، ستحتوي الشجرة الفرعية اليسرى دائمًا على قيمة أصغر من الجذر، وستحتوي الشجرة الفرعية اليمنى دائمًا على قيمة أكبر من الجذر.
مثال على أشجار البحث الثنائية
دعونا نأخذ المثال التالي لتوضيح مفاهيم شجرة البحث الثنائية.
هنا يمكنك اتباع جميع العقد للانضباط المحدد. توجد صيغة للحد الأقصى لعدد العقد في شجرة البحث الثنائية. إذا لاحظنا الشجرة أعلاه، يمكننا أن نرى أن كل عقدة لديها طفلين باستثناء جميع العقد الورقية. وارتفاع (ح) الشجرة الثنائية المعطاة هو 4. الصيغة هي 2h - 1. لذلك يعطي 15.
الصورة المذكورة أعلاه ليست شجرة ثنائية كاملة أو شجرة ثنائية متوازنة، وتسمى الشجرة الثنائية الكاملة أو الشجرة الثنائية المتوازنة. هناك بنية بيانات أخرى تسمى AVL (نوع آخر من الشجرة الثنائية) تعمل على تحسين ارتفاع الشجرة الثنائية وإجراء البحث بشكل أسرع عن BST كما في الشكل 3.
حاول حساب عملية العبور بالترتيب للشجرة الثنائية المذكورة أعلاه. ستجد أن هذا سيعطي مصفوفة مرتبة غير متناقصة، وستكون خوارزميات العبور مماثلة لتلك الخاصة بالشجرة الثنائية.
أنواع الشجرة الثنائية
فيما يلي بعض الأنواع المهمة من الشجرة الثنائية:
- شجرة ثنائية كاملة: يمكن أن تحتوي كل عقدة على 0 أو 2 عقد فرعية في هذه الشجرة الثنائية. غير مسموح بعقدة فرعية واحدة فقط في هذا النوع من الأشجار الثنائية. لذلك، باستثناء العقدة الورقية، سيكون لجميع العقد طفلان.
- شجرة ثنائية كاملة: يمكن أن تحتوي كل عقدة على 0 أو 2 عقدة. تبدو مثل الشجرة الثنائية الكاملة، ولكن جميع عناصر الورقة تميل إلى الشجرة الفرعية اليسرى، بينما في عقدة الشجرة الثنائية الكاملة يمكن أن تكون في الشجرة الفرعية اليمنى أو اليسرى.
- شجرة ثنائية مثالية: يجب أن تحتوي جميع العقد على 0 أو 2 عقدة، ويجب أن تكون جميع العقد الورقية على نفس المستوى أو الارتفاع. المثال أعلاه لبنية شجرة ثنائية كاملة ليس شجرة ثنائية مثالية لأن العقدة 6 والعقدة 1,2,3،XNUMX،XNUMX ليسا في نفس الارتفاع. لكن مثال الشجرة الثنائية الكاملة هو شجرة ثنائية مثالية.
- شجرة ثنائية منحلة: يمكن لكل عقدة أن يكون لها طفل واحد فقط. كل العمليات مثل البحث والإدراج والحذف تستغرق وقتًا قدره O(N).
- شجرة ثنائية متوازنة: هنا هذه الشجرة الثنائية، فرق الارتفاع بين الشجرة الفرعية اليسرى واليمنى هو 1 على الأكثر. لذلك، أثناء إضافة أو حذف عقدة، نحتاج إلى موازنة ارتفاع الشجرة مرة أخرى. يسمى هذا النوع من الأشجار الثنائية ذاتية التوازن شجرة AVL.
هناك ثلاث عمليات أساسية لـ BST. وسيتم مناقشتها بالتفصيل أدناه.
تنفيذ الشجرة الثنائية في C و C++
#include <iostream> #include <bits/stdc++.h> using namespace std; struct Node { int value; struct Node *left, *right; } struct Node *getEmptynode(int val) { struct Node *tempNode = (struct Node *)malloc(sizeof(struct Node)); tempNode->value = val; tempNode->left = NULL; tempNode->right = NULL; return tempNode; } struct Node *successor(struct Node *node) { struct Node *present = node; // going to the left most node while (present != NULL && present->left != NULL) { present = present->left; } return present; } struct Node *insert(struct Node *node, int value) { if (node == NULL) { return getEmptynode(value); } if (value < node->value) { node->left = insert(node->left, value); } else { node->right = insert(node->right, value); } return node; } int searchInBST(struct Node *node, int value) { struct Node *current = node; while (current->value != value) { if (current->value > value) { current = current->left; } else { current = current->right; } if (current == NULL) { return 0; } } return 1; } void inorder(struct Node *root) { if (root != NULL) { inorder(root->left); cout << root->value << " "; inorder(root->right); } } struct Node *deleteNode(struct Node *node, int value) { if (node == NULL) { return node; } if (value < node->value) { node->left = deleteNode(node->left, value); } else if (value > node->value) { node->right = deleteNode(node->right, value); } else { if (node->left == NULL) { struct Node *temp = node->right; free(node); return temp; } else if (node->right == NULL) { struct Node *temp = node->left; free(node); return temp; } struct Node *temp = successor(node->right); node->value = temp->value; node->right = deleteNode(node->right, temp->value); } return node; } int main() { struct Node *root = NULL; root = insert(root, 8); root = insert(root, 4); root = insert(root, 12); root = insert(root, 2); root = insert(root, 6); root = insert(root, 10); root = insert(root, 14); root = insert(root, 1); root = insert(root, 3); root = insert(root, 5); root = insert(root, 7); root = insert(root, 9); root = insert(root, 11); root = insert(root, 13); root = insert(root, 15); cout << "InOrder Traversal after inserting all nodes: " << endl; inorder(root); root = insert(root, -10); cout << "\nInOrder Traversal after inserting -10 : " << endl; inorder(root); cout << "\nSearching -5 in the BST: " << searchInBST(root, -5) << endl; cout << "Searching -10 in the BST: " << searchInBST(root, -10) << endl; root = deleteNode(root,8); cout<<"After deleting node 8, inorder traversal: "<<endl; inorder(root); root = deleteNode(root,-10); cout<<"\nAfter deleting node -10, inorder traversal: "<<endl; inorder(root); }
الإخراج:
InOrder Traversal after inserting all nodes: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 InOrder Traversal after inserting -10 : 10 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Searching -5 in the BST: 0 Searching -10 in the BST: 1 After deleting node 8, inorder traversal: -10 1 2 3 4 5 6 7 9 10 11 12 13 14 15 After deleting node -10, inorder traversal: 1 2 3 4 5 6 7 9 10 11 12 13 14 15
تنفيذ الشجرة الثنائية في Python
class Node: def __init__(self,value): self.left = None self.right = None self.value = value def insert(root,value): if root == None: return Node(value) if value< root.value: root.left = insert(root.left,value) else: root.right = insert(root.right,value) return root def searchInBST(root,value): current = root while current.value != value: if current.value > value: current = current.left else: current = current.right if current == None: return "Not found" return "Found" def inorder(root): if root != None: inorder(root.left) print(root.value,end=" ") inorder(root.right) def successor(root): present = root while present != None and present.left != None: present = present.left return present def deleteNode(root,value): if root == None: return root if value < root.value: root.left = deleteNode(root.left, value) elif value>root.value: root.right = deleteNode(root.right, value) else: if root.left == None: temp = root.right root = None return temp elif root.right == None: temp = root.left root = None return temp temp = successor(root.right) root.value = temp.value root.right = deleteNode(root.right, temp.value) return root root = Node(8) root = insert(root, 4) root = insert(root, 12) root = insert(root, 2) root = insert(root, 6) root = insert(root, 10) root = insert(root, 14) root = insert(root, 1) root = insert(root, 3) root = insert(root, 5) root = insert(root, 7) root = insert(root, 9) root = insert(root, 11) root = insert(root, 13) root = insert(root, 15) print("InOrder Traversal after inserting all nodes: ") inorder(root) root = insert(root, -10) print("\nInOrder Traversal after inserting -10 : ") inorder(root) print("\nSearching -5 in the BST: ",searchInBST(root, -5)) print("Searching -5 in the BST: ",searchInBST(root, -10)) root = deleteNode(root,8) print("After deleting node 8, inorder traversal:") inorder(root) root = deleteNode(root,-10) print("\nAfter deleting node -10, inorder traversal:") inorder(root)
الإخراج:
InOrder Traversal after inserting all nodes 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 InOrder Traversal after inserting -10 : -10 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Searching -5 in the BST: Not found Searching -5 in the BST: Found After deleting node 8, inorder traversal: -10 1 2 3 4 5 6 7 9 10 11 12 13 14 15 After deleting node -10, inorder traversal: 1 2 3 4 5 6 7 9 10 11 12 13 14 15
تطبيق الشجرة الثنائية
فيما يلي بعض التطبيقات الشائعة للشجرة الثنائية:
- تنظيم بيانات العقدة بترتيب فرزها
- تستخدم في الخريطة وتعيين كائنات العقدة في مكتبات لغات البرمجة.
- البحث عن العناصر في هياكل البيانات
»تعرف على برنامجنا التعليمي التالي حول خوارزمية الجمع







