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

Quicksort

แบ่งแยกและพิชิต

Quicksort เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

แบ่งและพิชิต

การเรียงลำดับแบบเร็วเป็นการเรียงลำดับแบบแบ่งและพิชิต โดยเลือกจุดหมุน แบ่งอาร์เรย์ให้สมาชิกที่เล็กกว่าไปทางซ้ายและสมาชิกที่ใหญ่กว่าไปทางขวา จากนั้นเรียงลำดับแต่ละฝั่งแบบเรียกซ้ำ

เวลาเฉลี่ยคือ O(n log n)

ขั้นตอนการแบ่งส่วน

แนวคิดสำคัญคือการแบ่งส่วน: จัดเรียงอาร์เรย์ใหม่รอบจุดหมุน เพื่อให้ทุกสิ่งทางซ้ายของจุดหมุนมีค่าน้อยกว่า และทุกสิ่งทางขวามีค่ามากกว่า จากนั้นจุดหมุนจะอยู่ในตำแหน่งสุดท้ายตามลำดับ

รูปแบบการแบ่งส่วนแบบ Lomuto

รูปแบบ Lomutoใช้สมาชิกตัวสุดท้ายเป็นจุดหมุน โดยเก็บดัชนี i เป็นขอบเขตของสมาชิกที่มีค่าน้อยกว่า และสลับสมาชิกขณะเดินตรวจสอบ

#include <stdio.h>

int partition(int a[], int lo, int hi) {
    int pivot = a[hi], i = lo - 1;
    for (int j = lo; j < hi; j++)
        if (a[j] < pivot) {
            i++;
            int t = a[i]; a[i] = a[j]; a[j] = t;
        }
    int t = a[i+1]; a[i+1] = a[hi]; a[hi] = t;
    return i + 1;
}

int main(void) {
    int a[] = {5, 2, 9, 1, 3};
    int p = partition(a, 0, 4);
    printf("pivot index = %d\n", p);
    for (int i = 0; i < 5; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

การเรียงลำดับแบบเรียกซ้ำ

การเรียงลำดับแบบเร็วจะเรียกการแบ่งส่วน แล้วเรียกซ้ำกับอาร์เรย์ย่อยสองส่วนรอบจุดหมุน กรณีฐานคืออาร์เรย์ย่อยที่มีขนาด 0 หรือ 1

#include <stdio.h>

int partition(int a[], int lo, int hi) {
    int pivot = a[hi], i = lo - 1;
    for (int j = lo; j < hi; j++)
        if (a[j] < pivot) { i++; int t=a[i];a[i]=a[j];a[j]=t; }
    int t = a[i+1]; a[i+1] = a[hi]; a[hi] = t;
    return i + 1;
}

void quicksort(int a[], int lo, int hi) {
    if (lo < hi) {
        int p = partition(a, lo, hi);
        quicksort(a, lo, p - 1);
        quicksort(a, p + 1, hi);
    }
}

int main(void) {
    int a[] = {9, 3, 7, 1, 8, 2, 5};
    quicksort(a, 0, 6);
    for (int i = 0; i < 7; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

การเลือกจุดหมุนที่ดี

จุดหมุนที่ไม่ดี (เช่น เลือกสมาชิกตัวสุดท้ายเสมอเมื่อข้อมูลเรียงลำดับแล้ว) ทำให้มีพฤติกรรม O(n ยกกำลังสอง) ตัวเลือกที่ดีกว่าจะกระจายส่วนต่าง ๆ ได้สม่ำเสมอยิ่งขึ้น

  • ค่ามัธยฐานจากสามตัว
  • จุดหมุนแบบสุ่ม

ค่ามัธยฐานจากสามตัว

ค่ามัธยฐานจากสามตัวจะเลือกค่ามัธยฐานของสมาชิกตัวแรก ตัวกลาง และตัวสุดท้ายเป็นจุดหมุน เพื่อหลีกเลี่ยงพฤติกรรมกรณีเลวร้ายที่สุดกับข้อมูลที่เรียงลำดับอยู่แล้ว

#include <stdio.h>

int median_of_three(int a[], int lo, int hi) {
    int mid = lo + (hi - lo) / 2;
    if (a[mid] < a[lo]) { int t=a[mid];a[mid]=a[lo];a[lo]=t; }
    if (a[hi] < a[lo])  { int t=a[hi];a[hi]=a[lo];a[lo]=t; }
    if (a[hi] < a[mid]) { int t=a[hi];a[hi]=a[mid];a[mid]=t; }
    return mid;
}

int main(void) {
    int a[] = {7, 1, 5, 3, 9};
    int m = median_of_three(a, 0, 4);
    printf("median value = %d\n", a[m]);
    return 0;
}

การวิเคราะห์กรณีเลวร้ายที่สุด

หากทุกการแบ่งส่วนแยกสมาชิกออกมาได้เพียงหนึ่งตัว ความลึกของการเรียกซ้ำจะกลายเป็น n และต้นทุนเป็น O(n ยกกำลังสอง) เหตุการณ์นี้เกิดขึ้นเมื่อใช้จุดหมุนคงที่กับข้อมูลที่เรียงลำดับหรือเรียงย้อนกลับ

การสุ่มทำให้กรณีเลวร้ายที่สุดเกิดขึ้นได้ยากมาก

จุดหมุนแบบสุ่ม

การสลับสมาชิกแบบสุ่มไปยังตำแหน่งจุดหมุนก่อนแบ่งส่วนช่วยป้องกันข้อมูลนำเข้าที่ออกแบบมาเพื่อทำให้การทำงานแย่ลง

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int a[] = {1, 2, 3, 4, 5};
    int lo = 0, hi = 4;
    srand(42);
    int r = lo + rand() % (hi - lo + 1);
    int t = a[r]; a[r] = a[hi]; a[hi] = t; /* move random to pivot slot */
    printf("chosen pivot = %d\n", a[hi]);
    return 0;
}

ทำงานในตำแหน่งเดิมและไม่คงเสถียร

การเรียงลำดับแบบเร็วจะเรียงข้อมูลในตำแหน่งเดิม โดยใช้พื้นที่สแตกเพียง O(log n) โดยเฉลี่ย อย่างไรก็ตาม วิธีนี้ไม่คงเสถียร: สมาชิกที่เท่ากันอาจถูกสลับลำดับจากการสลับระหว่างแบ่งส่วน

การปรับปรุงการเรียกส่วนท้าย

การเรียกซ้ำกับครึ่งที่เล็กกว่าก่อน แล้วใช้ลูปกับครึ่งที่ใหญ่กว่า จะจำกัดความลึกของสแตกไว้ที่ O(log n) และป้องกันสแตกล้นกับอาร์เรย์ขนาดใหญ่

การเรียงลำดับสตริง

โครงสร้างเดียวกันนี้ใช้เรียงลำดับชนิดข้อมูลใด ๆ ที่เปรียบเทียบได้ ในที่นี้การเรียงลำดับแบบเร็วจัดลำดับอาร์เรย์จำนวนเต็ม แต่การเปลี่ยนการเปรียบเทียบก็รองรับชนิดข้อมูลอื่นได้

#include <stdio.h>

int partition(int a[], int lo, int hi) {
    int pivot = a[hi], i = lo - 1;
    for (int j = lo; j < hi; j++)
        if (a[j] < pivot) { i++; int t=a[i];a[i]=a[j];a[j]=t; }
    int t = a[i+1]; a[i+1] = a[hi]; a[hi] = t; return i + 1;
}
void quicksort(int a[], int lo, int hi) {
    if (lo < hi) { int p = partition(a, lo, hi); quicksort(a, lo, p-1); quicksort(a, p+1, hi); }
}

int main(void) {
    int a[] = {42, -7, 0, 100, 13, 13};
    quicksort(a, 0, 5);
    for (int i = 0; i < 6; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

ตรวจสอบความเข้าใจ

ทดสอบความเข้าใจของคุณเกี่ยวกับการเรียงลำดับแบบเร็ว

สรุปทบทวน

คุณได้เรียนรู้การเรียงลำดับแบบเร็ว

  • แบ่งส่วนรอบจุดหมุน แล้วเรียกซ้ำกับแต่ละฝั่ง
  • ค่าเฉลี่ย O(n log n) และกรณีเลวร้ายที่สุด O(n ยกกำลังสอง)
  • จุดหมุนแบบค่ามัธยฐานจากสามตัวหรือแบบสุ่มช่วยหลีกเลี่ยงกรณีเลวร้ายที่สุด
  • ทำงานในตำแหน่งเดิมแต่ไม่คงเสถียร

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

บทเรียน “Quicksort” ฟรีหรือไม่

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

คุณจะเรียนรู้อะไรในบทเรียน “Quicksort”

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

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

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

บทเรียน “Quicksort” ใช้เวลานานแค่ไหน

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

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

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

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

  1. การเรียงแบบฟองและแบบแทรก
  2. Quicksort
  3. Mergesort
  4. การใช้ qsort
← กลับไปที่ C Academy