มันมีเสถียรภาพและมีความซับซ้อนเวลาของ O (n) มันควรจะเร็วกว่าอัลกอริทึมอย่าง Quicksort และ Mergesort แต่ฉันแทบจะไม่เคยเห็นมันมาใช้เลย
มันมีเสถียรภาพและมีความซับซ้อนเวลาของ O (n) มันควรจะเร็วกว่าอัลกอริทึมอย่าง Quicksort และ Mergesort แต่ฉันแทบจะไม่เคยเห็นมันมาใช้เลย
คำตอบ:
ซึ่งแตกต่างจากการจัดเรียง Radix, quicksort เป็นสากลในขณะที่การเรียง radix จะเป็นประโยชน์สำหรับคีย์จำนวนเต็มความยาวคงที่เท่านั้น
คุณต้องเข้าใจด้วยว่า O (f (n)) หมายถึง K * f (n) โดยที่ K นั้นมีค่าคงที่ตามอำเภอใจ สำหรับการเรียงเรเดียนซ์ K นี้เกิดขึ้นค่อนข้างใหญ่ (อย่างน้อยเรียงลำดับจำนวนบิตในจำนวนเต็มเรียง) ในทางตรงกันข้าม quicksort มี K ต่ำที่สุดแห่งหนึ่งในบรรดาอัลกอริทึมการเรียงลำดับและความซับซ้อนเฉลี่ยของ n * log (n) ดังนั้นใน quicksort สถานการณ์ในชีวิตจริงมักจะเร็วกว่าการเรียงลำดับ radix
อัลกอริทึมการเรียงลำดับส่วนใหญ่มีวัตถุประสงค์ทั่วไป รับฟังก์ชั่นการเปรียบเทียบพวกมันทำงานอะไรก็ได้และอัลกอริธึมอย่าง Quicksort และ Heapsort จะเรียงลำดับด้วยหน่วยความจำเสริม O (1)
การเรียงลำดับ Radix มีความเชี่ยวชาญมากขึ้น คุณต้องใช้รหัสเฉพาะที่อยู่ในคำสั่งทำพจนานุกรม คุณต้องการหนึ่ง bucket สำหรับแต่ละสัญลักษณ์ที่เป็นไปได้ในคีย์และที่เก็บต้องเก็บเร็กคอร์ดจำนวนมาก (อีกทางหนึ่งคุณต้องมีถังเก็บขนาดใหญ่จำนวนหนึ่งที่จะเก็บค่าคีย์ทุกค่าที่เป็นไปได้) คุณอาจต้องใช้หน่วยความจำมากขึ้นในการจัดเรียง Radix และคุณจะใช้มันแบบสุ่ม สิ่งนี้ไม่เหมาะสำหรับคอมพิวเตอร์ที่ทันสมัยเนื่องจากคุณมีแนวโน้มที่จะได้รับข้อบกพร่องของหน้าเช่น Quicksort จะทำให้แคชหายไป
สุดท้ายคนทั่วไปไม่ได้เขียนอัลกอริทึมการเรียงลำดับของตัวเองอีกต่อไป ภาษาส่วนใหญ่มีสิ่งอำนวยความสะดวกในการจัดเรียงห้องสมุดและสิ่งที่ต้องทำคือใช้งานได้ตามปกติ เนื่องจากการเรียงลำดับของ Radix ไม่สามารถใช้ได้ในระดับสากลโดยทั่วไปจะต้องได้รับการปรับให้เหมาะกับการใช้งานจริงและใช้หน่วยความจำเพิ่มเติมจำนวนมากจึงเป็นการยากที่จะนำไปไว้ในฟังก์ชันไลบรารีหรือแม่แบบ
O(n^2)
หน่วยความจำในกรณีที่แย่ที่สุดเนื่องจากการn
เรียกซ้ำบนพาร์ติชั่นซ้ายและขวา หากการใช้งานใช้การปรับให้เหมาะสมแบบเรียกซ้ำหางซึ่งสามารถลดลงเหลือเพียงO(n)
เนื่องจากการเรียกไปยังพาร์ติชันที่เหมาะสมไม่จำเป็นต้องใช้พื้นที่เพิ่มเติม ( en.wikipedia.org/wiki/Quicksort#Space_complexity )
S(n) \in O(n)
พื้นที่สำหรับการเรียงด้วย radix เช่นเดียวกับ heap หรือการเรียงแบบด่วน
n^2
เรื่อง quicksort อีกต่อไป แต่O(log n)
...
มันค่อนข้างหายากที่คีย์ที่คุณเรียงลำดับตามจริงแล้วเป็นจำนวนเต็มในช่วงที่รู้จักกันกระจัดกระจาย โดยปกติแล้วคุณจะมีเขตข้อมูลตัวอักษรซึ่งดูเหมือนว่าพวกเขาจะสนับสนุนการเรียงลำดับแบบไม่เปรียบเทียบ แต่เนื่องจากสตริงในโลกแห่งความจริงไม่ได้กระจายไปทั่วตัวอักษรอย่างสม่ำเสมอจึงไม่ได้ผลดีเท่าที่ควรในทางทฤษฎี
ในบางครั้งเกณฑ์ถูกกำหนดให้ดำเนินการเท่านั้น (จากสองเรคคอร์ดคุณสามารถตัดสินใจว่าจะมาก่อน แต่คุณไม่สามารถประเมินได้ว่าขนาดของเรคคอร์ดแยกต่างหาก 'ไกลแค่ไหน') ดังนั้นวิธีการนี้มักใช้ไม่ได้ใช้น้อยกว่าที่คุณอาจเชื่อหรือไม่เร็วกว่า O (n * log (n))
ฉันใช้มันตลอดเวลาจริง ๆ แล้วเป็นมากกว่าการเปรียบเทียบตามประเภท แต่ฉันยอมรับว่าลูกบอลประหลาดที่ทำงานกับตัวเลขได้มากกว่าสิ่งอื่นใด (ฉันแทบจะไม่เคยทำงานกับสตริงเลยและพวกมันมักจะฝึกงานถ้าเป็นเช่นนั้น การเรียงลำดับจะมีประโยชน์อีกครั้งในการกรองรายการที่ซ้ำกันและคำนวณจุดตัดที่ตั้งไว้จริง ๆ แล้วฉันไม่เคยทำการเปรียบเทียบศัพท์
ตัวอย่างพื้นฐานคือการเรียงคะแนน radix ตามมิติที่กำหนดซึ่งเป็นส่วนหนึ่งของการค้นหาหรือการแบ่งค่ามัธยฐานหรือวิธีที่รวดเร็วในการตรวจสอบจุดพ้อง, การเรียงลำดับความลึกหรือการเรียงลำดับดัชนีที่ใช้ในหลายลูปเพื่อให้เข้าถึงแคชได้ง่ายขึ้น รูปแบบ (ไม่ย้อนกลับไปในหน่วยความจำเพียงเพื่อกลับไปอีกครั้งและโหลดหน่วยความจำเดียวกันลงในสายแคช) มีแอพพลิเคชั่นที่มีความกว้างอย่างน้อยในโดเมนของฉัน (คอมพิวเตอร์กราฟิก) เพียงเพื่อเรียงลำดับในคีย์ตัวเลขขนาด 32 บิตและ 64 บิต
สิ่งหนึ่งที่ฉันต้องการขว้างและพูดก็คือการเรียงตัวแบบ Radix สามารถทำงานกับจำนวนจุดลอยตัวและเนกาทีฟแม้ว่ามันจะยากในการเขียนรุ่น FP ที่พกพาได้มากที่สุด ในขณะที่มันเป็น O (n * K) K ก็ต้องเป็นจำนวนไบต์ของขนาดคีย์ (เช่น: จำนวนเต็ม 32- ล้านล้านบิตโดยทั่วไปจะผ่าน 4 ไบต์ขนาดถ้ามี 2 ^ 8 รายการในถัง ) รูปแบบการเข้าถึงหน่วยความจำยังมีแนวโน้มที่จะเป็นมิตรกับแคชมากกว่า quicksorts ถึงแม้ว่ามันจะต้องการอาเรย์แบบขนานและอาเรย์การฝากข้อมูลขนาดเล็กโดยทั่วไป QS อาจทำ 50 ล้าน swaps เพื่อจัดเรียงอาร์เรย์ของจำนวนเต็มหนึ่งล้านด้วยรูปแบบการเข้าถึงแบบสุ่มเป็นระยะ การเรียงลำดับ radix สามารถทำได้ในแบบเส้นตรง 4 แบบซึ่งเป็นมิตรกับแคชมากกว่าข้อมูล
อย่างไรก็ตามการขาดความตระหนักในความสามารถในการทำเช่นนี้กับ K ขนาดเล็กในจำนวนลบพร้อมกับ floating-point อาจมีส่วนสำคัญอย่างมากต่อการขาดความนิยมของ Radix
สำหรับความคิดเห็นของฉันเกี่ยวกับสาเหตุที่ผู้คนไม่ได้ใช้บ่อยครั้งอาจต้องทำกับโดเมนจำนวนมากโดยทั่วไปไม่จำเป็นต้องเรียงหมายเลขหรือใช้เป็นคีย์ค้นหา อย่างไรก็ตามจากประสบการณ์ส่วนตัวของฉันอดีตเพื่อนร่วมงานจำนวนมากของฉันก็ไม่ได้ใช้มันในกรณีที่มันเหมาะสมอย่างสมบูรณ์และบางส่วนเพราะพวกเขาไม่ทราบว่าสามารถทำงานกับ FP และฟิล์มเนกาทีฟได้ ดังนั้นนอกเหนือจากการทำงานกับตัวเลขเท่านั้นมันมักจะคิดว่าจะใช้งานได้โดยทั่วไปน้อยกว่าที่เป็นจริง ฉันจะไม่ใช้มันมากนักถ้าฉันคิดว่ามันใช้ไม่ได้กับจำนวนจุดลอยตัวและจำนวนเต็มลบ
มาตรฐานบางอย่าง:
Sorting 10000000 elements 3 times...
mt_sort_int: {0.135 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]
mt_radix_sort: {0.228 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]
std::sort: {1.697 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]
qsort: {2.610 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]
และนั่นก็เป็นเพียงการดำเนินการที่ไร้เดียงสาของฉัน ( mt_sort_int
เป็นการเรียงลำดับแบบ Radix แต่ด้วยรหัสสาขาที่เร็วกว่าเนื่องจากสามารถถือว่าคีย์เป็นจำนวนเต็มได้) ลองนึกภาพว่าการดำเนินการตามมาตรฐานแบบเขียนโดยผู้เชี่ยวชาญอาจรวดเร็วเพียงใด
กรณีเดียวที่ฉันพบว่าการเรียงเรดิสกับค่าโดยสารแย่กว่าการเปรียบเทียบอย่างรวดเร็วของ C ++ std::sort
สำหรับองค์ประกอบจำนวนน้อยจริง ๆ เช่น 32 ซึ่ง ณ จุดนี้ฉันเชื่อว่าstd::sort
เริ่มใช้การเรียงลำดับที่เหมาะสมกว่าสำหรับองค์ประกอบที่เล็กที่สุด ประเภทการแทรก std::sort
แต่ที่จุดที่ฉันใช้การดำเนินการเพียง
อีกเหตุผลหนึ่งที่: การเรียงลำดับวันเหล่านี้มักจะถูกนำไปใช้กับรูทีนการเรียงที่ผู้ใช้ระบุซึ่งแนบมากับตรรกะการเรียงลำดับที่ให้มาด้วยคอมไพเลอร์ ด้วยการเรียงลำดับ radix สิ่งนี้จะมีความซับซ้อนมากขึ้นและแย่ลงไปอีกเมื่อรูทีนการเรียงลำดับทำหน้าที่กับหลายคีย์ของความยาวตัวแปร (พูดชื่อและวันเกิด)
ในโลกแห่งความเป็นจริงฉันได้ทำการจัดเรียง Radix หนึ่งครั้ง. นี่คือในอดีตเมื่อหน่วยความจำถูก จำกัด ฉันไม่สามารถนำข้อมูลทั้งหมดของฉันไปยังหน่วยความจำในครั้งเดียว นั่นหมายความว่าจำนวนการเข้าถึงข้อมูลมีความสำคัญมากกว่า O (n) และ O (n log n) ฉันทำหนึ่งผ่านข้อมูลที่จัดสรรแต่ละระเบียนไปยังถังขยะ (โดยรายการที่บันทึกอยู่ในถังขยะที่ไม่ได้ย้ายอะไรจริง ๆ ) สำหรับถังขยะที่ไม่ว่างแต่ละ (คีย์เรียงของฉันคือข้อความจะมีจำนวนมาก ช่องว่างเปล่า) ฉันตรวจสอบว่าฉันสามารถนำข้อมูลเข้าสู่หน่วยความจำจริงหรือไม่ถ้าใช่ให้นำเข้าและใช้ quicksort หากไม่มีให้สร้างไฟล์ชั่วคราวที่มีเฉพาะรายการในถังขยะและเรียกรูทีนซ้ำ ๆ (ในทางปฏิบัติถังขยะสองสามอันจะล้น) สิ่งนี้ทำให้เกิดการอ่านที่สมบูรณ์สองครั้งและการเขียนที่หนึ่งไปยังที่เก็บข้อมูลเครือข่ายสมบูรณ์
ทุกวันนี้ปัญหาเรื่องข้อมูลขนาดใหญ่นั้นยากที่จะหายากฉันอาจจะไม่เขียนอะไรแบบนั้นอีกเลย (ถ้าฉันต้องเผชิญกับข้อมูลเดียวกันวันนี้ฉันจะระบุระบบปฏิบัติการ 64 บิตเพิ่ม RAM ถ้าคุณได้รับการตีอย่างแรงในตัวแก้ไขนั้น)
หากพารามิเตอร์ทั้งหมดของคุณเป็นจำนวนเต็มทั้งหมดและหากคุณมีพารามิเตอร์อินพุตมากกว่า 1024 พารามิเตอร์การเรียงลำดับแบบเลขฐานจะเร็วกว่าเสมอ
ทำไม?
Complexity of radix sort = max number of digits x number of input parameters.
Complexity of quick sort = log(number of input parameters) x number of input parameters
ดังนั้นการเรียงลำดับของ Radix จะเร็วขึ้นเมื่อ
log(n)> max num of digits
จำนวนเต็มสูงสุดใน Java คือ 2147483647 ซึ่งมีความยาว 10 หลัก
ดังนั้นการเรียงลำดับของ Radix จะเร็วกว่าเสมอเมื่อ
log(n)> 10
ดังนั้นการเรียงลำดับของ Radix จะเร็วขึ้นเสมอเมื่อ
n>1024