الخوارزميات وهياكل البيانات بلغة Rust: دليل شامل للمبتدئين
Rust هي لغة برمجة تجمع بين الأداء العالي للغات C/C++ وأمان الذاكرة المضمون في مرحلة التجميع. بالنسبة للمطورين المبتدئين، فإن دراسة الخوارزميات وهياكل البيانات بلغة Rust ليست فقط وسيلة لإتقان المفاهيم الأساسية لعلوم الحاسوب، بل هي أيضًا فرصة لفهم الميزات الفريدة للغة: الملكية (ownership)، الاقتراض (borrowing)، وأوقات الحياة (lifetimes).
في هذه المقالة، سنستعرض هياكل البيانات والخوارزميات الرئيسية التي يجب أن يعرفها كل مطور. جميع أمثلة الكود مكتوبة بلغة Rust وجاهزة للتشغيل. سنبدأ بهياكل البيانات الأساسية التي توفرها المكتبة القياسية، ثم ننتقل إلى تنفيذ الخوارزميات الكلاسيكية.
1. هياكل البيانات الأساسية في Rust
توفر المكتبة القياسية لـ Rust (std) مجموعة غنية من هياكل البيانات الجاهزة. دعنا ننظر إلى ثلاثة من أهمها.
المتجهات (Vec)
Vec هي مصفوفة ديناميكية يمكنها تغيير حجمها. وهي مشابهة لـ ArrayList في Java أو list في Python. تضمن المتجهات ترتيبًا متواصلاً للعناصر في الذاكرة، مما يجعل الوصول عبر الفهرس سريعًا جدًا (O(1)).
fn main() { // إنشاء متجه فارغ let mut numbers: Vec<i32> = Vec::new(); // إضافة عناصر numbers.push(10); numbers.push(20); numbers.push(30); // الوصول عبر الفهرس let first = numbers[0]; // 10 // التكرار for num in &numbers { println!("{}", num); } // ماكرو vec! let fruits = vec!["apple", "banana", "cherry"]; println!("الفاكهة الثانية: {}", fruits[1]); // banana}خرائط التجزئة (HashMap)
HashMap هي بنية بيانات تخزن أزواج المفتاح-القيمة. توفر متوسط وقت وصول O(1) للإدراج والبحث والحذف. مثالية للمهام التي تتطلب العثور السريع على البيانات حسب المفتاح.
use std::collections::HashMap;
fn main() { let mut scores = HashMap::new(); scores.insert(String::from("Alice"), 100); scores.insert(String::from("Bob"), 85); // الحصول على القيمة حسب المفتاح let alice_score = scores.get(&String::from("Alice")); match alice_score { Some(score) => println!("Alice سجلت: {}", score), None => println!("Alice غير موجودة"), } // التكرار على جميع الأزواج for (name, score) in &scores { println!("{}: {}", name, score); }}السلاسل النصية (String)
في Rust، يوجد نوعان رئيسيان من السلاسل النصية: &str (شريحة سلسلة نصية) و String (سلسلة نصية قابلة للتغيير ومالكة). يتطلب العمل مع السلاسل النصية في Rust الانتباه بسبب ترميز UTF-8.
fn main() { let mut hello = String::from("مرحبًا، "); hello.push_str("العالم!"); // إضافة سلسلة نصية hello.push('!'); // إضافة حرف println!("{}", hello); // مرحبًا، العالم!! // شرائح السلاسل النصية (احذر حدود الأحرف!) let slice = &hello[0..7]; // "مرحبًا" println!("الشريحة: {}", slice);}2. تنفيذ المكدس وقائمة الانتظار
المكدس وقائمة الانتظار هما هيكلان أساسيان للبيانات يُستخدمان غالبًا في الخوارزميات. في Rust، يمكن تنفيذهما بسهولة باستخدام Vec.
المكدس (LIFO — Last In, First Out)
يعمل المكدس وفق مبدأ "آخر من يدخل هو أول من يخرج". توفر Vec بالفعل طريقتي push و pop اللتين تنفذان سلوك المكدس.
fn main() { let mut stack: Vec<i32> = Vec::new(); stack.push(1); stack.push(2); stack.push(3); while let Some(top) = stack.pop() { println!("نستخرج: {}", top); } // الإخراج: 3, 2, 1}