แผนที่ย่อยและมุมมองช่วงค่า
แยกมุมมองด้วย 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)); // trueheadMap: คีย์ที่ต่ำกว่าขอบเขต
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.99subMap แบบย้อนกลับ
เชื่อม 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- TreeMap: คู่คีย์-ค่าที่เรียงลำดับ
- แผนที่ย่อยและมุมมองช่วงค่า
- TreeSet และ NavigableSet
- การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้