مقدمة: لماذا Rust للخوارزميات؟
Rust هي لغة برمجة أنظمة حديثة تجمع بين الأداء العالي للغات C/C++ وأمان الذاكرة. لدراسة الخوارزميات وهياكل البيانات، تعتبر Rust مناسبة بشكل خاص للأسباب التالية:
- التحكم في الملكية (ownership) يفرض التفكير بوضوح في إدارة الذاكرة
- الأمان — لا يسمح المترجم بالعديد من أخطاء وقت التشغيل
- السرعة — يتم ترجمة Rust إلى كود آلة، وهو أمر مهم للخوارزميات عالية الأداء
في هذه المقالة، سنشرح تنفيذ أربعة هياكل وخوارزميات أساسية بلغة Rust مع أمثلة عملية.
1. القائمة المرتبطة (Linked List)
أحد هياكل البيانات الكلاسيكية. يتطلب تنفيذها في Rust استخدام Box لتخصيص الذاكرة في الكومة و Option لتمثيل غياب العقدة.
تنفيذ قائمة مرتبطة أحادية الاتجاه
// تعريف عقدة القائمة#[derive(Debug)]struct Node<T> { value: T, next: Option<Box<Node<T>>>,}
// القائمة نفسها#[derive(Debug)]struct LinkedList<T> { head: Option<Box<Node<T>>>,}
impl<T> LinkedList<T> { // إنشاء قائمة فارغة fn new() -> Self { LinkedList { head: None } }
// إضافة عنصر إلى البداية fn push_front(&mut self, value: T) { let new_node = Box::new(Node { value, next: self.head.take(), }); self.head = Some(new_node); }
// حذف عنصر من البداية fn pop_front(&mut self) -> Option<T> { self.head.take().map(|node| { self.head = node.next; node.value }) }}
fn main() { let mut list = LinkedList::new(); list.push_front(10); list.push_front(20); list.push_front(30); println!("{:?}", list); // LinkedList { head: Some(Node { value: 30, next: ... }) } let popped = list.pop_front(); println!("تم الحذف: {:?}", popped); // تم الحذف: Some(30) println!("القائمة الآن: {:?}", list);}ما يحدث هنا:
Box<Node>— مؤشر إلى عقدة في الكومةOption— إما وجود عقدة (Some) أو عدم وجودها (None)take()— يأخذ القيمة منOptionتاركاًNone
2. شجرة البحث الثنائية (Binary Search Tree)
الشجرة هي بنية هرمية. في شجرة البحث الثنائية، كل عقدة لها فرع أيسر وأيمن، حيث يكون الفرع الأيسر أصغر من الجذر والأيمن أكبر.
تنفيذ BST
use std::cmp::Ordering;
#[derive(Debug)]struct TreeNode<T> { value: T, left: Option<Box<TreeNode<T>>>, right: Option<Box<TreeNode<T>>>,}
#[derive(Debug)]struct BinarySearchTree<T> { root: Option<Box<TreeNode<T>>>,}
impl<T: Ord> BinarySearchTree<T> { fn new() -> Self { BinarySearchTree { root: None } }
// إدراج عنصر fn insert(&mut self, value: T) { let mut current = &mut self.root; while let Some(node) = current { match value.cmp(&node.value) { Ordering::Less => current = &mut node.left, Ordering::Greater => current = &mut node.right, Ordering::Equal => return, // تجاهل التكرارات } } *current = Some(Box::new(TreeNode { value, left: None, right: None, })); }
// البحث عن عنصر fn contains(&self, value: &T) -> bool { let mut current = &self.root; while let