Menerjemahkan Kode ke Matematika
Diberikan (kurang lebih) semantik operasional formal Anda dapat menerjemahkan kode algoritma (pseudo-) secara harfiah ke dalam ekspresi matematika yang memberi Anda hasilnya, asalkan Anda dapat memanipulasi ekspresi menjadi bentuk yang bermanfaat. Ini bekerja dengan baik untuk ukuran biaya tambahan seperti jumlah perbandingan, swap, pernyataan, akses memori, siklus beberapa kebutuhan mesin abstrak, dan sebagainya.
Contoh: Perbandingan di Bubblesort
Pertimbangkan algoritma ini yang mengurutkan array yang diberikan A
:
bubblesort(A) do 1
n = A.length; 2
for ( i = 0 to n-2 ) do 3
for ( j = 0 to n-i-2 ) do 4
if ( A[j] > A[j+1] ) then 5
tmp = A[j]; 6
A[j] = A[j+1]; 7
A[j+1] = tmp; 8
end 9
end 10
end 11
end 12
Katakanlah kita ingin melakukan analisis algoritma penyortiran yang biasa, yaitu menghitung jumlah perbandingan elemen (baris 5). Kami segera mencatat bahwa jumlah ini tidak bergantung pada konten array A
, hanya pada panjangnya . Jadi kita bisa menerjemahkan (nested) -lompatan secara harfiah ke dalam jumlah (nested); variabel loop menjadi variabel penjumlahan dan rentang membawa. Kita mendapatkan:nfor
Ccmp(n)=∑i=0n−2∑j=0n−i−21=⋯=n(n−1)2=(n2) ,
di mana adalah biaya untuk setiap eksekusi baris 5 (yang kami hitung).1
Contoh: Swap dalam Bubblesort
Saya akan menyatakan dengan subprogram yang terdiri dari baris ke dan oleh biaya untuk menjalankan subprogram ini (satu kali).Pi,ji
j
Ci,j
Sekarang katakanlah kita ingin menghitung swap , yaitu seberapa sering dieksekusi. Ini adalah "blok dasar", yaitu subprogram yang selalu dijalankan secara atom dan memiliki biaya konstan (di sini, ). Mengontrak blok semacam itu adalah salah satu penyederhanaan yang berguna yang sering kita terapkan tanpa memikirkan atau membicarakannya.P6,81
Dengan terjemahan yang sama seperti di atas, kita sampai pada rumus berikut:
Cswaps(A)=∑i=0n−2∑j=0n−i−2C5,9(A(i,j)) .
A(i,j) menunjukkan keadaan array sebelum -terulangan ke- .(i,j)P5,9
Perhatikan bahwa saya menggunakan sebagai ganti sebagai parameter; kita akan segera melihat alasannya. Saya tidak menambahkan dan sebagai parameter karena biaya tidak tergantung pada mereka di sini (dalam model biaya seragam , yaitu); secara umum, mereka mungkin saja.AnijC5,9
Jelas, biaya tergantung pada konten (nilai-nilai dan , khususnya) jadi kami harus memperhitungkannya. Sekarang kita menghadapi tantangan: bagaimana kita "membuka" ? Nah, kita bisa membuat ketergantungan pada konten eksplisit:P5,9AA[j]
A[j+1]
C5,9A
C5,9(A(i,j))=C5(A(i,j))+{10,A(i,j)[j]>A(i,j)[j+1],else .
Untuk setiap array input yang diberikan, biaya-biaya ini didefinisikan dengan baik, tetapi kami ingin pernyataan yang lebih umum; kita perlu membuat asumsi yang lebih kuat. Mari kita selidiki tiga kasus khas.
Kasus terburuk
Hanya dari melihat jumlah dan mencatat bahwa , kita dapat menemukan batas atas sepele untuk biaya:C5,9(A(i,j))∈{0,1}
Cswaps(A)≤∑i=0n−2∑j=0n−i−21=n(n−1)2=(n2) .
Tetapi dapatkah ini terjadi , yaitu adakah untuk batas atas ini tercapai? Ternyata, ya: jika kita memasukkan array yang diurutkan terbalik dari elemen berbeda berpasangan, setiap iterasi harus melakukan swap¹. Oleh karena itu, kami telah mendapatkan jumlah swap terburuk yang tepat untuk Bubblesort.A
Kasus terbaik
Sebaliknya, ada batas bawah sepele:
Cswaps(A)≥∑i=0n−2∑j=0n−i−20=0 .
Ini juga dapat terjadi: pada array yang sudah diurutkan, Bubblesort tidak menjalankan satu swap.
Kasus rata-rata
Kasus terburuk dan terbaik membuka cukup celah. Tapi apa adalah khas jumlah swap? Untuk menjawab pertanyaan ini, kita perlu mendefinisikan apa arti "khas". Secara teori, kami tidak memiliki alasan untuk lebih memilih satu input daripada input lainnya dan oleh karena itu kami biasanya mengasumsikan distribusi yang seragam atas semua input yang mungkin, yaitu setiap input memiliki kemungkinan yang sama besar. Kami membatasi diri untuk array dengan elemen berbeda berpasangan dan dengan demikian mengasumsikan model permutasi acak .
Kemudian, kami dapat menulis ulang biaya kami seperti ini²:
E[Cswaps]=1n!∑A∑i=0n−2∑j=0n−i−2C5,9(A(i,j))
Sekarang kita harus melampaui manipulasi jumlah yang sederhana. Dengan melihat algoritma, kami mencatat bahwa setiap swap menghapus tepat satu inversi dalam (kami hanya pernah bertukar tetangga )³. Artinya, jumlah swap dilakukan pada adalah persis jumlah inversi dari . Dengan demikian, kita dapat mengganti dua jumlah dalam dan mendapatkanAAinv(A)A
E[Cswaps]=1n!∑Ainv(A) .
Beruntung bagi kami, jumlah rata-rata inversi telah ditentukan
E[Cswaps]=12⋅(n2)
yang merupakan hasil akhir kami. Perhatikan bahwa ini persis setengah dari biaya terburuk.
- Perhatikan bahwa algoritma dirumuskan dengan cermat sehingga iterasi "yang terakhir" dengan
i = n-1
loop luar yang tidak pernah melakukan apa pun tidak dieksekusi.
- " " adalah notasi matematika untuk "nilai yang diharapkan", yang di sini hanya rata-rata.E
- Kami belajar sepanjang jalan bahwa tidak ada algoritma yang hanya menukar elemen tetangga dapat secara asimptotik lebih cepat daripada Bubblesort (bahkan rata-rata) - jumlah inversi adalah batas yang lebih rendah untuk semua algoritma tersebut. Ini berlaku untuk mis. Penyortiran dan Penyortiran Pilihan .
Metode Umum
Kita telah melihat dalam contoh bahwa kita harus menerjemahkan struktur kontrol ke dalam matematika; Saya akan menyajikan ansambel khas aturan terjemahan. Kita juga telah melihat bahwa biaya dari setiap subprogram yang diberikan mungkin tergantung pada keadaan saat ini , yaitu (kira-kira) nilai variabel saat ini. Karena algoritma (biasanya) memodifikasi keadaan, metode umum sedikit rumit untuk diketahui. Jika Anda mulai merasa bingung, saya sarankan Anda kembali ke contoh atau membuat sendiri.
Kami menyatakan dengan keadaan saat ini (bayangkan sebagai seperangkat tugas variabel). Ketika kami menjalankan program yang dimulai dengan status , kami berakhir dengan status (disediakan berakhir).ψP
ψψ/PP
Pernyataan individu
Diberi hanya satu pernyataan S;
, Anda menetapkan biaya . Ini biasanya akan menjadi fungsi konstan.CS(ψ)
Ekspresi
Jika Anda memiliki ekspresi E
formulir E1 ∘ E2
(misalnya, ekspresi aritmatika di mana ∘
mungkin penambahan atau penggandaan, Anda menambahkan biaya secara rekursif:
CE(ψ)=c∘+CE1(ψ)+CE2(ψ) .
Catat itu
- biaya operasi mungkin tidak konstan tetapi tergantung pada nilai dan danc∘E1E2
- evaluasi ekspresi dapat mengubah keadaan dalam banyak bahasa,
jadi Anda mungkin harus fleksibel dengan aturan ini.
Urutan
Diberikan program P
sebagai urutan program Q;R
, Anda menambahkan biaya
CP(ψ)=CQ(ψ)+CR(ψ/Q) .
Persyaratan
Diberikan program P
formulir if A then Q else R end
, biaya tergantung pada negara:
CP(ψ)=CA(ψ)+{CQ(ψ/A)CR(ψ/A),A evaluates to true under ψ,else
Secara umum, mengevaluasi A
mungkin sangat mengubah keadaan, sehingga pembaruan untuk biaya masing-masing cabang.
For-Loops
Diberikan program P
formulir for x = [x1, ..., xk] do Q end
, tetapkan biaya
CP(ψ)=cinit_for+∑i=1kcstep_for+CQ(ψi∘{x:=xi})
di mana adalah status sebelum memproses untuk nilai , yaitu setelah iterasi dengan diatur ke , ..., .ψiQ
xi
x
x1
xi-1
Perhatikan konstanta tambahan untuk pemeliharaan loop; variabel loop harus dibuat ( ) dan menetapkan nilainya ( )). Ini relevan sejakcinit_forcstep_for
- komputasi berikutnya
xi
mungkin mahal dan
- a
for
-Lingkaran dengan tubuh kosong (misalnya setelah menyederhanakan dalam kasus terbaik dengan biaya tertentu) tidak memiliki biaya nol jika melakukan iterasi.
Sementara-Loops
Diberikan program P
formulir while A do Q end
, tetapkan biaya
CP(ψ) =CA(ψ)+{0CQ(ψ/A)+CP(ψ/A;Q),A evaluates to false under ψ, else
Dengan memeriksa algoritme, perulangan ini sering kali dapat direpresentasikan dengan baik sebagai jumlah yang mirip dengan perulangan for-loop.
Contoh: Pertimbangkan algoritma singkat ini:
while x > 0 do 1
i += 1 2
x = x/2 3
end 4
Dengan menerapkan aturan, kita dapatkan
C1,4({i:=i0;x:=x0}) =c<+{0c+=+c/+C1,4({i:=i0+1;x:=⌊x0/2⌋}),x0≤0, else
dengan beberapa biaya konstan untuk masing-masing pernyataan. Kami berasumsi secara implisit bahwa ini tidak tergantung pada negara (nilai-nilai dan ); ini mungkin atau mungkin tidak benar dalam "kenyataan": pikirkan tentang luapan!c…i
x
Sekarang kita harus menyelesaikan pengulangan ini untuk . Kami mencatat bahwa baik jumlah iterasi bukan biaya loop body bergantung pada nilai , sehingga kami dapat menjatuhkannya. Kita dibiarkan dengan pengulangan ini:C1,4i
C1,4(x)={c>c>+c+=+c/+C1,4(⌊x/2⌋),x≤0, else
Ini diselesaikan dengan sarana dasar untuk
C1,4(ψ)=⌈log2ψ(x)⌉⋅(c>+c+=+c/)+c> ,
memperkenalkan kembali kondisi penuh secara simbolis; jika , maka .ψ={…,x:=5,…}ψ(x)=5
Panggilan Prosedur
Diberikan program P
formulir M(x)
untuk beberapa parameter di x
mana M
prosedur dengan parameter (bernama) p
, menetapkan biaya
CP(ψ)=ccall+CM(ψglob∘{p:=x}) .
Catat lagi konstanta tambahan (yang mungkin sebenarnya bergantung pada !). Panggilan prosedur mahal karena bagaimana mereka diterapkan pada mesin nyata, dan kadang-kadang bahkan mendominasi runtime (misalnya mengevaluasi pengulangan angka Fibonacci secara naif).ccallψ
Saya membahas beberapa masalah semantik yang mungkin Anda miliki dengan keadaan di sini. Anda akan ingin membedakan negara global dan lokal untuk panggilan prosedur. Mari kita asumsikan kita hanya melewati negara global di sini dan M
mendapat negara lokal baru, diinisialisasi dengan menetapkan nilai p
to x
. Lebih jauh, x
mungkin ungkapan yang kita (biasanya) asumsikan dievaluasi sebelum melewatinya.
Contoh: Pertimbangkan prosedurnya
fac(n) do
if ( n <= 1 ) do 1
return 1 2
else 3
return n * fac(n-1) 4
end 5
end
Sesuai aturan, kami mendapatkan:
Cfac({n:=n0})=C1,5({n:=n0})=c≤+{C2({n:=n0})C4({n:=n0}),n0≤1, else=c≤+{creturncreturn+c∗+ccall+Cfac({n:=n0−1}),n0≤1, else
Perhatikan bahwa kami mengabaikan negara global, karena fac
jelas tidak mengaksesnya. Perulangan khusus ini mudah dipecahkan
Cfac(ψ)=ψ(n)⋅(c≤+creturn)+(ψ(n)−1)⋅(c∗+ccall)
Kami telah membahas fitur bahasa yang akan Anda temui dalam kode pseudo yang khas. Waspadai biaya tersembunyi ketika menganalisis kode pseudo tingkat tinggi; jika ragu, buka. Notasi tersebut mungkin terlihat rumit dan tentu saja merupakan masalah selera; konsep-konsep yang tercantum tidak dapat diabaikan. Namun, dengan beberapa pengalaman Anda akan dapat melihat langsung bagian mana dari negara yang relevan untuk ukuran biaya mana, misalnya "ukuran masalah" atau "jumlah simpul". Sisanya dapat dijatuhkan - ini menyederhanakan banyak hal!
Jika Anda berpikir sekarang bahwa ini terlalu rumit, disarankan: itu adalah ! Turunkan biaya tepat dari algoritma dalam model apa pun yang begitu dekat dengan mesin nyata sehingga memungkinkan prediksi runtime (bahkan yang relatif) adalah upaya yang sulit. Dan itu bahkan tidak mempertimbangkan caching dan efek buruk lainnya pada mesin nyata.
Oleh karena itu, analisis algoritme sering disederhanakan sampai titik yang dapat ditelusur secara matematis. Misalnya, jika Anda tidak memerlukan biaya yang pasti, Anda bisa melebih-lebihkan atau meremehkan pada titik mana pun (untuk batas atas, batas bawah): kurangi set konstanta, singkirkan persyaratan, sederhanakan penjumlahan, dan sebagainya.
Catatan tentang biaya asimptotik
Apa yang biasanya Anda temukan dalam literatur dan di web adalah "Analisis Besar-Oh". Istilah yang tepat adalah analisis asimptotik yang berarti bahwa alih-alih mendapatkan biaya yang tepat seperti yang kami lakukan dalam contoh, Anda hanya memberikan biaya hingga faktor konstan dan dalam batas (secara kasar, "untuk besar ").n
Ini (sering) adil karena pernyataan abstrak memiliki beberapa (umumnya tidak diketahui) biaya dalam kenyataan, tergantung pada mesin, sistem operasi dan faktor lainnya, dan runtime pendek dapat didominasi oleh sistem operasi yang mengatur proses di tempat pertama dan yang lainnya. Jadi, Anda mendapatkan sedikit gangguan.
Inilah bagaimana analisis asimptotik berhubungan dengan pendekatan ini.
Identifikasi operasi dominan (yang menyebabkan biaya), yaitu operasi yang paling sering terjadi (hingga faktor konstan). Dalam contoh Bubblesort, satu pilihan yang mungkin adalah perbandingan di baris 5.
Sebagai alternatif, ikat semua konstanta untuk operasi elementer dengan resp maksimum (dari atas). minimum mereka (dari bawah) dan melakukan analisis biasa.
- Lakukan analisis menggunakan jumlah eksekusi operasi ini sebagai biaya.
- Saat menyederhanakan, izinkan estimasi. Berhati-hatilah untuk hanya mengizinkan estimasi dari atas jika sasaran Anda adalah resp batas atas ( ). dari bawah jika Anda ingin batas bawah ( ).OΩ
Pastikan Anda memahami arti simbol Landau . Ingatlah bahwa batasan seperti itu ada untuk ketiga kasus ; menggunakan tidak berarti analisis kasus terburuk.O
Bacaan lebih lanjut
Ada banyak tantangan dan trik dalam analisis algoritma. Berikut ini beberapa bacaan yang disarankan.
Ada banyak pertanyaan yang ditandai dengan analisis-algoritma yang menggunakan teknik yang mirip dengan ini.