🌳 TreeMap في جافا: الدليل الشامل للخريطة الشجرية المرتبة

TreeMap هي إحدى هياكل البيانات الرائعة في جافا التي تخزن البيانات على شكل أزواج مفتاح-قيمة مع خاصية فريدة: ترتيب المفاتيح تلقائياً! إذا كنت تبحث عن خريطة تحافظ على ترتيب عناصرها، فأنت في المكان الصحيح.


🤔 ما هي TreeMap؟

TreeMap هي فئة في حزمة java.util تنفذ واجهة NavigableMap التي ترث بدورها من SortedMap. الفكرة الأساسية هي أنها تخزن البيانات في بنية شجرة حمراء-سوداء (Red-Black Tree)، مما يضمن أن المفاتيح تكون مرتبة دائماً حسب ترتيبها الطبيعي أو حسب مُقارن (Comparator) مخصص.

المميزات الرئيسية:

  • المفاتيح مرتبة تلقائياً
  • لا تسمح بالمفاتيح المكررة
  • تسمح بالقيم المكررة والقيم null
  • لا تسمح بالمفاتيح null إذا كانت تستخدم الترتيب الطبيعي

⚙️ إنشاء كائن TreeMap

لنبدأ بإنشاء أول كائن TreeMap لدينا. هناك عدة طرق للإنشاء:

import java.util.TreeMap;

// 1. إنشاء TreeMap فارغة (باستخدام الترتيب الطبيعي للمفاتيح)
TreeMap<String, Integer> grades = new TreeMap<>();

// 2. إنشاء TreeMap من خريطة موجودة
TreeMap<String, Integer> copyGrades = new TreeMap<>(grades);

// 3. إنشاء TreeMap مع مُقارن مخصص للترتيب
TreeMap<String, Integer> customOrder = new TreeMap<>(Comparator.reverseOrder());

📝 العمليات الأساسية على TreeMap

الإضافة والاسترجاع والتحديث

TreeMap<String, String> countries = new TreeMap<>();

// إضافة عناصر
countries.put("EG", "Egypt");
countries.put("SA", "Saudi Arabia");
countries.put("AE", "United Arab Emirates");
countries.put("KW", "Kuwait");

// الاسترجاع
String country = countries.get("SA"); // تُرجع "Saudi Arabia"

// التحديث
countries.put("SA", "Kingdom of Saudi Arabia"); // تحديث القيمة

// الحجم
int size = countries.size(); // 4

الحذف

// حذف عنصر بمفتاح محدد
countries.remove("KW");

// حذف جميع العناصر
countries.clear();

🔍 الخصائص الفريدة لـ TreeMap

ما يميز TreeMap عن HashMap هو القدرة على التنقل والاستعلام بناءً على الترتيب:

TreeMap<Integer, String> students = new TreeMap<>();
students.put(101, "Ahmed");
students.put(105, "Mohamed");
students.put(110, "Fatima");
students.put(115, "Khaled");

// الحصول على أول مفتاح (الأصغر)
Integer firstKey = students.firstKey(); // 101

// الحصول على آخر مفتاح (الأكبر)
Integer lastKey = students.lastKey(); // 115

// الحصول على مفتاح أكبر من مفتاح محدد
Integer higherKey = students.higherKey(105); // 110

// الحصول على مفتاح أصغر من مفتاح محدد
Integer lowerKey = students.lowerKey(110); // 105

📊 TreeMap مقابل HashMap: أيهما تختار؟

الميزة TreeMap HashMap
الترتيب ✓ مرتبة تلقائياً ✗ غير مرتبة
الأداء O(log n) للعمليات الأساسية O(1) للعمليات الأساسية
المفاتيح null ✗ غير مسموحة (بالترتيب الطبيعي) ✓ مسموحة
الاستخدام عندما تحتاج ترتيب المفاتيح عندما لا يهمك الترتيب

نصيحة: استخدم TreeMap عندما تحتاج إلى الوصول للبيانات بترتيب معين، واستخدم HashMap عندما تريد أسرع أداء ولا يهمك الترتيب.


💡 مثال تطبيقي: إدارة منتجات متجر

لنطبق ما تعلمناه في مثال واقعي:

TreeMap<String, Double> products = new TreeMap<>();

// إضافة منتجات
products.put("Laptop", 2500.0);
products.put("Mouse", 50.0);
products.put("Keyboard", 120.0);
products.put("Monitor", 800.0);

// عرض المنتجات مرتبة أبجدياً (حسب المفتاح)
System.out.println("المنتجات مرتبة:");
for (String product : products.keySet()) {
    System.out.println(product + ": " + products.get(product) + " ريال");
}

// البحث عن منتجات في نطاق معين
System.out.println("\nمنتجات من M إلى P:");
SortedMap<String, Double> subMap = products.subMap("M", "Q");
for (String product : subMap.keySet()) {
    System.out.println(product);
}

⚠️ ملاحظات هامة

  1. الأداء: TreeMap أبطأ من HashMap لأن عمليات الإضافة والحذف والبحث تأخذ وقت O(log n) بدلاً من O(1)
  2. المفاتيح: يجب أن تكون المفاتيح قابلة للمقارنة (Comparable) أو تزود بمُقارن مخصص
  3. الذاكرة: تستخدم ذاكرة أكثر من HashMap بسبب بنية الشجرة

🎯 خلاصة الدرس

تعلمنا اليوم أن TreeMap هي خريطة مرتبة تلقائياً، مثالية عندما نريد الحفاظ على ترتيب المفاتيح. استخدمها عندما تحتاج إلى:

  • عرض البيانات مرتبة
  • البحث عن عناصر في نطاقات معينة
  • الحصول على العناصر الأولى أو الأخيرة بسهولة