0Pricing
Java Academy · درس

الخرائط الفرعية وعروض النطاق

استخرج عروض subMap وheadMap وtailMap لإجراء عمليات بحث حسب النطاق في الخرائط المرتبة

الخرائط الفرعية وعروض النطاق درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.

عروض النطاق في TreeMap

تعيد subMap وheadMap وtailMap في TreeMap عروضًا مرتبطة بالخريطة الأصلية؛ فهي تعكس التغييرات في الخريطة الأساسية والعكس صحيح. كما تنعكس التغييرات التي تُجرى عبر العرض في الخريطة الأصلية.

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 1; i <= 10; i++) map.put(i * 10, "item" + i);

var view = map.subMap(30, 70); // [30, 70)
System.out.println(view); // {30=item3, 40=item4, 50=item5, 60=item6}

map.put(45, "new"); // also visible through view!
System.out.println(view.containsKey(45)); // true

headMap: المفاتيح الأقل من حد

تعيد headMap(toKey) جميع الإدخالات التي مفاتيحها أصغر تمامًا من toKey. استخدم النسخة الشاملة headMap(toKey, true) لتضمين الحد.

TreeMap<String, Integer> words = new TreeMap<>();
"banana cherry apple date elderberry".chars()
    .mapToObj(c -> String.valueOf((char)c)).distinct()
    .forEach(w -> words.put(w, w.length()));
// Actually let's use real words:
TreeMap<String, Integer> wc = new TreeMap<>();
wc.put("apple",5); wc.put("banana",6); wc.put("cherry",6); wc.put("date",4);

System.out.println(wc.headMap("cherry")); // {apple=5, banana=6}

tailMap: المفاتيح بدءًا من حد

تعيد tailMap(fromKey) جميع الإدخالات التي مفاتيحها أكبر من أو تساوي fromKey.

TreeMap<Integer, String> grades = new TreeMap<>();
grades.put(50,"F"); grades.put(60,"D"); grades.put(70,"C"); grades.put(80,"B"); grades.put(90,"A");

// All passing grades (>= 60)
var passing = grades.tailMap(60);
System.out.println(passing); // {60=D, 70=C, 80=B, 90=A}

subMap مع حدود شاملة

تمنح subMap(from, fromInclusive, to, toInclusive) ذات الوسائط الأربعة تحكمًا كاملًا في شمول الحدود:

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 10; i <= 100; i += 10) map.put(i, "v"+i);

// [30, 60] — both inclusive
System.out.println(map.subMap(30, true, 60, true));
// {30=v30, 40=v40, 50=v50, 60=v60}

// (30, 60) — both exclusive
System.out.println(map.subMap(30, false, 60, false));
// {40=v40, 50=v50}

التعديل من خلال عرض

تنعكس عمليات put/remove على عرض subMap في الخريطة الأصلية، والعكس صحيح. وتؤدي محاولة إدراج مفتاح خارج نطاق العرض إلى رمي استثناء.

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 1; i <= 5; i++) map.put(i * 10, "v" + i);

var view = map.subMap(20, 40); // [20, 40)
view.remove(20); // removes from both view and original map
System.out.println(map.containsKey(20)); // false

// This would throw IllegalArgumentException:
// view.put(50, "out of range");

حالة استخدام: استعلام عن نطاق من السجلات

استرجع جميع إدخالات السجل الواقعة بين طابعين زمنيين باستخدام عرض نطاق من TreeMap:

import java.time.*;
TreeMap<LocalDateTime, String> logs = new TreeMap<>();
logs.put(LocalDateTime.of(2024,1,1,8,0), "Server start");
logs.put(LocalDateTime.of(2024,1,1,10,0), "Request spike");
logs.put(LocalDateTime.of(2024,1,1,14,0), "Maintenance");
logs.put(LocalDateTime.of(2024,1,1,18,0), "Server stop");

var morning = logs.subMap(
    LocalDateTime.of(2024,1,1,8,0), true,
    LocalDateTime.of(2024,1,1,12,0), false
);
morning.forEach((t,m) -> System.out.println(t+" : "+m));

حالة استخدام: البحث ضمن نطاق سعري

اعثر على جميع المنتجات الواقعة ضمن نطاق سعري باستخدام أسعار المنتجات مفاتيحَ لـ TreeMap:

TreeMap<Double, String> products = new TreeMap<>();
products.put(9.99, "Pen");
products.put(24.99, "Book");
products.put(49.99, "Headphones");
products.put(299.99, "Tablet");

double min = 10.0, max = 100.0;
var affordable = products.subMap(min, true, max, true);
affordable.forEach((p,n) -> System.out.println(n+" $"+p));
// Book $24.99, Headphones $49.99

subMap تنازلي

سلسِل descendingMap() مع أحد العروض للتنقل بترتيب عكسي:

TreeMap<Integer, String> map = new TreeMap<>();
for (int i = 10; i <= 100; i += 10) map.put(i, "v"+i);

// Get [40, 80] in descending order
map.subMap(40, true, 80, true)
   .descendingMap()
   .forEach((k,v) -> System.out.println(k + "=" + v));
// 80=v80, 70=v70, 60=v60, 50=v50, 40=v40

واجهة NavigableMap

تمتد NavigableMap من SortedMap، وتضيف التنقل باستخدام مفاتيح ceiling وfloor وhigher وlower، إلى جانب العروض التنازلية. تُعد TreeMap التطبيق الأكثر شيوعًا، بينما تُعد ConcurrentSkipListMap البديل الآمن للخيوط.

أداء العروض

تملك عمليات عرض النطاق الفرعي، مثل get وput وcontainsKey، التعقيد نفسه O(log n) الموجود في TreeMap الأساسية. أما إنشاء العرض نفسه فتعقيده O(1)، إذ لا يحدث أي نسخ. وتكون عمليات مسح نطاق يحتوي على n من المفاتيح في العرض بتعقيد O(log N + n)، حيث تمثل N حجم الخريطة بالكامل.

مشكلة شائعة: العروض القديمة

بما أن العروض مرتبطة بالخريطة الأصلية، فقد يصبح العرض فارغًا أو يرمي استثناءً إذا مُسحت الخريطة الأصلية. احرص دائمًا على توثيق أن العروض حية، ولا تحتفظ بها بعد دورة حياتها المقصودة.

TreeMap<Integer, String> map = new TreeMap<>();
map.put(10, "a"); map.put(20, "b"); map.put(30, "c");

var view = map.subMap(10, 30);
map.clear(); // view becomes empty
System.out.println(view.size()); // 0 — but no exception

تحقق سريع

تستدعي map.subMap(30, false, 70, true) على TreeMap بالمفاتيح {10,20,30,40,50,60,70,80}. ما المفاتيح المضمّنة في النتيجة؟

مراجعة: الخرائط الفرعية وعروض النطاق

أهم النقاط:

  • تعيد subMap وheadMap وtailMap عروضًا حية مرتبطة بالخريطة الأصلية، من دون نسخ
  • تنعكس التغييرات في العرض على الخريطة الأصلية، والعكس صحيح
  • استخدم subMap(from, fromInclusive, to, toInclusive) ذات الوسائط الأربعة للتحكم الكامل في الحدود
  • تؤدي عمليات put خارج النطاق عبر العرض إلى رمي IllegalArgumentException
  • تعقيد مسح النطاق هو O(log N + n)

الأسئلة الشائعة

هل درس «الخرائط الفرعية وعروض النطاق» مجاني؟

نعم — نص درس «الخرائط الفرعية وعروض النطاق» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.

ماذا ستتعلم في «الخرائط الفرعية وعروض النطاق»؟

استخرج عروض subMap وheadMap وtailMap لإجراء عمليات بحث حسب النطاق في الخرائط المرتبة تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟

لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «الخرائط الفرعية وعروض النطاق»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟

نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. TreeMap: أزواج المفاتيح والقيم المرتبة
  2. الخرائط الفرعية وعروض النطاق
  3. TreeSet وNavigableSet
  4. الترتيب المخصص في مجموعات الأشجار
← العودة إلى Java Academy