Ada berbagai macam pendekatan yang layak. Yang paling cocok tergantung pada
- apa yang Anda coba tunjukkan,
- berapa banyak detail yang Anda inginkan atau butuhkan.
Jika algoritme adalah yang dikenal luas yang Anda gunakan sebagai subrutin, Anda sering tetap berada pada level yang lebih tinggi. Jika algoritme adalah objek utama yang sedang diselidiki, Anda mungkin ingin lebih detail. Hal yang sama dapat dikatakan untuk analisis: jika Anda memerlukan batas atas runtime yang kasar, Anda melanjutkan secara berbeda dari saat Anda menginginkan jumlah pernyataan yang tepat.
Saya akan memberi Anda tiga contoh untuk algoritma Mergesort yang terkenal yang mudah-mudahan menggambarkan ini.
Level tinggi
Algoritma Mergesort mengambil daftar, membaginya dalam dua (sekitar) bagian yang sama-sama panjang, berulang pada daftar parsial tersebut dan menggabungkan hasil (diurutkan) sehingga hasil akhirnya diurutkan. Pada daftar tunggal atau kosong, ini mengembalikan input.
Algoritma ini jelas merupakan algoritma pengurutan yang benar. Memisahkan daftar dan menggabungkannya masing-masing dapat diimplementasikan dalam waktu , yang memberi kita perulangan untuk runtime kasus terburuk T ( n ) = 2 T ( nΘ(n). Dengan teorema Master, ini dievaluasi menjadiT(n)∈Θ(nlogn).T(n)=2T(n2)+Θ(n)T(n)∈Θ(nlogn)
Tingkat Sedang
Algoritma Mergesort diberikan oleh pseudo-code berikut:
procedure mergesort(l : List) {
if ( l.length < 2 ) {
return l
}
left = mergesort(l.take(l.length / 2)
right = mergesort(l.drop(l.length / 2)
result = []
while ( left.length > 0 || right.length > 0 ) {
if ( right.length == 0 || (left.length > 0 && left.head <= right.head) ) {
result = left.head :: result
left = left.tail
}
else {
result = right.head :: result
right = right.tail
}
}
return result.reverse
}
Kami membuktikan kebenaran dengan induksi. Untuk daftar panjang nol atau satu, algoritme itu sepele benar. Sebagai hipotesis induksi, anggap mergesort
berkinerja benar pada daftar panjang paling banyak untuk beberapa arbitrer, tetapi tetap alami n > 1 . Sekarang mari L menjadi daftar panjang n + 1 . Dengan hipotesis induksi, dan tahan (tidak menurun) versi yang diurutkan dari resp pertama. paruh kedua L setelah panggilan rekursif. Oleh karena itu, loop memilih di setiap iterasi elemen terkecil yang belum diselidiki dan menambahkannya ; dengan demikian adalah daftar yang tidak diurutkan yang mengandung semua elemen darinn>1Ln+1left
right
Lwhile
result
result
left
dan right
. Kebalikannya adalah versi yang tidak diurutkan secara bertahap , yang merupakan hasil - dan yang diinginkan - yang dikembalikan.L
Sedangkan untuk runtime, mari kita hitung perbandingan elemen dan operasi daftar (yang mendominasi runtime tanpa gejala). Daftar panjangnya kurang dari dua tidak menyebabkan keduanya. Untuk daftar panjang , kami memiliki operasi yang disebabkan oleh menyiapkan input untuk panggilan rekursif, yang dari panggilan rekursif sendiri ditambah loop dan satu . Kedua parameter rekursif dapat dihitung dengan paling banyak n operasi daftar masing-masing. The loop dieksekusi persis n kali dan setiap iterasi penyebab paling banyak satu perbandingan elemen dan tepat dua operasi daftar. Final dapat diimplementasikan menggunakan 2 nn>1while
reverse
nwhile
nreverse
2noperasi daftar - setiap elemen dihapus dari input dan dimasukkan ke dalam daftar output. Oleh karena itu, hitungan operasi memenuhi pengulangan berikut:
T(0)=T(1)T(n)=0≤T(⌈n2⌉)+T(⌊n2⌋)+7n
Karena jelas tidak menurun, cukup untuk mempertimbangkan n = 2 k untuk pertumbuhan asimptotik. Dalam hal ini , perulangan disederhanakan menjadiTn=2k
T(0)=T(1)T(n)=0≤2T(n2)+7n
Dengan teorema Master, kita mendapatkan yang meluas ke runtime .T∈Θ(nlogn)mergesort
Tingkat sangat rendah
Pertimbangkan penerapan Mergesort di Isabelle / HOL ini :
types dataset = "nat * string"
fun leq :: "dataset \<Rightarrow> dataset \<Rightarrow> bool" where
"leq (kx::nat, dx) (ky, dy) = (kx \<le> ky)"
fun merge :: "dataset list \<Rightarrow> dataset list \<Rightarrow> dataset list" where
"merge [] b = b" |
"merge a [] = a" |
"merge (a # as) (b # bs) = (if leq a b then a # merge as (b # bs) else b # merge (a # as) bs)"
function (sequential) msort :: "dataset list \<Rightarrow> dataset list" where
"msort [] = []" |
"msort [x] = [x]" |
"msort l = (let mid = length l div 2 in merge (msort (take mid l)) (msort (drop mid l)))"
by pat_completeness auto
termination
apply (relation "measure length")
by simp+
Ini sudah termasuk bukti-bukti yang jelas dan terminasi. Temukan (hampir) bukti kebenaran lengkap di sini .
Untuk "runtime", yaitu jumlah perbandingan, perulangan yang serupa dengan yang ada di bagian sebelumnya dapat diatur. Alih-alih menggunakan teorema Master dan melupakan konstanta, Anda juga dapat menganalisisnya untuk mendapatkan perkiraan yang secara asimtotik sama dengan kuantitas sebenarnya. Anda dapat menemukan analisis lengkap dalam [1]; di sini adalah garis besar kasar (tidak sesuai dengan kode Isabelle / HOL):
Seperti di atas, pengulangan untuk jumlah perbandingan adalah
f0=f1fn=0=f⌈n2⌉+f⌊n2⌋+en
di mana adalah jumlah perbandingan yang diperlukan untuk menggabungkan hasil parsial². Untuk menyingkirkan lantai dan langit-langit, kami melakukan perbedaan kasus tentang apakah n genap:enn
{f2mf2m+1=2fm+e2m=fm+fm+1+e2m+1
Menggunakan perbedaan maju / mundur bersarang dari dan e n kita mendapatkan itufnen
.∑k=1n−1(n−k)⋅Δ∇fk=fn−nf1
Jumlahnya cocok dengan sisi kanan rumus Perron . Kami mendefinisikan Dirichlet pembangkit seri dari sebagaiΔ∇fk
W(s)=∑k≥1Δ∇fkk−s=11−2−s⋅∑k≥1Δ∇ekks=: ⊟(s)
yang bersama-sama dengan formula Perron membawa kita ke
fn= nf1+n2πsaya∫3 - i ∞3+i∞⊟(s)ns(1−2−s)s(s+1)ds
⊟(s)
fn∼n⋅log2( n ) + n ⋅ A(log2( N ) ) + 1
SEBUAH[ - 1 , - 0,9 ]
- Transformasi Mellin dan asimptotik: rekurensi mergesort oleh Flajolet dan Golin (1992)
- en= ⌊ n2⌋
en= n - 1
en= n - ⌊ n2⌋⌈ n2⌉ +1- ⌈ n2⌉⌊ n2⌋ +1