Apa karakteristik dari algoritma kompleksitas waktu ?

19

Terkadang mudah untuk mengidentifikasi kompleksitas waktu dari sebuah algoritma yang saya teliti dengan cermat. Algoritma dengan dua loop bersarang jelas . Algoritma yang mengeksplorasi semua kemungkinan kombinasi dari N kelompok dari dua nilai yang jelas 2 ^ N .N 2 N 2 NNN2N2N

Namun saya tidak tahu bagaimana "menemukan" suatu algoritma dengan kompleksitas Θ(NlogN) . Implementasi mergesort rekursif, misalnya, adalah satu. Apa karakteristik umum dari mergesort atau algoritma Θ(NlogN) yang akan memberi saya petunjuk jika saya menganalisisnya?

Saya yakin ada lebih dari satu cara algoritma dapat dari kompleksitas Θ(NlogN) , jadi setiap dan semua jawaban dihargai. BTW Saya mencari karakteristik dan tip umum, bukan bukti yang kuat.

Barry Fruitman
sumber
6
O(logn) berarti pohon.
Pratik Deoghare
2
@PratikDeoghare: Tidak harus.
Raphael
3
@ Raphael yang saya maksud sebagian besar! :)
Pratik Deoghare

Jawaban:

17

Pola dasar Anda adalah algoritma divide-and-menaklukkan , yang membagi (dan menggabungkan kembali) pekerjaan dalam waktu linier dan berulang pada potongan-potongan. Menggabungkan semacam bekerja seperti itu: menghabiskan waktu membagi input menjadi dua bagian yang kira-kira sama, mengurutkan masing-masing bagian secara rekursif, dan menghabiskan waktu menggabungkan dua bagian yang diurutkan.O ( n ) Θ ( n )Θ(nlogn)O(n)Θ(n)

Secara intuitif, melanjutkan ide membagi-dan-taklukkan, setiap tahap pembagian memakan waktu linier secara total, karena peningkatan jumlah keping untuk membagi sama persis dengan penurunan ukuran keping, karena waktu yang diambil oleh pembagian adalah linier. Total waktu berjalan adalah produk dari total biaya tahap divisi dikalikan dengan jumlah tahap divisi. Karena ukuran potongan dibelah dua pada setiap waktu, ada , sehingga total waktu berjalan adalah . (Hingga konstanta multiplikasi, dasar logaritma tidak relevan.)n log ( n )log2(n)nlog(n)

Menempatkannya dalam persamaan (), salah satu cara untuk memperkirakan waktu berjalan dari algoritma semacam itu adalah dengan menyatakannya secara rekursif: . Jelas bahwa algoritme ini membutuhkan lebih dari waktu linier, dan kita dapat melihat lebih banyak dengan membagi dengan : Ketika menggandakan, meningkat dengan jumlah yang konstan: meningkat secara logaritma, atau dengan kata lain, .T ( n ) = 2 T ( n / 2 ) + Θ ( n ) n T ( n )T(n)T(n)=2T(n/2)+Θ(n)nnT(n)/nT(n)/nT(n)=Θ(nlogn)

T(n)n=T(n/2)n/2+Θ(1)
nT(n)/nT(n)/nT(n)=Θ(nlogn)

Ini adalah contoh dari pola yang lebih umum: teorema master . Untuk algoritma rekursif yang membagi input dari ukuran menjadi lembar ukuran dan memakan waktu untuk melakukan pembagian dan rekombinasi, waktu berjalan memuaskan . Ini mengarah ke bentuk tertutup yang tergantung pada nilai-nilai dan dan bentuk . Jika dan , teorema master menyatakan bahwa .nan/bf(n)T(n)=aT(n/b)+f(n)abfa=bf(n)=Θ(n)T(n)=Θ(nlogn)

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1
Untuk meringkas: algoritma yang menghilangkan fraksi konstan dari ruang pencarian pada suatu waktu akan menunjukkan istilah logaritmik. Faktor-faktor lain tergantung pada berapa lama waktu yang dibutuhkan untuk melakukan pekerjaan itu.
Raphael
1
contoh: quicksort case rata-rataO(nlogn)
vzn
11

Dua kategori algoritma lainnya yang memerlukan waktu :Θ(nlogn)

Algoritma tempat setiap item diproses secara bergantian, dan dibutuhkan waktu logaritmik untuk memproses setiap item (mis. HeapSort atau banyak algoritma geometri komputasi bidang sapuan bidang).

Algoritma di mana waktu berjalan didominasi oleh langkah pemilahan pra-pemrosesan. (Misalnya, dalam algoritma Kruskal untuk pohon spanning minimum, kami dapat mengurutkan tepi berdasarkan berat sebagai langkah pertama).

Joe
sumber
Terpilih untuk paragraf pertama. Yang kedua tampaknya berlebihan, karena algoritma penyortiran linearithmic yang kita tahu adalah membagi & menaklukkan atau heapsort. Contoh untuk kategori pertama adalah pencarian objek dalam pohon pencarian biner (atau array yang diurutkan) dengan ukuran n ; pada tingkat yang lebih abstrak, itu juga bisa dilihat sebagai membagi & menaklukkan. nn
Raphael
@Raphael Saya tahu penyortiran itu berlebihan dengan kategori waktu berjalan yang sudah diberikan. Intinya adalah bahwa penyortiran kadang-kadang "bottleneck" dan algoritma di mana pada awalnya mem-blush pertanyaannya bukan tentang penyortiran mungkin masih memiliki run-time karena penyortiran diperlukan.
Joe
9

Kategori lain: Algoritma di mana output memiliki ukuran , dan karenanya Θ ( n log n ) waktu berjalan adalah linier dalam ukuran output .Θ(nlogn)Θ(nlogn)

Meskipun detail dari algoritma tersebut sering menggunakan teknik divide-and-menaklukkan, mereka tidak harus begitu. Run-time secara fundamental berasal dari pertanyaan yang diajukan, dan jadi saya pikir perlu disebutkan secara terpisah.

Ini muncul dalam struktur data yang didasarkan pada pohon pencarian biner augmented, di mana setiap node menyimpan struktur data ukuran linier untuk mencari daun di subtree node itu. Struktur data seperti itu sering muncul dalam pencarian rentang geometris, dan seringkali didasarkan pada skema dekomposisi . Lihat Survei Agarwal .

Untuk contoh konkret, pertimbangkan pohon rentang , dibangun untuk menjawab pertanyaan rentang orthogonal dua dimensi. Meskipun ruang itu kemudian dikurangi menggunakan beberapa teknik kompresi untuk mengemas beberapa objek menjadi satu kata, versi buku teks (dan paling intuitif) dari struktur data membutuhkan ruang (setiap daun disimpan dalam struktur tambahan di setiap simpul di jalur dari daun ke root, atau di O ( log n ) tempat), dan algoritma konstruksi membutuhkan waktu linier dalam kebutuhan ruang .O(nlogn)O(logn)

Joe
sumber
Sebuah contoh akan menemukan n-th prima menggunakan saringan, karena Anda akan membutuhkan saringan ukuran . θ(nlogn)
gnasher729
6

Kompleksitas muncul dari algoritme divide and conquer yang membagi input mereka ke dalam k k dengan ukuran yang kira-kira sama dalam waktu O ( n ) , beroperasi pada bagian-bagian ini secara rekursif, dan kemudian menggabungkannya dalam waktu O ( n ) . Jika Anda hanya beroperasi pada beberapa bagian, waktu berjalan turun menjadi O ( n ) .O(nlogn)kO(n)O(n)O(n)

Yuval Filmus
sumber
5

Itu biasanya adalah algoritme dari varietas "divide and conquer", di mana biaya untuk membagi dan menggabungkan sub-solusi tidak "terlalu besar". Lihatlah FAQ ini untuk melihat jenis perulangan apa yang memunculkan perilaku ini.

vonbrand
sumber
3

Biasanya, algoritma Divide-and-menaklukkan akan menghasilkan kompleksitas O (N log N).

Brent Hronik
sumber
-1

Contoh umum dari loop ( bukan algoritma per se) yang berjalan di adalah sebagai berikut:HAI(ncatatann)

for (i = 0; i < constant; i++){
    for(j = 0; j < n; j++){
        // Do some O(1) stuff on the input
    }
}

// Alternative Variant:
for (i = 0; i < constant; i++){
    for(j = n; j < constant; j++){
        // Do some O(1) stuff on the input
    }
}

(perhatikan bahwa loop bersarang ini bukan . Juga perhatikan bahwa loop tidak diarsipkan dan tidak pula rekursif.)O(n2)

Saya tidak bisa memberikan contoh konkret dari algoritma yang menggunakan loop ini, tetapi sering muncul ketika coding algoritma kustom.

Nicolas Miari
sumber
Ya, keduanya tetapi untuk alasan sepele bahwa ikatan tidak kencang. Yang pertama adalah Θ ( n ) dan yang kedua adalah Θ ( 1 ) (atau Θ ( | n | ) jika n bisa negatif). HAI(ncatatann)Θ(n)Θ(1)Θ(|n|)n
David Richerby
Saya pikir itu berguna untuk disebutkan, karena memang muncul dalam praktek tetapi setiap pencarian untuk " " sebagian besar "membagi dan menaklukkan" contoh-contoh seperti misalnya semacam penggabungan. O(nlogn)
Nicolas Miari
Selain itu, pertanyaan awal tidak menanyakan theta besar.
Nicolas Miari
1
O(nlogn)O(22n)O(almost anything else)Θ(nlogn)O(nlogn)
David Richerby
O(nlogn)O(nlogn)O(nlogn)O(nlogn)
Nicolas Miari