Mengapa metode Java's Arrays.sort menggunakan dua algoritma pengurutan yang berbeda untuk jenis yang berbeda?

121

Arrays.sortMetode Java 6 menggunakan Quicksort untuk array primitif dan merge sort untuk array objek. Saya percaya bahwa sebagian besar waktu Quicksort lebih cepat daripada jenis gabungan dan menghabiskan lebih sedikit memori. Eksperimen saya mendukung itu, meskipun kedua algoritma tersebut adalah O (n log (n)). Jadi mengapa algoritma yang berbeda digunakan untuk jenis yang berbeda?

zjffdu.dll
sumber
14
Kasus terburuk Quicksort adalah N ^ 2 bukan NlogN.
codaddict
Tunggu, apa yang terjadi jika Anda memiliki array Integers atau sesuatu?
Tikhon Jelvis
1
Bukankah ini dijelaskan dalam sumber yang Anda baca?
Humphrey Bogart
5
Informasi ini tidak lagi terkini. Mulai Java SE 7, MergeSort telah diganti dengan TimSort dan QuickSort telah diganti dengan Dual-Pivot QuickSort . Lihat jawaban saya di bawah untuk link ke dokumen Java API.
Will Byrne

Jawaban:

200

Alasan yang paling mungkin: quicksort tidak stabil , yaitu entri yang sama dapat mengubah posisi relatifnya selama pengurutan; antara lain, ini berarti bahwa jika Anda mengurutkan array yang sudah diurutkan, itu mungkin tidak tetap tidak berubah.

Karena tipe primitif tidak memiliki identitas (tidak ada cara untuk membedakan dua int dengan nilai yang sama), ini tidak menjadi masalah bagi mereka. Tetapi untuk tipe referensi, ini dapat menyebabkan masalah untuk beberapa aplikasi. Oleh karena itu, jenis gabungan stabil digunakan untuk itu.

OTOH, alasan untuk tidak menggunakan penyortiran stabil (dijamin n * log (n)) untuk tipe primitif mungkin karena hal itu memerlukan pembuatan tiruan dari array. Untuk tipe referensi, di mana objek yang dirujuk biasanya mengambil lebih banyak memori daripada array referensi, ini biasanya tidak menjadi masalah. Tetapi untuk tipe primitif, mengkloning array secara langsung akan menggandakan penggunaan memori.

Michael Borgwardt
sumber
1
Alasan lain untuk menggunakan quicksort adalah karena pada kasus rata-rata, quicksort lebih cepat daripada mergesort. Meskipun quicksort melakukan lebih banyak perbandingan daripada mergesort, quicksort melakukan lebih sedikit akses array. Quicksort 3 arah juga dapat mencapai waktu linier jika input berisi banyak entri duplikat yang tidak biasa dalam aplikasi praktis (Dugaan saya adalah pengurutan cepat pivot ganda juga memiliki properti ini).
Jingguo Yao
Untuk tipe primitif itu tidak mengkloning array, itu dapat mengurutkannya di tempat, jadi saya pikir satu-satunya alasan adalah kontrak stabilitas, pada dasarnya ...
rogerdpack
27

Menurut dokumen Java 7 API yang dikutip dalam jawaban ini , Arrays#Sort()untuk array objek sekarang menggunakan TimSort , yang merupakan gabungan dari MergeSort dan InsertionSort. Di sisi lain, Arrays#sort()untuk array primitif sekarang menggunakan Dual-Pivot QuickSort . Perubahan ini diimplementasikan mulai Java SE 7.

Will Byrne
sumber
2
Ini bukan jawaban, mengapa 2 algoritme berbeda dipilih.
Alexandr
12

Salah satu alasan yang dapat saya pikirkan adalah quicksort memiliki kompleksitas waktu kasus terburuk O ( n ^ 2 ) sementara mergesort mempertahankan waktu kasus terburuk O ( n log n ). Untuk array objek ada harapan yang adil bahwa akan ada beberapa referensi objek duplikat yang merupakan salah satu kasus di mana quicksort melakukan yang terburuk.

Ada perbandingan visual yang layak dari berbagai algoritme , berikan perhatian khusus pada grafik paling kanan untuk algoritme yang berbeda.

msw
sumber
2
Java quicksort adalah quicksort yang dimodifikasi yang tidak diturunkan ke O (n ^ 2), dari dokumen "Algoritme ini menawarkan performa n * log (n) pada banyak kumpulan data yang menyebabkan quicksort lain menurun ke performa kuadrat"
sbridges
7

Saya mengambil kelas Coursera tentang Algoritma dan di salah satu ceramah Profesor Bob Sedgewick menyebutkan penilaian untuk sistem Java semacam:

"Jika pemrogram menggunakan objek, mungkin ruang bukanlah pertimbangan yang sangat penting dan ruang ekstra yang digunakan oleh jenis gabungan mungkin tidak menjadi masalah. Dan jika pemrogram menggunakan tipe primitif, mungkin kinerja adalah hal terpenting sehingga mereka menggunakan penyortiran cepat. "

kukido
sumber
4
Itu bukan alasan utamanya. Tepat setelah kalimat itu ada pertanyaan, yang disematkan ke dalam video tentang "Mengapa untuk jenis referensi digunakan MergeSort?" (karena stabil). Saya pikir Sedgewick tidak menyebutkannya dalam video untuk mempertanyakannya.
Seperti
1

java.util.Arrays menggunakan quicksort untuk tipe primitif seperti int dan mergesort untuk objek yang mengimplementasikan Comparable atau menggunakan Comparator . Ide menggunakan dua metode yang berbeda adalah bahwa jika programmer menggunakan objek mungkin ruang bukan pertimbangan yang sangat penting sehingga ruang ekstra yang digunakan oleh mergesort mungkin tidak menjadi masalah dan jika programmer menggunakan tipe primitif mungkin kinerja adalah hal yang paling penting jadi gunakan yang quicksort .

Sebagai Contoh: Ini adalah contoh ketika menyortir masalah stabilitas.

masukkan deskripsi gambar di sini

Itulah mengapa pengurutan stabil masuk akal untuk tipe objek, terutama tipe objek yang bisa berubah dan tipe objek dengan lebih banyak data daripada hanya kunci sortir, dan mergesort adalah semacam itu. Tetapi untuk tipe primitif, stabilitas tidak hanya tidak relevan. Tidak ada artinya.

Sumber: INFO

Dinesh Kumar
sumber
0

Arrays.sortMetode Java menggunakan quicksort, insertion sort, dan mergesort. Bahkan ada quicksort pivot tunggal dan ganda yang diimplementasikan dalam kode OpenJDK. Algoritme pengurutan tercepat bergantung pada keadaan dan pemenangnya adalah: pengurutan penyisipan untuk larik kecil (47 saat ini dipilih), penggabungan untuk larik yang paling banyak diurutkan, dan pengurutan cepat untuk larik yang tersisa sehingga Array.sort () Java mencoba memilih algoritma terbaik untuk terapkan berdasarkan kriteria tersebut.

David McManamon
sumber