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

การจัดลำดับแบบกำหนดเองในคอลเลกชันแบบต้นไม้

ส่ง 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, apple

Comparator ขณะสร้าง 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()); // 1

TreeMap ที่ไม่แยกตัวพิมพ์เล็ก-ใหญ่

ความต้องการที่พบได้บ่อยในการใช้งานจริง: 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

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

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