0Pricing
Java Academy · บทเรียน

แผนที่ย่อยและมุมมองช่วงค่า

แยกมุมมองด้วย subMap, headMap และ tailMap เพื่อค้นหาตามช่วงในแผนที่ที่เรียงลำดับ

แผนที่ย่อยและมุมมองช่วงค่า เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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) แบบ 4 อาร์กิวเมนต์ช่วยให้ควบคุมการรวมขอบเขตได้อย่างเต็มที่:

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) แบบ 4 อาร์กิวเมนต์ใช้ควบคุมขอบเขตได้อย่างเต็มที่
  • การใช้ put นอกช่วงผ่านมุมมองจะทำให้เกิด IllegalArgumentException
  • ความซับซ้อนของการสแกนตามช่วง: O(log N + n)

คำถามที่พบบ่อย

บทเรียน “แผนที่ย่อยและมุมมองช่วงค่า” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “แผนที่ย่อยและมุมมองช่วงค่า” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “แผนที่ย่อยและมุมมองช่วงค่า”

แยกมุมมองด้วย subMap, headMap และ tailMap เพื่อค้นหาตามช่วงในแผนที่ที่เรียงลำดับ คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “แผนที่ย่อยและมุมมองช่วงค่า” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. TreeMap: คู่คีย์-ค่าที่เรียงลำดับ
  2. แผนที่ย่อยและมุมมองช่วงค่า
  3. TreeSet และ NavigableSet
  4. การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้
← กลับไปที่ Java Academy