🌳 TreeSet في جافا: دليلك الشامل للتعامل مع المجموعات المرتبة

مرحباً بك في درس جديد من دروس هياكل البيانات في جافا! اليوم سنتعرف على TreeSet، وهي واحدة من أكثر المجموعات فائدة وإثارة للاهتمام. إذا كنت تذكر درس HashSet، فأنت تعلم أن المجموعات (Sets) تخزن عناصر فريدة دون تكرار. لكن ماذا لو أردنا أن تكون هذه العناصر مرتبة تلقائياً؟ هنا يأتي دور TreeSet! 🚀

TreeSet هي فئة في جافا تنتمي لحزمة java.util وتقوم بتنفيذ واجهتي SortedSet و NavigableSet. ببساطة، هي مجموعة (Set) تحفظ عناصرها بشكل مرتب تصاعدياً (من الأصغر إلى الأكبر) تلقائياً. تخيلها كشجرة بحث ثنائية متوازنة (Red-Black Tree) تمنع التكرار وتفرض الترتيب.


📦 إنشاء كائن TreeSet وإضافة العناصر

لنبدأ بإنشاء أول TreeSet خاص بنا. العملية بسيطة جداً وتشبه إنشاء أي مجموعة أخرى.

import java.util.TreeSet;

public class TreeSetExample {
    public static void main(String[] args) {
        // 1. إنشاء TreeSet فارغ للأعداد الصحيحة
        TreeSet<Integer> numbers = new TreeSet<>();
        
        // 2. إضافة عناصر باستخدام add()
        numbers.add(50);
        numbers.add(20);
        numbers.add(80);
        numbers.add(10);
        numbers.add(30);
        numbers.add(20); // هذه القيمة مكررة، لن تتم إضافتها!
        
        // 3. طباعة المجموعة لرؤية الترتيب التلقائي
        System.out.println("TreeSet after adding elements: " + numbers);
        // المخرجات: [10, 20, 30, 50, 80]
        // لاحظ: العناصر مرتبة تصاعدياً رغم إضافتها عشوائياً!
    }
}

ملاحظة مهمة: العناصر في TreeSet يجب أن تكون قابلة للمقارنة. لهذا استخدمنا Integer في المثال. لو حاولت إضافة كائنات من فئة أنشأتها أنت، ستحتاج لأن تجعلها تنفذ واجهة Comparable.


🔍 الخصائص والمميزات الرئيسية لـ TreeSet

دعونا نلخص ما يميز TreeSet:

  1. 🔄 ترتيب تلقائي: العناصر مرتبة دائماً (تصاعدياً افتراضياً).
  2. 🚫 منع التكرار: مثل جميع الـ Sets، لا تسمح بتخزين عناصر مكررة.
  3. ⚡ أداء جيد: عمليات البحث والإضافة والحذف لها تعقيد زمني O(log n)، وهو جيد جداً للمجموعات الكبيرة.
  4. 🧭 طرق ملاحة قوية: توفر طرقاً للعثور على العناصر "الأقرب" لقيمة معينة (مثل أكبر من، أصغر من).

🛠️ العمليات الأساسية على TreeSet

1. التحقق من وجود عنصر

TreeSet<String> fruits = new TreeSet<>();
fruits.add("تفاح");
fruits.add("موز");
fruits.add("برتقال");

boolean hasApple = fruits.contains("تفاح"); // true
boolean hasGrape = fruits.contains("عنب");   // false

2. حذف عنصر

fruits.remove("موز");
System.out.println(fruits); // [برتقال, تفاح]

3. الحصول على حجم المجموعة

int size = fruits.size(); // 2

4. معرفة العنصر الأول والأخير (بسبب الترتيب)

TreeSet<Integer> nums = new TreeSet<>();
nums.add(5); nums.add(1); nums.add(9); nums.add(3);

Integer first = nums.first(); // 1 (أصغر عنصر)
Integer last = nums.last();   // 9 (أكبر عنصر)

🧭 طرق الملاحة المتقدمة في TreeSet

هذه الميزات الرائعة تأتي من تنفيذ واجهة NavigableSet. إنها تجعل TreeSet ذكية جداً!

TreeSet<Integer> scores = new TreeSet<>();
scores.add(100); scores.add(85); scores.add(92); scores.add(70); scores.add(60);

// lower(E e): أكبر عنصر أصغر من القيمة المعطاة
Integer below90 = scores.lower(90); // 85

// higher(E e): أصغر عنصر أكبر من القيمة المعطاة
Integer above90 = scores.higher(90); // 92

// floor(E e): أكبر عنصر أصغر من أو يساوي القيمة المعطاة
Integer floor90 = scores.floor(90); // 85 (لأن 90 غير موجودة)

// ceiling(E e): أصغر عنصر أكبر من أو يساوي القيمة المعطاة
Integer ceiling90 = scores.ceiling(90); // 92

🔄 اجتياز عناصر TreeSet

يمكنك اجتياز TreeSet باستخدام for-each loop أو Iterator، وستحصل على العناصر مرتبة.

TreeSet<String> colors = new TreeSet<>();
colors.add("Red");
colors.add("Blue");
colors.add("Green");
colors.add("Yellow");

System.out.println("The colors sorted alphabetically:");
for (String color : colors) {
    System.out.println("- " + color);
}
// The output: Blue, Green, Red, Yellow (according to alphabetical order)

🤔 مقارنة سريعة: TreeSet vs. HashSet

الميزة TreeSet HashSet
الترتيب ✅ مرتبة تلقائياً ❌ غير مرتبة (عشوائية)
الأداء O(log n) للإضافة/البحث O(1) للإضافة/البحث (أسرع غالباً)
التخزين شجرة Red-Black Tree جدول Hash
الاستخدام عندما تحتاج عناصر مرتبة عندما تحتاج أداء سريع ولا يهمك الترتيب

💡 متى تستخدم TreeSet؟

استخدم TreeSet عندما:

  • تحتاج إلى مجموعة عناصر فريدة ومُرتبة دائماً.
  • تحتاج للقيام بعمليات بحث معقدة (مثل "العنصر الأكبر من X").
  • لا تمانع تضحية طفيفة في السرعة مقابل الحصول على الترتيب.

تجنب استخدامها عندما:

  • السرعة القصوى هي أولويتك (HashSet أسرع).
  • لا يهمك ترتيب العناصر.
  • ذاكرتك محدودة (TreeSet تستهلك ذاكرة أكثر قليلاً).

🎯 خلاصة الدرس

تعلمنا اليوم أن TreeSet هي مجموعة في جافا تجمع بين ميزتين رائعتين: منع التكرار و الترتيب التلقائي للعناصر. تعتمد على بنية الشجرة لتحقيق ذلك وتوفر لنا طرقاً ذكية للملاحة بين العناصر. تذكر أن اختيارك بين TreeSet و HashSet يعتمد على حاجتك للترتيب مقابل السرعة.