การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้
ส่ง Comparator ให้ TreeMap/TreeSet เพื่อกำหนดลำดับการเรียงตามโดเมน
การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้ เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องใช้การจัดลำดับแบบกำหนดเอง
โครงสร้างข้อมูลแบบต้นไม้ (TreeMap, TreeSet) ใช้ลำดับธรรมชาติโดยค่าเริ่มต้น เมื่ออ็อบเจ็กต์ในโดเมนของคุณไม่มีลำดับธรรมชาติ หรือเมื่อจำเป็นต้องเรียงลำดับแบบอื่น ให้ส่ง Comparator ขณะสร้างโครงสร้าง
Comparator ขณะสร้าง TreeMap
ส่งตัวเปรียบเทียบเพื่อเรียงคีย์ตามกฎแบบกำหนดเอง — ตัวอย่างเช่น เรียงตามลำดับตัวอักษรย้อนกลับ:
import java.util.*;
TreeMap<String, Integer> map = new TreeMap<>(Comparator.reverseOrder());
map.put("banana", 2);
map.put("apple", 1);
map.put("cherry", 3);
map.forEach((k,v) -> System.out.println(k)); // cherry, banana, appleComparator ขณะสร้าง TreeSet
ส่งตัวเปรียบเทียบให้ TreeSet เพื่อควบคุมลำดับการเรียงโดยไม่ขึ้นกับลำดับธรรมชาติของสมาชิก:
TreeSet<String> byLength = new TreeSet<>(
Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder())
);
byLength.addAll(List.of("fig","apple","kiwi","date","banana"));
for (String s : byLength) System.out.print(s + " ");
// fig date kiwi apple bananaการเรียงอ็อบเจ็กต์ตามหลายฟิลด์
เชื่อมตัวเปรียบเทียบเพื่อเรียงตามฟิลด์หลัก แล้วใช้ฟิลด์รองเป็นเกณฑ์ตัดสินเมื่อค่าเท่ากัน:
record Employee(String name, String dept, int salary) {}
TreeSet<Employee> sorted = new TreeSet<>(
Comparator.comparing(Employee::dept)
.thenComparingInt(Employee::salary).reversed()
.thenComparing(Employee::name)
);
sorted.add(new Employee("Alice", "Eng", 90_000));
sorted.add(new Employee("Bob", "Eng", 85_000));
sorted.add(new Employee("Carol", "HR", 70_000));
for (Employee e : sorted) System.out.println(e.dept()+" "+e.name());ความสอดคล้องกับความเท่ากัน
กฎสำคัญ: ตัวเปรียบเทียบที่ TreeSet/TreeMap ใช้จะเป็นตัวกำหนดความเท่ากันสำหรับโครงสร้างข้อมูล หาก comparator.compare(a, b) == 0 จะถือว่า a และ b เป็นคีย์เดียวกัน — แม้ว่า a.equals(b) จะเป็นเท็จก็ตาม
// Comparator ignoring case — "apple" and "APPLE" become the same key!
TreeSet<String> ci = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
ci.add("apple");
ci.add("APPLE"); // not added — same by comparator
System.out.println(ci.size()); // 1TreeMap ที่ไม่แยกตัวพิมพ์เล็ก-ใหญ่
ความต้องการที่พบได้บ่อยในการใช้งานจริง: TreeMap ที่คีย์เป็นข้อความซึ่งไม่แยกตัวพิมพ์เล็ก-ใหญ่ (มีประโยชน์สำหรับส่วนหัวของคำขอเว็บและคีย์การตั้งค่า):
TreeMap<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
headers.put("Content-Type", "application/json");
headers.put("content-type", "text/html"); // overwrites!
System.out.println(headers.get("CONTENT-TYPE")); // text/html
System.out.println(headers.size()); // 1ตัวเปรียบเทียบที่รองรับค่าว่าง
โครงสร้างข้อมูลแบบต้นไม้ที่ใช้ลำดับธรรมชาติจะโยน NPE เมื่อคีย์เป็นค่าว่าง ให้ใช้ตัวเปรียบเทียบที่รองรับค่าว่าง เพื่อให้ค่าว่างเป็นคีย์ที่มีค่าต่ำสุดได้:
TreeMap<String, Integer> map = new TreeMap<>(
Comparator.nullsFirst(Comparator.naturalOrder())
);
map.put(null, 0);
map.put("b", 2);
map.put("a", 1);
map.forEach((k,v) -> System.out.println(k + "=" + v));
// null=0, a=1, b=2ตัวอย่างอ็อบเจ็กต์ในโดเมน: Product ตามราคา
เรียงสินค้าใน TreeSet ตามราคา โดยใช้ชื่อเป็นเกณฑ์ตัดสินเมื่อราคาเท่ากัน เพื่อรักษาความไม่ซ้ำกัน:
record Product(String name, double price) {}
TreeSet<Product> catalog = new TreeSet<>(
Comparator.comparingDouble(Product::price)
.thenComparing(Product::name)
);
catalog.add(new Product("Widget", 9.99));
catalog.add(new Product("Gadget", 24.99));
catalog.add(new Product("Donut", 9.99));
catalog.forEach(p -> System.out.println(p.name() + " $" + p.price()));
// Donut $9.99, Widget $9.99, Gadget $24.99การเรียกดูตัวเปรียบเทียบ
เรียก comparator() บน TreeMap/TreeSet เพื่อเรียกดูตัวเปรียบเทียบแบบกำหนดเอง จะคืนค่า null หากใช้ลำดับธรรมชาติ
TreeMap<String, Integer> map = new TreeMap<>(Comparator.reverseOrder());
System.out.println(map.comparator() != null); // true
TreeMap<String, Integer> natural = new TreeMap<>();
System.out.println(natural.comparator()); // nullการประกอบตัวเปรียบเทียบ
Comparator ของ Java มีเมธอดสำหรับสร้างแบบเชื่อมต่อกัน เพื่อประกอบการจัดลำดับได้อย่างกระชับ:
Comparator<String> comp =
Comparator.comparingInt(String::length) // by length
.thenComparing(Comparator.naturalOrder()); // then alphabetically
TreeSet<String> ts = new TreeSet<>(comp);
ts.addAll(List.of("go", "java", "c", "rust", "py"));
ts.forEach(s -> System.out.print(s + " "));
// c go py java rustเมื่อใดไม่ควรใช้ตัวเปรียบเทียบแบบกำหนดเอง
หลีกเลี่ยงการใช้ตัวเปรียบเทียบที่ไม่สอดคล้องกับความเท่ากันกับคีย์ของ TreeMap หรือสมาชิกของ TreeSet เพราะจะทำให้เกิดรายการที่ดูเหมือน “หายไป” ตรวจสอบให้แน่ใจว่า compare(a, b) == 0 ก็ต่อเมื่อ a.equals(b) เท่านั้น เพื่อให้ทำงานได้ถูกต้องในบริบทของโครงสร้างข้อมูลทั้งหมด
ตรวจสอบความเข้าใจ
TreeSet ใช้ตัวเปรียบเทียบที่พิจารณาเฉพาะ String::length จะเกิดอะไรขึ้นเมื่อคุณเพิ่มทั้ง "cat" และ "dog"
สรุป: การจัดลำดับแบบกำหนดเอง
ประเด็นสำคัญ:
- ส่ง Comparator ไปยังตัวสร้าง TreeMap/TreeSet เพื่อกำหนดการจัดลำดับแบบกำหนดเอง
- ความเท่าเทียมที่กำหนดโดย Comparator เป็นตัวกำหนดความไม่ซ้ำกันในคอลเลกชันแบบต้นไม้
- ตรวจสอบให้ Comparator สอดคล้องกับ equals เพื่อหลีกเลี่ยงผลลัพธ์ที่ไม่คาดคิด
- ใช้ Comparator.nullsFirst/nullsLast เพื่อจัดลำดับที่รองรับค่า null
- เชื่อมต่อด้วย thenComparing เพื่อเรียงลำดับตามหลายฟิลด์
คำถามที่พบบ่อย
บทเรียน “การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้”
ส่ง Comparator ให้ TreeMap/TreeSet เพื่อกำหนดลำดับการเรียงตามโดเมน คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- TreeMap: คู่คีย์-ค่าที่เรียงลำดับ
- แผนที่ย่อยและมุมมองช่วงค่า
- TreeSet และ NavigableSet
- การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้