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

Mergesort

การเรียงลำดับแบบคงเสถียรภาพ

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

การเรียงลำดับแบบคงลำดับเดิม

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

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

แบ่งอาร์เรย์แบบเรียกซ้ำที่จุดกึ่งกลาง จนแต่ละส่วนมีสมาชิกหนึ่งตัว สมาชิกเพียงตัวเดียวถือว่าเรียงลำดับแล้วโดยปริยาย ซึ่งเป็นกรณีฐาน

ขั้นตอนการผสาน

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

#include <stdio.h>

void merge(int a[], int lo, int mid, int hi, int tmp[]) {
    int i = lo, j = mid + 1, k = lo;
    while (i <= mid && j <= hi)
        tmp[k++] = (a[i] <= a[j]) ? a[i++] : a[j++];
    while (i <= mid) tmp[k++] = a[i++];
    while (j <= hi)  tmp[k++] = a[j++];
    for (int t = lo; t <= hi; t++) a[t] = tmp[t];
}

int main(void) {
    int a[] = {1, 4, 6, 2, 3, 5}; /* two sorted runs */
    int tmp[6];
    merge(a, 0, 2, 5, tmp);
    for (int i = 0; i < 6; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

เหตุผลที่คงลำดับเดิม

การผสานใช้ a[i] <= a[j] ดังนั้นเมื่อสมาชิกสองตัวมีค่าเท่ากัน จะเลือกสมาชิกจากช่วงซ้ายก่อน เนื่องจากช่วงซ้ายเก็บสมาชิกที่มาก่อน จึงรักษาลำดับเดิมไว้ได้

ตัวควบคุมการเรียกซ้ำ

Mergesort เรียกใช้ตัวเองแบบเรียกซ้ำกับแต่ละส่วน แล้วจึงผสาน เราส่งบัฟเฟอร์ชั่วคราวที่ใช้ร่วมกันเข้าไป เพื่อหลีกเลี่ยงการจองหน่วยความจำใหม่ทุกครั้งที่เรียก

#include <stdio.h>

void merge(int a[], int lo, int mid, int hi, int tmp[]) {
    int i=lo, j=mid+1, k=lo;
    while (i<=mid && j<=hi) tmp[k++] = (a[i]<=a[j]) ? a[i++] : a[j++];
    while (i<=mid) tmp[k++]=a[i++];
    while (j<=hi)  tmp[k++]=a[j++];
    for (int t=lo;t<=hi;t++) a[t]=tmp[t];
}
void msort(int a[], int lo, int hi, int tmp[]) {
    if (lo >= hi) return;
    int mid = lo + (hi - lo) / 2;
    msort(a, lo, mid, tmp);
    msort(a, mid + 1, hi, tmp);
    merge(a, lo, mid, hi, tmp);
}

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

การใช้หน่วยความจำ

ต่างจาก quicksort ตรงที่ mergesort ต้องใช้หน่วยความจำเพิ่มเติม O(n) สำหรับบัฟเฟอร์การผสาน นี่คือข้อเสียหลักเมื่อใช้งานกับอาร์เรย์ขนาดใหญ่มากในสภาวะที่หน่วยความจำจำกัด

รับประกัน O(n log n)

การเรียกซ้ำจะแบ่งครึ่งเสมอ ทำให้มีระดับจำนวน log n ระดับ และแต่ละระดับจะผสานสมาชิก n ตัว ดังนั้น mergesort จึงมีความซับซ้อน O(n log n) ในกรณีดีที่สุด โดยเฉลี่ย และแย่ที่สุด ต่างจาก quicksort

การนับระดับการผสาน

จำนวนระดับของการเรียกซ้ำคือ ceil(log2 n) มาคำนวณสำหรับขนาดหลายค่า

#include <stdio.h>

int levels(int n) {
    int L = 0;
    while (n > 1) { n = (n + 1) / 2; L++; }
    return L;
}

int main(void) {
    int sizes[] = {1, 2, 8, 100, 1000};
    for (int i = 0; i < 5; i++)
        printf("n=%d levels=%d\n", sizes[i], levels(sizes[i]));
    return 0;
}

Mergesort จากล่างขึ้นบน

รูปแบบที่วนซ้ำนี้จะผสานช่วงข้อมูลขนาด 1 จากนั้นเป็น 2 แล้วจึงเป็น 4 โดยเพิ่มขนาดเป็นสองเท่าในแต่ละรอบ วิธีนี้ไม่ใช้การเรียกซ้ำเลย และเหมาะกับลิงก์ลิสต์

#include <stdio.h>

void merge(int a[], int lo, int mid, int hi, int tmp[]) {
    int i=lo,j=mid+1,k=lo;
    while(i<=mid&&j<=hi) tmp[k++]=(a[i]<=a[j])?a[i++]:a[j++];
    while(i<=mid) tmp[k++]=a[i++];
    while(j<=hi) tmp[k++]=a[j++];
    for(int t=lo;t<=hi;t++) a[t]=tmp[t];
}

int main(void) {
    int a[] = {5, 2, 9, 1, 3, 8}, n = 6, tmp[6];
    for (int width = 1; width < n; width *= 2)
        for (int lo = 0; lo < n - width; lo += 2 * width) {
            int mid = lo + width - 1;
            int hi = (lo + 2*width - 1 < n-1) ? lo + 2*width - 1 : n-1;
            merge(a, lo, mid, hi, tmp);
        }
    for (int i = 0; i < n; i++) printf("%d ", a[i]);
    printf("\n");
    return 0;
}

เมื่อใดควรเลือก Mergesort

ควรเลือกใช้ mergesort เมื่อคุณต้องการ:

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

Mergesort เทียบกับ Quicksort

Quicksort มักทำงานได้เร็วกว่าในทางปฏิบัติและเรียงลำดับภายในพื้นที่เดิม แต่ไม่คงลำดับเดิมและอาจมีกรณีแย่ที่สุดที่ใช้เวลามาก ส่วน mergesort คงลำดับเดิมและมีขอบเขตเวลาที่รับประกันได้ แต่ใช้หน่วยความจำเพิ่มเติม ให้เลือกตามข้อจำกัดของคุณ

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับ mergesort

สรุปทบทวน

คุณได้เรียนรู้เกี่ยวกับ mergesort

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

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

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

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

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

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

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

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

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

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

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

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

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

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