Quicksort vs heapsort


95

ทั้ง Quicksort และ heapsort ทำการเรียงลำดับในสถานที่ แบบไหนดีกว่ากัน? แอปพลิเคชันและกรณีใดบ้างที่เป็นที่ต้องการ


3
สามารถทำซ้ำได้ของQuicksort ที่เหนือกว่า Heap Sort
Bernhard Barker

คำตอบ:


61

บทความนี้มีการวิเคราะห์บางอย่าง

นอกจากนี้จาก Wikipedia:

คู่แข่งที่ตรงที่สุดของ quicksort คือ heapsort โดยทั่วไป Heapsort จะค่อนข้างช้ากว่า Quicksort แต่เวลาทำงานในกรณีที่เลวร้ายที่สุดคือΘ (nlogn) เสมอ Quicksort มักจะเร็วกว่าแม้ว่าจะยังคงมีโอกาสที่จะเกิดประสิทธิภาพในกรณีที่เลวร้ายที่สุดยกเว้นในตัวแปร introsort ซึ่งจะเปลี่ยนเป็น heapsort เมื่อตรวจพบกรณีที่ไม่ดี หากทราบล่วงหน้าว่าฮีปพอร์ตจำเป็นต้องใช้การใช้โดยตรงจะเร็วกว่าการรอให้ introsort เปลี่ยนไปใช้


13
อาจเป็นสิ่งสำคัญที่จะต้องทราบว่าในการใช้งานทั่วไปทั้ง quicksort หรือ heapsort ไม่ใช่ประเภทที่เสถียร
MjrKusanagi

@DVK ตามลิงค์ของคุณcs.auckland.ac.nz/~jmor159/PLDS210/qsort3.htmlการจัดเรียงฮีปใช้เวลาเปรียบเทียบ 2,842 สำหรับ n = 100 แต่ต้องใช้การเปรียบเทียบ 53,113 สำหรับ n = 500 และนั่นหมายความว่าอัตราส่วนระหว่าง n = 500 และ n = 100 คือ 18 เท่าและไม่ตรงกับอัลกอริทึมการเรียงฮีปที่มีความซับซ้อน O (N logN) ฉันเดาว่าน่าจะเป็นไปได้ว่าการใช้งานการเรียงลำดับฮีปของพวกเขามีข้อบกพร่องบางอย่างอยู่ภายใน
DU Jiaen

@DUJiaen - จำไว้ว่า O () เกี่ยวกับพฤติกรรมที่ไม่แสดงอาการที่ N ขนาดใหญ่และมีตัวคูณที่เป็นไปได้
DVK

สิ่งนี้ไม่เกี่ยวข้องกับตัวคูณ หากอัลกอริทึมมีความซับซ้อนของ O (N log N) ก็ควรเป็นไปตามแนวโน้มของ Time (N) = C1 * N * log (N) และถ้าคุณใช้ Time (500) / Time (100) จะเห็นได้ชัดว่า C1 จะหายไปและผลลัพธ์ควรปิดที่ (500 log500) / (100 log100) = 6.7 แต่จากลิงค์ของคุณมันคือ 18 ซึ่งก็คือ เกินขนาดมากเกินไป
DU Jiaen

2
ลิงค์ตาย
PlsWork

128

Heapsort ได้รับการรับรอง O (N log N) สิ่งที่ดีกว่ากรณีที่เลวร้ายที่สุดใน Quicksort Heapsort ไม่ต้องการหน่วยความจำเพิ่มเติมสำหรับอาร์เรย์อื่นในการวางข้อมูลที่สั่งซื้อตามที่ Mergesort ต้องการ เหตุใดแอปพลิเคชันเชิงพาณิชย์จึงติดกับ Quicksort? Quicksort มีอะไรพิเศษกว่าการใช้งานอื่น ๆ ?

ฉันได้ทดสอบอัลกอริทึมด้วยตัวเองและฉันเห็นว่า Quicksort มีบางอย่างที่พิเศษแน่นอน ทำงานได้เร็วเร็วกว่าอัลกอริทึม Heap และ Merge มาก

ความลับของ Quicksort คือแทบจะไม่ทำการแลกเปลี่ยนองค์ประกอบที่ไม่จำเป็น Swap ใช้เวลานาน

ด้วย Heapsort แม้ว่าข้อมูลทั้งหมดของคุณจะถูกเรียงลำดับไปแล้วคุณจะสลับองค์ประกอบ 100% เพื่อสั่งอาร์เรย์

ด้วย Mergesort มันยิ่งแย่ลงไปอีก คุณจะเขียนองค์ประกอบ 100% ในอาร์เรย์อื่นและเขียนกลับในองค์ประกอบเดิมแม้ว่าข้อมูลจะเรียงลำดับแล้วก็ตาม

ด้วย Quicksort คุณจะไม่เปลี่ยนสิ่งที่สั่งซื้อไปแล้ว หากข้อมูลของคุณถูกเรียงลำดับอย่างสมบูรณ์คุณแทบจะไม่ต้องเปลี่ยนอะไรเลย! แม้ว่าจะมีเรื่องยุ่งยากมากมายเกี่ยวกับกรณีที่เลวร้ายที่สุด แต่การปรับปรุงตัวเลือก pivot เพียงเล็กน้อยนอกเหนือจากการรับองค์ประกอบแรกหรือองค์ประกอบสุดท้ายของอาร์เรย์ก็สามารถหลีกเลี่ยงได้ หากคุณได้รับเดือยจากองค์ประกอบที่อยู่ตรงกลางระหว่างองค์ประกอบแรกองค์ประกอบสุดท้ายและองค์ประกอบกลางคุณควรหลีกเลี่ยงกรณีที่เลวร้ายที่สุด

สิ่งที่เหนือกว่าใน Quicksort ไม่ใช่กรณีที่เลวร้ายที่สุด แต่เป็นกรณีที่ดีที่สุด! ในกรณีที่ดีที่สุดคุณทำการเปรียบเทียบในจำนวนเท่ากันก็โอเค แต่คุณแทบไม่ได้สลับอะไรเลย โดยเฉลี่ยแล้วคุณจะสลับบางส่วนขององค์ประกอบ แต่ไม่ใช่องค์ประกอบทั้งหมดเช่นเดียวกับใน Heapsort และ Mergesort นั่นคือสิ่งที่ทำให้ Quicksort มีเวลาที่ดีที่สุด แลกเปลี่ยนน้อยลงความเร็วมากขึ้น

การใช้งานด้านล่างใน C # บนคอมพิวเตอร์ของฉันทำงานในโหมดรีลีสเต้น Array เรียงลำดับ 3 วินาทีด้วยเดือยกลางและ 2 วินาทีพร้อมเดือยที่ปรับปรุงแล้ว (ใช่มีค่าใช้จ่ายในการรับเดือยที่ดี)

static void Main(string[] args)
{
    int[] arrToSort = new int[100000000];
    var r = new Random();
    for (int i = 0; i < arrToSort.Length; i++) arrToSort[i] = r.Next(1, arrToSort.Length);

    Console.WriteLine("Press q to quick sort, s to Array.Sort");
    while (true)
    {
        var k = Console.ReadKey(true);
        if (k.KeyChar == 'q')
        {
            // quick sort
            Console.WriteLine("Beg quick sort at " + DateTime.Now.ToString("HH:mm:ss.ffffff"));
            QuickSort(arrToSort, 0, arrToSort.Length - 1);
            Console.WriteLine("End quick sort at " + DateTime.Now.ToString("HH:mm:ss.ffffff"));
            for (int i = 0; i < arrToSort.Length; i++) arrToSort[i] = r.Next(1, arrToSort.Length);
        }
        else if (k.KeyChar == 's')
        {
            Console.WriteLine("Beg Array.Sort at " + DateTime.Now.ToString("HH:mm:ss.ffffff"));
            Array.Sort(arrToSort);
            Console.WriteLine("End Array.Sort at " + DateTime.Now.ToString("HH:mm:ss.ffffff"));
            for (int i = 0; i < arrToSort.Length; i++) arrToSort[i] = r.Next(1, arrToSort.Length);
        }
    }
}

static public void QuickSort(int[] arr, int left, int right)
{
    int begin = left
        , end = right
        , pivot
        // get middle element pivot
        //= arr[(left + right) / 2]
        ;

    //improved pivot
    int middle = (left + right) / 2;
    int
        LM = arr[left].CompareTo(arr[middle])
        , MR = arr[middle].CompareTo(arr[right])
        , LR = arr[left].CompareTo(arr[right])
        ;
    if (-1 * LM == LR)
        pivot = arr[left];
    else
        if (MR == -1 * LR)
            pivot = arr[right];
        else
            pivot = arr[middle];
    do
    {
        while (arr[left] < pivot) left++;
        while (arr[right] > pivot) right--;

        if(left <= right)
        {
            int temp = arr[right];
            arr[right] = arr[left];
            arr[left] = temp;

            left++;
            right--;
        }
    } while (left <= right);

    if (left < end) QuickSort(arr, left, end);
    if (begin < right) QuickSort(arr, begin, right);
}

10
+1 สำหรับการพิจารณาเกี่ยวกับหมายเลข ของการแลกเปลี่ยนการดำเนินการอ่าน / เขียนที่จำเป็นสำหรับอัลกอริทึมการเรียงลำดับต่างๆ
ycy

2
สำหรับกลยุทธ์การเลือกเดือยที่กำหนดเวลาคงที่คุณสามารถค้นหาอาร์เรย์ที่สร้างกรณีที่เลวร้ายที่สุด O (n ^ 2) ไม่เพียงพอที่จะกำจัดเพียงขั้นต่ำ คุณต้องเลือก pivots ที่อยู่ในวงดนตรีเฉพาะที่เชื่อถือได้
พลวง

1
ฉันสงสัยว่านี่เป็นรหัสที่แน่นอนที่คุณใช้สำหรับการจำลองของคุณระหว่างการเรียงลำดับด่วนที่เข้ารหัสด้วยมือและ C # ในตัว Array.sort หรือไม่? ฉันทดสอบรหัสนี้และในการทดสอบทั้งหมดของฉันอย่างดีที่สุดการเรียงลำดับด่วนด้วยรหัสด้วยมือนั้นเหมือนกับ Array.sort สิ่งหนึ่งที่ฉันควบคุมในการทดสอบนี้คือการทำสำเนาอาร์เรย์แบบสุ่มสองชุดที่เหมือนกัน ท้ายที่สุดแล้วการสุ่มที่กำหนดอาจเป็นที่ชื่นชอบมากกว่า (พึ่งพากรณีที่ดีที่สุด) มากกว่าการสุ่มแบบอื่น ดังนั้นฉันจึงวิ่งชุดที่เหมือนกันในแต่ละชุด Array.sort ผูกหรือเอาชนะทุกครั้ง (ปล่อยบิลด์ btw)
คริส

1
การเรียงลำดับการผสานไม่จำเป็นต้องคัดลอกองค์ประกอบ 100% เว้นแต่จะเป็นการใช้งานที่ไร้เดียงสาจากตำราเรียน ใช้งานได้ง่ายดังนั้นคุณต้องคัดลอก 50% เท่านั้น (ด้านซ้ายของอาร์เรย์ที่ผสานทั้งสอง) การเลื่อนการคัดลอกเป็นเรื่องเล็กน้อยจนกว่าคุณจะต้อง "สลับ" สององค์ประกอบจริงๆดังนั้นด้วยข้อมูลที่เรียงลำดับแล้วคุณจะไม่มีหน่วยความจำเหนือศีรษะ ดังนั้นแม้แต่ 50% ก็เป็นกรณีที่แย่ที่สุดและคุณสามารถมีอะไรก็ได้ระหว่างนั้นถึง 0%
ddekany

1
@MarquinhoPeli ฉันตั้งใจจะบอกว่าคุณต้องการหน่วยความจำที่มีอยู่เพิ่มขึ้นเพียง 50% เมื่อเทียบกับขนาดของรายการที่เรียงลำดับไม่ใช่ 100% ซึ่งดูเหมือนจะเป็นความเข้าใจผิดทั่วไป ดังนั้นฉันจึงพูดถึงการใช้หน่วยความจำสูงสุด ฉันไม่สามารถให้ลิงค์ได้ แต่มันง่ายที่จะดูว่าคุณพยายามรวมทั้งสองที่จัดเรียงไว้แล้วครึ่งหนึ่งของอาร์เรย์เข้าที่หรือไม่ (มีเพียงครึ่งซ้ายเท่านั้นที่มีปัญหาในการเขียนทับองค์ประกอบที่คุณยังไม่ได้ใช้) คุณต้องทำสำเนาหน่วยความจำเท่าใดในระหว่างกระบวนการจัดเรียงทั้งหมดเป็นอีกคำถามหนึ่ง แต่เห็นได้ชัดว่ากรณีที่เลวร้ายที่สุดต้องไม่ต่ำกว่า 100% สำหรับอัลกอริทึมการเรียงลำดับใด ๆ
ddekany

15

สำหรับสถานการณ์ส่วนใหญ่การเร็วกับเร็วกว่าเล็กน้อยนั้นไม่เกี่ยวข้อง ... คุณแค่ไม่ต้องการให้มันช้าลงในบางครั้ง แม้ว่าคุณจะสามารถปรับแต่ง QuickSort เพื่อหลีกเลี่ยงสถานการณ์ที่เชื่องช้า แต่คุณก็สูญเสียความสง่างามของ QuickSort พื้นฐานไป ดังนั้นสำหรับสิ่งส่วนใหญ่ฉันชอบ HeapSort จริงๆ ... คุณสามารถใช้งานได้ด้วยความสง่างามที่เรียบง่ายเต็มรูปแบบและไม่เคยช้าเลย

สำหรับสถานการณ์ที่คุณต้องการความเร็วสูงสุดในกรณีส่วนใหญ่ QuickSort อาจเป็นที่ต้องการมากกว่า HeapSort แต่อาจไม่ใช่คำตอบที่ถูกต้อง สำหรับสถานการณ์ที่สำคัญอย่างรวดเร็วควรตรวจสอบรายละเอียดของสถานการณ์อย่างใกล้ชิด ตัวอย่างเช่นในโค้ด speed-Critical บางส่วนของฉันเป็นเรื่องปกติมากที่ข้อมูลจะถูกจัดเรียงหรือจัดเรียงใกล้เคียงอยู่แล้ว (เป็นการทำดัชนีฟิลด์ที่เกี่ยวข้องหลายฟิลด์ซึ่งมักจะเลื่อนขึ้นและลงพร้อมกันหรือเลื่อนขึ้นและลงตรงข้ามกัน ดังนั้นเมื่อคุณเรียงลำดับทีละรายการรายการอื่น ๆ จะถูกจัดเรียงหรือเรียงลำดับย้อนกลับหรือปิด ... ซึ่งทั้งสองอย่างสามารถฆ่า QuickSort ได้) สำหรับกรณีนั้นฉันไม่ได้ใช้งาน ... แต่ฉันใช้ SmoothSort ของ Dijkstra ... ตัวแปร HeapSort ที่เป็น O (N) เมื่อเรียงลำดับแล้วหรือใกล้เรียงแล้ว ... มันไม่สวยหรูไม่เข้าใจง่ายเกินไป แต่เร็ว ... อ่านhttp://www.cs.utexas.edu/users/EWD/ewd07xx/EWD796a.PDFหากคุณต้องการอะไรที่ท้าทายกว่านี้ในการเขียนโค้ด


6

Quicksort-Heapsort ลูกผสมในสถานที่ก็น่าสนใจเช่นกันเนื่องจากส่วนใหญ่ต้องการการเปรียบเทียบ n * log n ในกรณีที่เลวร้ายที่สุด (เหมาะสมที่สุดเมื่อเทียบกับระยะแรกของ asymptotics ดังนั้นพวกเขาจึงหลีกเลี่ยงสถานการณ์ที่เลวร้ายที่สุด ของ Quicksort), O (log n) พื้นที่พิเศษและพวกมันรักษาพฤติกรรมที่ดีของ Quicksort ไว้อย่างน้อย "ครึ่งหนึ่ง" ตามชุดข้อมูลที่สั่งไว้แล้ว Dikert และ Weiss นำเสนออัลกอริทึมที่น่าสนใจอย่างยิ่งในhttp://arxiv.org/pdf/1209.4214v1.pdf :

  • เลือก pivot p เป็นค่ามัธยฐานของตัวอย่างสุ่มขององค์ประกอบ sqrt (n) (สามารถทำได้ในการเปรียบเทียบสูงสุด 24 sqrt (n) ผ่านอัลกอริทึมของ Tarjan & co หรือ 5 sqrt (n) การเปรียบเทียบผ่านแมงมุมที่ซับซ้อนมากขึ้น อัลกอริธึมโรงงานของ Schonhage);
  • แบ่งอาร์เรย์ของคุณเป็นสองส่วนเหมือนในขั้นตอนแรกของ Quicksort
  • ฮีปส่วนที่เล็กที่สุดและใช้ O (log n) บิตพิเศษเพื่อเข้ารหัสฮีปที่ชายด์ซ้ายทุกตัวมีค่ามากกว่าพี่น้อง
  • ดึงรูทของฮีปแบบวนซ้ำร่อนลาคูนที่รูตทิ้งไว้จนกว่าจะถึงใบไม้ของกองจากนั้นเติม lacune ด้วยองค์ประกอบที่เหมาะสมซึ่งนำมาจากส่วนอื่นของอาร์เรย์
  • เกิดซ้ำในส่วนที่ไม่ได้เรียงลำดับที่เหลือของอาร์เรย์ (หากเลือก p เป็นค่ามัธยฐานที่แน่นอนจะไม่มีการเรียกซ้ำเลย)

2

คอมพ์ ระหว่างquick sortและmerge sortเนื่องจากทั้งสองเป็นประเภทของการเรียงลำดับในสถานที่จึงมีความแตกต่างระหว่างเวลาทำงานของเคส wrost ของเวลาทำงานของเคส wrost สำหรับการเรียงลำดับอย่างรวดเร็วคือO(n^2)และสำหรับการเรียงฮีปมันจะยังคงอยู่O(n*log(n))และสำหรับจำนวนเฉลี่ยของการจัดเรียงข้อมูลอย่างรวดเร็วจะมีประโยชน์มากกว่า เนื่องจากเป็นอัลกอริทึมแบบสุ่มดังนั้นความน่าจะเป็นที่จะได้รับ ans ที่ถูกต้อง ในเวลาที่น้อยลงจะขึ้นอยู่กับตำแหน่งขององค์ประกอบ Pivot ที่คุณเลือก

ดังนั้นก

การโทรที่ดี:ขนาดของ L และ G แต่ละอันน้อยกว่า 3 วินาที / 4

การโทรไม่ถูกต้อง:หนึ่งใน L และ G มีขนาดมากกว่า 3 วินาที / 4

สำหรับจำนวนเล็กน้อยเราสามารถไปสำหรับการเรียงลำดับการแทรกและสำหรับข้อมูลจำนวนมากไปสำหรับการเรียงลำดับฮีป


แม้ว่าการเรียงลำดับการผสานสามารถนำไปใช้กับการจัดเรียงแบบแทนที่การใช้งานนั้นซับซ้อน AFAIK การใช้งานการเรียงลำดับแบบผสานส่วนใหญ่ไม่ได้อยู่ในสถานที่ แต่มีความเสถียร
MjrKusanagi

2

Heapsort มีประโยชน์ในการมีO (n * log (n)) ที่แย่ที่สุดดังนั้นในกรณีที่ Quicksort มีแนวโน้มที่จะทำงานได้ไม่ดี (โดยทั่วไปแล้วชุดข้อมูลที่เรียงลำดับโดยทั่วไป) จึงเป็นที่ต้องการมาก


4
Quicksort จะทำงานได้ไม่ดีในชุดข้อมูลที่เรียงลำดับส่วนใหญ่หากเลือกวิธีการเลือกเดือยที่ไม่ดี กล่าวคือวิธีการเลือกเดือยที่ไม่ดีคือการเลือกองค์ประกอบแรกหรือองค์ประกอบสุดท้ายเป็นเดือยเสมอ หากมีการเลือกเดือยแบบสุ่มในแต่ละครั้งและมีการใช้วิธีการที่ดีในการจัดการองค์ประกอบซ้ำ ๆ โอกาสที่จะเกิด Quicksort กรณีที่เลวร้ายที่สุดมีน้อยมาก
Justin Peel

1
@ จัสติน - นั่นเป็นเรื่องจริงมากฉันกำลังพูดถึงการใช้งานที่ไร้เดียงสา
zellio

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

2

ถ้าคุณไปที่ระดับสถาปัตยกรรม ... เราใช้โครงสร้างข้อมูลคิวในหน่วยความจำแคชดังนั้นสิ่งที่มีอยู่ในคิวก็จะถูกจัดเรียงเช่นเดียวกับการจัดเรียงอย่างรวดเร็วเราไม่มีปัญหาในการแบ่งอาร์เรย์ออกเป็นความยาวใด ๆ ... แต่ในกอง เรียงลำดับ (โดยใช้อาร์เรย์) จึงอาจเกิดขึ้นได้ว่าพาเรนต์อาจไม่อยู่ในอาร์เรย์ย่อยที่มีอยู่ในแคชจากนั้นจึงต้องนำมาไว้ในหน่วยความจำแคช ... ซึ่งใช้เวลานาน Quicksort ดีที่สุด !! 😀


1

ฮีปพอร์ตสร้างฮีปแล้วแยกไอเท็มสูงสุดซ้ำ ๆ กรณีที่แย่ที่สุดคือ O (n log n)

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

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

สิ่งนี้อาจไม่ตอบคำถามของคุณโดยตรงคิดว่าฉันจะเพิ่มสองเซ็นต์ของฉัน


1
อย่าใช้การเรียงฟอง หากคุณคิดว่าข้อมูลของคุณจะถูกจัดเรียงอย่างสมเหตุสมผลคุณสามารถใช้การจัดเรียงการแทรกหรือแม้กระทั่งทดสอบข้อมูลเพื่อดูว่ามีการจัดเรียงหรือไม่ อย่าใช้ bubbleort
vy32

หากคุณมีชุดข้อมูล RANDOM ที่ใหญ่มากทางออกที่ดีที่สุดของคุณคือ Quicksort หากสั่งซื้อเพียงบางส่วนก็ไม่ได้ แต่ถ้าคุณเริ่มทำงานกับชุดข้อมูลขนาดใหญ่คุณควรรู้อย่างน้อยเกี่ยวกับพวกเขา
Kobor42

1

Heap Sort เป็นเดิมพันที่ปลอดภัยเมื่อจัดการกับอินพุตที่มีขนาดใหญ่มาก การวิเคราะห์ Asymptotic แสดงให้เห็นลำดับการเติบโตของ Heapsort ในกรณีที่เลวร้ายที่สุดคือBig-O(n logn)Quicksort Big-O(n^2)เป็นกรณีที่แย่ที่สุด อย่างไรก็ตามHeapsortค่อนข้างช้าในทางปฏิบัติในเครื่องส่วนใหญ่มากกว่าการจัดเรียงอย่างรวดเร็วที่ใช้งานได้ดี Heapsort ไม่ใช่อัลกอริทึมการเรียงลำดับที่เสถียร

เหตุผลที่ฮีปพอร์ตทำงานช้ากว่า Quicksort นั้นเนื่องมาจากตำแหน่งที่ดีกว่าในการอ้างอิง (" https://en.wikipedia.org/wiki/Locality_of_reference ") ใน Quicksort ซึ่งองค์ประกอบข้อมูลอยู่ในสถานที่จัดเก็บที่ค่อนข้างใกล้ ระบบที่มีแหล่งอ้างอิงที่ชัดเจนเป็นตัวเลือกที่ดีสำหรับการเพิ่มประสิทธิภาพ อย่างไรก็ตามการจัดเรียงแบบฮีปเกี่ยวข้องกับการก้าวกระโดดที่มากขึ้น ทำให้ Quicksort ดีขึ้นสำหรับอินพุตขนาดเล็ก


3
การเรียงลำดับด่วนก็ไม่เสถียรเช่นกัน
พลวง

1

สำหรับฉันแล้วมีความแตกต่างพื้นฐานอย่างมากระหว่าง heapsort และ quicksort: หลังใช้การเรียกซ้ำ ในอัลกอริธึมแบบเรียกซ้ำฮีปจะเพิ่มขึ้นตามจำนวนการเรียกซ้ำ นี่ไม่สำคัญว่าnจะเล็ก แต่ตอนนี้ฉันกำลังเรียงเมทริกซ์สองตัวด้วยn = 10 ^ 9 !! โปรแกรมใช้ ram เกือบ 10 GB และหน่วยความจำเพิ่มเติมใด ๆ จะทำให้คอมพิวเตอร์ของฉันเริ่มการแลกเปลี่ยนกับหน่วยความจำดิสก์เสมือน ดิสก์ของฉันเป็นดิสก์ RAM แต่ยังคงสลับไปมาทำให้ความเร็วแตกต่างกันมาก ดังนั้นใน statpack ที่เข้ารหัส C ++ ซึ่งรวมเมทริกซ์มิติข้อมูลที่ปรับได้โดยไม่ทราบขนาดล่วงหน้าสำหรับโปรแกรมเมอร์และการเรียงลำดับทางสถิติแบบไม่ใช้พารามิเตอร์ฉันชอบฮีปพอร์ตเพื่อหลีกเลี่ยงความล่าช้าในการใช้กับเมทริกซ์ข้อมูลขนาดใหญ่มาก


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

Quicksort ไม่จำเป็นต้องเรียกซ้ำ ในความเป็นจริงเป็นไปได้เสมอที่จะเปลี่ยนอัลกอริทึมแบบเรียกซ้ำให้เป็นแบบไม่วนซ้ำ แน่นอนว่าการนำเสนอแบบคลาสสิกของ QS ล้วนเกี่ยวข้องกับการเรียกซ้ำ แต่ในทางปฏิบัติไม่จำเป็นต้องเป็นเช่นนั้น
gniourf_gniourf

0

พูดง่ายๆ >> HeapSort ได้รับประกัน ~ กรณีที่เลวร้ายที่สุด ~ เวลาทำงานของ "O (n log n)" ซึ่งตรงข้ามกับเวลาทำงาน ~ เฉลี่ย ~ ของ QuickSort ของ "O (n log n)" โดยทั่วไปแล้ว QuickSort จะใช้ในทางปฏิบัติเนื่องจากโดยทั่วไปแล้วจะเร็วกว่า แต่ HeapSort ใช้สำหรับการจัดเรียงภายนอกเมื่อคุณต้องการจัดเรียงไฟล์ขนาดใหญ่ที่ไม่พอดีกับหน่วยความจำของคอมพิวเตอร์ของคุณ


-1

หากต้องการตอบคำถามเดิมและตอบความคิดเห็นอื่น ๆ ที่นี่:

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

TL; DR: Quick เป็นการจัดเรียงตามวัตถุประสงค์ทั่วไปที่ดีที่สุด (เร็วพอสมควรเสถียรและส่วนใหญ่อยู่ในตำแหน่ง) โดยส่วนตัวแล้วฉันชอบการเรียงลำดับฮีปแม้ว่าฉันจะต้องการการจัดเรียงที่มั่นคง

การเลือก - N ^ 2 - มันดีจริงๆสำหรับองค์ประกอบน้อยกว่า 20 ชิ้นหรือมากกว่านั้นก็ทำได้ดีกว่า เว้นแต่ข้อมูลของคุณจะได้รับการจัดเรียงเรียบร้อยแล้วหรือเกือบจะมาก N ^ 2 ช้ามากเร็วมาก

จากประสบการณ์ของฉันอย่างรวดเร็วไม่ใช่ว่าจะรวดเร็วตลอดเวลา โบนัสสำหรับการใช้การจัดเรียงอย่างรวดเร็วเป็นการจัดเรียงทั่วไปแม้ว่าจะเร็วพอสมควรและมีความเสถียร นอกจากนี้ยังเป็นอัลกอริทึมที่ใช้งานได้ แต่เนื่องจากโดยทั่วไปมีการใช้งานซ้ำจึงต้องใช้พื้นที่สแต็กเพิ่มเติม นอกจากนี้ยังอยู่ระหว่าง O (n log n) และ O (n ^ 2) การกำหนดเวลาในบางประเภทดูเหมือนจะยืนยันสิ่งนี้โดยเฉพาะอย่างยิ่งเมื่อค่าอยู่ในช่วงที่ จำกัด วิธีนี้เร็วกว่าการจัดเรียงการเลือก 10,000,000 รายการ แต่ช้ากว่าการผสานหรือฮีป

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

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


การเรียงลำดับด่วนไม่ใช่การจัดเรียงที่คงที่ นอกเหนือจากนั้นคำถามในลักษณะนี้กระตุ้นให้เกิดการตอบสนองตามความคิดเห็นและอาจนำไปสู่การแก้ไขสงครามและข้อโต้แย้ง คำถามที่เรียกร้องให้มีการตอบสนองตามความคิดเห็นนั้นไม่ได้รับการสนับสนุนอย่างชัดเจนจากแนวทาง SO ผู้ตอบควรหลีกเลี่ยงสิ่งล่อใจที่จะตอบพวกเขาแม้ว่าพวกเขาจะมีประสบการณ์และสติปัญญาที่สำคัญก็ตาม ไม่ว่าจะตั้งค่าสถานะเพื่อปิดหรือรอให้คนที่มีชื่อเสียงมากพอที่จะตั้งค่าสถานะและปิด ความคิดเห็นนี้ไม่ได้สะท้อนถึงความรู้ของคุณหรือความถูกต้องของคำตอบของคุณ
MikeC
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.