Rumah / Tutorial Windows / Jenis fungsi kompleksitas algoritma. Aktivitas ilmiah dan hampir ilmiah saya: Kompleksitas komputasi algoritma Kompleksitas waktu dari algoritma gelombang

Jenis fungsi kompleksitas algoritma. Aktivitas ilmiah dan hampir ilmiah saya: Kompleksitas komputasi algoritma Kompleksitas waktu dari algoritma gelombang

Penamaan Penjelasan intuitif Definisi
f dibatasi dari atas oleh suatu fungsi g style="max-width: 98%; tinggi: otomatis; lebar: otomatis;" src="/pictures/wiki/files/101/eebfe73c29ff3f9bc886d263bd3e91f3.png" border="0"> or style="max-width: 98%; height: auto; width: auto;" src="/pictures/wiki/files/100/d96907f9d7419a7e0c74e4089c35c35e.png" border="0">
f dibatasi dari bawah oleh fungsi g(hingga faktor konstan) secara asimtotik style="max-width: 98%; tinggi: otomatis; lebar: otomatis;" src="/pictures/wiki/files/48/0fda981f377ae7b8d361f58ce148c173.png" border="0">
f dibatasi dari atas dan bawah oleh fungsi g tanpa gejala 0), n_0: \untuk semua (n>n_0) \; |Cg(n)|
g mendominasi f tanpa gejala style="max-width: 98%; tinggi: otomatis; lebar: otomatis;" src="/pictures/wiki/files/49/176ce786e936badb831a0bb87f25249d.png" border="0">
f mendominasi g tanpa gejala style="max-width: 98%; tinggi: otomatis; lebar: otomatis;" src="/pictures/wiki/files/53/554bc3f42cfa6d0638722e58e4a99d8b.png" border="0">
f setara dengan g tanpa gejala

Contoh

Catatan

Harus ditekankan bahwa tingkat pertumbuhan waktu eksekusi terburuk bukanlah satu-satunya atau kriteria yang paling penting untuk mengevaluasi algoritma dan program. Berikut adalah beberapa pertimbangan yang memungkinkan Anda untuk melihat kriteria runtime dari sudut pandang lain:

Jika penyelesaian beberapa masalah untuk graf n-verteks dengan satu algoritma membutuhkan waktu (jumlah langkah) orde n C , dan dengan orde lain n+n!/C, di mana C adalah bilangan konstan , maka menurut "ideologi polinomial" algoritma pertama praktis efisien , dan yang kedua tidak, meskipun, misalnya, pada C = 10 (10 10), situasinya justru sebaliknya.

  1. Algoritme yang efisien tetapi kompleks mungkin tidak diinginkan jika program yang sudah jadi didukung oleh orang yang tidak terlibat dalam penulisan program ini. Mari kita berharap bahwa poin dasar dari teknologi untuk membuat algoritma yang efisien diketahui secara luas, dan algoritma yang agak rumit diterapkan secara bebas dalam praktik. Namun, perlu untuk meramalkan kemungkinan bahwa algoritme yang efektif, tetapi "rumit" tidak akan diminati karena kerumitannya dan kesulitan yang muncul saat mencoba mencari tahu.
  2. Ada beberapa contoh di mana algoritma yang efisien membutuhkan volume yang besar. memori mesin(tanpa kemungkinan menggunakan media penyimpanan eksternal yang lebih lambat) bahwa faktor ini meniadakan keuntungan "efisiensi" dari algoritme.
  3. Dalam algoritma numerik, akurasi dan stabilitas algoritma tidak kalah pentingnya dengan efisiensi waktu.

Kelas kesulitan

Kelas kompleksitas adalah sekumpulan masalah pengenalan yang memiliki algoritma yang serupa dalam kompleksitas komputasi. Dua perwakilan penting:

Kelas P

Soal persamaan kelas P dan NP

ilmuwan terkenal

  • Leonid Levin
  • Alexander Razborov
  • Edie Sheimir

Lihat juga

Tautan

  • Yuri Lifshitz "Masalah modern informatika teoretis". Kursus kuliah tentang algoritma untuk masalah NP-hard.
  • A.A. Razborov Ilmu Komputer Teoretis: pandangan matematikawan // Komputer. - 2001. - No. 2. (tautan alternatif)
  • A.A. Razborov Pada kompleksitas perhitungan // pendidikan matematika. - MTSNMO, 1999. - No. 3. - S. 127-141.

Yayasan Wikimedia. 2010 .

Lihat apa "Kompleksitas waktu algoritma" di kamus lain:

    kompleksitas waktu (dari algoritma)- - Topik perlindungan informasi EN kompleksitas waktu ... Buku Pegangan Penerjemah Teknis

    KOMPLEKSITAS KEGIATAN OPERATOR- seperangkat faktor objektif yang mempengaruhi kualitas dan durasi kinerja seseorang dari fungsi yang diperlukan dalam HMS. Jadi. dibagi menjadi beberapa jenis, yang masing-masing dicirikan oleh kombinasi faktor-faktor dengan cara tertentu ... ... Kamus Ensiklopedis Psikologi dan Pedagogi

    Sebuah fungsi komputasi yang memberikan perkiraan numerik dari kesulitan (kerumitan) dari proses penerapan algoritma ke data awal. A. penyempurnaan dengan. perhitungan adalah konsep fungsi pensinyalan (atau hanya fungsi pensinyalan), ke tepi diberikan ... ... Ensiklopedia Matematika

    Dalam ilmu komputer dan teori algoritma, kompleksitas komputasi dari suatu algoritma adalah fungsi yang menentukan ketergantungan jumlah pekerjaan yang dilakukan oleh beberapa algoritma pada ukuran data input. Bagian yang mempelajari kompleksitas komputasi disebut teori ... ... Wikipedia

    Dalam ilmu komputer, teori kompleksitas komputasi adalah cabang dari teori komputasi yang mempelajari biaya kerja yang diperlukan untuk memecahkan masalah komputasi. Biaya biasanya diukur dengan konsep abstrak ruang dan waktu yang disebut ... ... Wikipedia

    Ini adalah algoritma untuk mengurutkan elemen dalam daftar. Jika item daftar memiliki beberapa bidang, bidang yang berfungsi sebagai kriteria urutan disebut kunci pengurutan. Dalam praktiknya, angka sering bertindak sebagai kunci, dan di bidang lain ... ... Wikipedia

    Algoritma pengurutan adalah algoritma untuk mengurutkan elemen dalam daftar. Jika item daftar memiliki beberapa bidang, bidang yang berfungsi sebagai kriteria urutan disebut kunci pengurutan. Dalam praktiknya, angka sering bertindak sebagai kunci, dan dalam ... ... Wikipedia

    - (GM) sistem kriptografi kunci publik yang dikembangkan oleh Shafi Goldwasser dan Silvio Micali pada tahun 1982. GM adalah skema enkripsi probabilistik kunci publik pertama yang terbukti aman di bawah standar kriptografi ... ... Wikipedia Baca lebih lanjut


Halo! Kuliah hari ini akan sedikit berbeda dari yang lain. Ini akan berbeda karena hanya terkait secara tidak langsung dengan Java. Namun, topik ini sangat penting bagi setiap programmer. Kita akan berbicara tentang algoritma. Apa itu algoritma? pembicaraan bahasa sederhana, ini adalah beberapa urutan tindakan yang harus dilakukan untuk mencapai hasil yang diinginkan. Kita sering menggunakan algoritma dalam kehidupan kita sehari-hari. Misalnya, setiap pagi Anda memiliki tugas: datang ke sekolah atau bekerja, dan pada saat yang sama menjadi:

  • berpakaian
  • membersihkan
  • penuh
Yang algoritma akan memungkinkan Anda untuk mencapai hasil ini?
  1. Bangun dengan alarm.
  2. Mandi, cuci.
  3. Siapkan sarapan, buat kopi/teh.
  4. Makan.
  5. Jika Anda belum menyetrika pakaian Anda sejak malam, setrikalah.
  6. Berpakaian.
  7. Meninggalkan rumah.
Urutan tindakan ini pasti akan memungkinkan Anda untuk mendapatkan hasil yang diinginkan. Dalam pemrograman, seluruh esensi pekerjaan kami terletak pada solusi masalah yang konstan. Sebagian besar tugas ini dapat dilakukan dengan menggunakan algoritma yang sudah dikenal. Misalnya, Anda dihadapkan dengan tugas berikut: mengurutkan daftar 100 nama dalam array. Tugasnya cukup sederhana, tetapi bisa diselesaikan cara yang berbeda. Berikut adalah salah satu solusi yang mungkin: Algoritma untuk mengurutkan nama berdasarkan abjad:
  1. Beli atau unduh di Internet "Kamus Nama Pribadi Rusia" edisi 1966.
  2. Temukan setiap nama dari daftar kami di kamus ini.
  3. Tuliskan di selembar kertas di halaman kamus mana nama itu berada.
  4. Urutkan nama-nama tersebut dengan menggunakan catatan di selembar kertas.
Akankah urutan tindakan seperti itu menyelesaikan masalah kita? Ya, itu akan memungkinkan. Akankah keputusan ini? efisien? Hampir tidak. Di sini kita datang ke yang lain sangat properti penting algoritma - mereka efisiensi. Anda dapat memecahkan masalah dengan cara yang berbeda. Tetapi baik dalam pemrograman maupun dalam kehidupan sehari-hari, kami memilih metode yang paling efektif. Jika tugas Anda adalah membuat sandwich mentega, Anda tentu bisa memulainya dengan menanam gandum dan memerah susu sapi. Tapi itu akan tidak efisien solusi - itu akan memakan waktu yang sangat lama dan akan menghabiskan banyak uang. Untuk mengatasi masalah sederhana Anda, Anda cukup membeli roti dan mentega. Dan algoritme dengan gandum dan sapi, meskipun memungkinkan Anda untuk memecahkan masalah, terlalu rumit untuk diterapkan dalam praktik. Untuk menilai kompleksitas algoritma dalam pemrograman, dibuat notasi khusus yang disebut Big-O ("O besar"). Big-O memungkinkan Anda untuk memperkirakan berapa banyak waktu eksekusi suatu algoritme bergantung pada data yang diteruskan ke sana. Mari kita lihat contoh paling sederhana - transfer data. Bayangkan Anda perlu mentransfer beberapa informasi sebagai file jarak jauh (misalnya, 5.000 kilometer). Algoritma mana yang paling efisien? Itu tergantung pada data yang dia gunakan untuk bekerja. Misalnya, kami memiliki file audio 10 megabyte.
Dalam hal ini, algoritma yang paling efisien adalah mentransfer file melalui Internet. Ini akan memakan waktu paling lama beberapa menit! Jadi, mari kita suarakan algoritme kita sekali lagi: "Jika Anda ingin mentransfer informasi dalam bentuk file dengan jarak 5000 kilometer, Anda perlu menggunakan transmisi data melalui Internet." Bagus sekali. Sekarang mari kita menganalisisnya. Apakah itu menyelesaikan masalah kita? Secara umum, ya, memang begitu. Tapi bagaimana dengan kompleksitasnya? Hmm, di sinilah hal-hal menarik. Faktanya adalah bahwa algoritma kami sangat bergantung pada data yang masuk, yaitu pada ukuran file. Sekarang kami memiliki 10 megabyte, dan semuanya beres. Bagaimana jika kita perlu mentransfer 500 megabyte? 20 gigabyte? 500 terabyte? 30 petabyte? Apakah algoritme kami akan berhenti berfungsi? Tidak, semua volume data ini masih dapat ditransfer. Apakah akan berjalan lebih lama? Ya, tentu saja! Sekarang kita tahu fitur penting dari algoritma kita: semakin besar ukuran data yang akan ditransfer, semakin lama algoritma akan selesai. Tetapi kami ingin memahami lebih tepatnya seperti apa ketergantungan ini (antara ukuran data dan waktu transfernya). Dalam kasus kami, kompleksitas algoritma akan menjadi linier. "Linear" berarti bahwa dengan bertambahnya jumlah data, waktu untuk mentransfernya akan meningkat kira-kira secara proporsional. Jika data menjadi 2 kali lebih banyak, dan akan membutuhkan waktu 2 kali lebih lama untuk mentransfernya. Jika data menjadi 10 kali lebih besar, dan waktu transfer akan meningkat 10 kali lipat. Menggunakan notasi Big-O, kompleksitas algoritma kami didefinisikan sebagai PADA). Notasi ini paling diingat untuk masa depan - selalu digunakan untuk algoritma dengan kompleksitas linier. Perhatikan: kita sama sekali tidak berbicara tentang berbagai hal "variabel" di sini: kecepatan Internet, kekuatan komputer kita, dan sebagainya. Saat mengevaluasi kompleksitas suatu algoritme, itu tidak masuk akal - kami tetap tidak dapat mengontrolnya. Big-O mengevaluasi algoritme itu sendiri, terlepas dari “ lingkungan” di mana dia harus bekerja. Mari kita lanjutkan dengan contoh kita. Katakanlah pada akhirnya ternyata ukuran file yang akan ditransfer adalah 800 terabyte. Jika kita mengirimkannya melalui Internet, masalahnya tentu saja akan terpecahkan. Hanya ada satu masalah: dibutuhkan sekitar 708 hari untuk mentransmisikan melalui tautan modern standar (dengan kecepatan 100 megabit per detik) yang kebanyakan kita gunakan di rumah. Hampir 2 tahun! :HAI Jadi, algoritma kami jelas tidak cocok di sini. Butuh solusi lain! Tanpa diduga, raksasa IT, Amazon, datang membantu kami! Dia layanan Amazon Snowmobile memungkinkan Anda memuat sejumlah besar data ke penyimpanan seluler dan mengirimkannya ke alamat yang benar dengan truk!
Jadi, kami memiliki algoritma baru! “Jika Anda ingin mentransfer informasi dalam bentuk file lebih dari 5.000 kilometer dan proses ini memakan waktu lebih dari 14 hari saat mentransfer melalui Internet, Anda perlu menggunakan transportasi data di truk Amazon.” Angka 14 hari dipilih secara acak di sini: katakanlah ini adalah periode maksimum yang kita mampu. Mari kita menganalisis algoritma kita. Bagaimana dengan kecepatan? Bahkan jika sebuah truk melaju hanya dengan kecepatan 50 km/jam, ia akan menempuh jarak 5.000 kilometer hanya dalam 100 jam. Itu hanya lebih dari empat hari! Ini jauh lebih baik daripada opsi transmisi Internet. Bagaimana dengan kompleksitas algoritma ini? Apakah juga akan linier, O(N)? Tidak, tidak akan. Lagi pula, truk tidak peduli berapa banyak Anda memuatnya - truk akan tetap melaju dengan kecepatan yang sama dan tiba tepat waktu. Apakah kita memiliki 800 terabyte, atau data 10 kali lebih banyak, truk masih akan mencapai tempat itu dalam 5 hari. Dengan kata lain, algoritme untuk mengirimkan data melalui truk kompleksitas konstan. "Konstan" berarti tidak bergantung pada data yang dikirimkan ke algoritma. Masukkan flash drive 1GB ke dalam truk - itu akan tiba dalam 5 hari. Taruh di sana disk dengan 800 terabyte data - itu akan mencapai Anda dalam 5 hari. Saat menggunakan Big-O, kompleksitas konstan dilambangkan sebagai O(1). Sejak kita mengenal PADA) dan O(1), sekarang mari kita lihat lebih banyak contoh "pemrograman" :) Katakanlah Anda diberi larik 100 angka, dan tugasnya adalah mencetak masing-masing ke konsol. Anda menulis normal for loop yang melakukan pekerjaan ini int numbers = new int [ 100 ] ; // ..isi array dengan angka for (int i: number) ( System. out. println (i) ; ) Berapakah kompleksitas dari algoritma yang ditulis? Linier, O(N). Jumlah tindakan yang harus dilakukan program tergantung pada berapa banyak angka yang dilewatkan ke dalamnya. Jika ada 100 angka dalam larik, akan ada 100 tindakan (keluaran di layar) Jika ada 10.000 nomor dalam larik, 10.000 tindakan perlu dilakukan. Bisakah algoritme kami ditingkatkan? Tidak. Bagaimanapun, kita harus N melewati array dan jalankan N output ke konsol. Mari kita pertimbangkan contoh lain. public static void main(String args) (LinkedList < Integer> angka = Daftar Tautan baru< >() ; angka. tambahkan (0 , 20202 ); angka. tambahkan (0, 123); angka. tambahkan (0, 8283); ) Kami memiliki LinkedList kosong di mana kami memasukkan beberapa angka. Kita perlu mengevaluasi kompleksitas algoritme untuk memasukkan satu nomor ke dalam LinkedList dalam contoh kita, dan bagaimana hal itu bergantung pada jumlah elemen dalam daftar. Jawabannya adalah O(1) - kompleksitas konstan. Mengapa? Perhatikan bahwa setiap kali kita memasukkan nomor di awal daftar. Selain itu, seperti yang Anda ingat, ketika Anda memasukkan nomor ke dalam LinkedList, elemen tidak bergerak ke mana pun - tautannya didefinisikan ulang (jika Anda tiba-tiba lupa cara kerja LinkedList, lihat salah satu dari kami). Jika sekarang angka pertama dalam daftar kami adalah angka x, dan kami memasukkan angka y di awal daftar, yang diperlukan hanyalah x. sebelumnya = y; y. sebelumnya = nol; y. berikutnya = x; Untuk penggantian tautan ini kami tidak peduli berapa banyak angka yang ada di LinkedList sekarang- setidaknya satu, setidaknya satu miliar. Kompleksitas algoritma akan konstan - O(1).

Kompleksitas logaritma

Jangan panik! :) Jika pada kata "logaritmik" Anda ingin menutup kuliah dan tidak membaca lebih lanjut, tunggu beberapa menit. Tidak akan ada kesulitan matematika di sini (ada banyak penjelasan seperti itu di tempat lain), dan kami akan menganalisis semua contoh "dengan jari". Bayangkan bahwa tugas Anda adalah menemukan satu nomor tertentu dalam larik 100 nomor. Lebih tepatnya, untuk memeriksa apakah itu ada sama sekali. Segera setelah nomor yang diinginkan ditemukan, pencarian harus dihentikan, dan entri berikut akan ditampilkan ke konsol: “Nomor yang diinginkan telah ditemukan! Indeksnya dalam array = ....” Bagaimana Anda memecahkan masalah seperti itu? Di sini solusinya jelas: Anda harus menelusuri elemen array satu per satu mulai dari yang pertama (atau dari yang terakhir) dan memeriksa apakah nomor saat ini cocok dengan yang Anda cari. Dengan demikian, jumlah tindakan secara langsung tergantung pada jumlah elemen dalam array. Jika kita memiliki 100 angka, maka kita perlu pergi ke elemen berikutnya 100 kali dan memeriksa nomor untuk kecocokan 100 kali. Jika ada 1000 angka, maka akan ada 1000 langkah cek. Ini jelas kompleksitas linier, PADA). Dan sekarang kami akan menambahkan satu klarifikasi ke contoh kami: array di mana Anda perlu menemukan nomor diurutkan dalam urutan menaik. Apakah itu mengubah sesuatu untuk tugas kita? Kami masih dapat mencari nomor yang diinginkan dengan cara brute force. Tapi sebaliknya kita bisa menggunakan yang terkenal algoritma pencarian biner.
Di baris atas gambar, kita melihat array yang diurutkan. Kita perlu menemukan angka 23 di dalamnya, daripada memilah-milah angka, kita cukup membagi array menjadi 2 bagian dan memeriksa angka rata-rata dalam array. Kami menemukan nomor yang terletak di sel 4 dan memeriksanya (baris kedua dalam gambar). Jumlah ini adalah 16, dan kami mencari 23. Jumlah saat ini kurang. Apa artinya ini? Apa semua nomor sebelumnya (yang terletak sebelum nomor 16) tidak dapat diperiksa: mereka pasti akan kurang dari yang kita cari, karena array kita diurutkan! Mari kita lanjutkan pencarian di antara 5 elemen yang tersisa. Perhatikan: kami hanya melakukan satu pemeriksaan, tetapi telah menghilangkan setengah dari opsi yang mungkin. Kami hanya memiliki 5 item tersisa. Kami akan mengulangi langkah kami - membagi array yang tersisa dengan 2 lagi dan mengambil elemen tengah lagi (baris 3 pada gambar). Jumlah ini adalah 56, dan itu lebih dari yang kami cari. Apa artinya ini? Bahwa kami menolak 3 opsi lagi - angka 56 itu sendiri, dan dua angka setelahnya (pasti lebih besar dari 23, karena array diurutkan). Kami hanya memiliki 2 angka yang tersisa untuk diperiksa (baris terakhir pada gambar) - angka dengan indeks array 5 dan 6. Kami memeriksa yang pertama, dan inilah yang kami cari - angka 23! indeksnya = 5! Mari kita lihat hasil dari algoritme kita, dan kemudian menangani kompleksitasnya. (Omong-omong, sekarang Anda mengerti mengapa itu disebut biner: esensinya terletak pada pembagian data yang konstan dengan 2). Hasilnya sangat mengesankan! Jika kami mencari nomor yang tepat dengan pencarian linier, kami akan membutuhkan 10 cek, dan dengan pencarian biner kami melewatkan 3! Dalam kasus terburuk, akan ada 4 dari mereka, jika pada langkah terakhir jumlah yang kami butuhkan adalah yang kedua, dan bukan yang pertama. Bagaimana dengan kompleksitasnya? Ini adalah poin yang sangat menarik :) Algoritma pencarian biner sangat bergantung pada jumlah elemen dalam array daripada algoritma pencarian linier (yaitu, enumerasi sederhana). Pada 10 elemen dalam array, pencarian linier akan membutuhkan maksimal 10 pemeriksaan, dan pencarian biner akan membutuhkan maksimal 4 pemeriksaan. Perbedaannya adalah 2,5 kali. Tapi untuk array di 1000 item pencarian linier akan membutuhkan 1000 cek, dan biner - jumlah 10! Perbedaannya sudah 100 kali lipat! Perhatikan bahwa jumlah elemen dalam array telah meningkat dengan faktor 100 (dari 10 menjadi 1000), sedangkan jumlah pemeriksaan yang diperlukan untuk pencarian biner hanya meningkat dengan faktor 2,5, dari 4 menjadi 10. Jika kita dapatkan ke 10.000 item, perbedaannya bahkan lebih mengesankan: 10.000 cek untuk pencarian linier, dan total 14 cek untuk biner. Dan lagi: jumlah elemen meningkat 1000 kali (dari 10 menjadi 10.000), dan jumlah cek hanya meningkat 3,5 kali (dari 4 menjadi 14). Kompleksitas algoritma pencarian biner adalah logaritmik, atau, menggunakan notasi Big-O, - O(log n). Kenapa dia disebut begitu? Logaritma adalah kebalikan dari eksponensial. Logaritma biner digunakan untuk menghitung pangkat sebuah angka 2. Misalnya, kita memiliki 10.000 elemen yang perlu kita urutkan dengan pencarian biner.
Sekarang Anda memiliki gambar di depan mata Anda, dan Anda tahu bahwa untuk ini Anda memerlukan maksimal 14 pemeriksaan. Tetapi bagaimana jika tidak ada gambar di depan mata Anda, dan Anda perlu menghitung jumlah pasti pemeriksaan yang diperlukan? Cukup menjawab pertanyaan sederhana: Berapakah pangkat 2 yang harus dinaikkan agar diperoleh hasil >= banyaknya elemen yang akan diperiksa? Untuk 10.000 itu akan menjadi derajat ke-14. 2 pangkat 13 terlalu kecil (8192) Tapi 2 pangkat 14 = 16384, angka ini memenuhi kondisi kita (ini adalah >= jumlah elemen dalam array). Kami menemukan logaritma - 14. Kami membutuhkan begitu banyak pemeriksaan! :) Algoritma dan kompleksitasnya adalah topik yang terlalu luas untuk ditampung dalam satu kuliah. Tetapi mengetahuinya sangat penting: dalam banyak wawancara Anda akan menerima tugas algoritmik. Untuk teori, saya dapat merekomendasikan Anda beberapa buku. Anda dapat memulai dengan “Video Big-O di YouTube. Sampai jumpa di kuliah-kuliah berikutnya! :)

Seringkali dimungkinkan untuk menghasilkan lebih dari satu algoritma untuk menyelesaikan masalah yang sama. Dalam hubungan ini, muncul pertanyaan: algoritma mana yang "lebih baik"?

Dalam kebanyakan kasus, "lebih baik", tampaknya, adalah algoritma yang, pada input data yang sama, datang ke solusi masalah, mengkonsumsi lebih sedikit sumber daya komputasi (memori dan waktu). Ini, tentu saja, diskusi yang longgar. Untuk alasan yang lebih ketat, kami memperkenalkan beberapa konsep.

Proses komputasi dari suatu algoritma adalah urutan langkah-langkah yang diambil saat mengeksekusi algoritma untuk beberapa masukan.

Penting untuk memahami perbedaan antara algoritma itu sendiri dan proses komputasi yang dihasilkan oleh algoritma ini. Yang pertama hanya keterangan kedua.

Kompleksitas waktu suatu algoritme adalah waktu \(T\) yang diperlukan untuk menyelesaikan proses komputasi algoritme untuk beberapa masukan.

Jelas bahwa waktu eksekusi tergantung pada artis tertentu. Katakanlah kalkulator elektronik dan superkomputer mungkin akan menjalankan algoritma yang sama pada waktu yang berbeda.

Namun, waktu \(T\) dapat dinyatakan dalam jumlah tindakan dasar \(k\) dan waktu eksekusi rata-rata dari tindakan dasar \(t\) :

Selain itu, \(k\) adalah properti paling algoritma, dan \(t\) adalah properti dari pelaksana.

Mengingat fakta bahwa \(t\) dapat dianggap sebagai konstanta untuk performer tertentu, biasanya kompleksitas algoritma diperkirakan hingga faktor konstan. Dengan kata lain, kompleksitas algoritma diperkirakan urutan pertumbuhan.

Orde pertumbuhan Fungsi pasti positif \(g(x)\) memiliki orde pertumbuhan \(f(x)\) (ditulis \(g(x)=\mathcal(O)(f(x))\) ) jika \(\ada c>0: \: \forall x>x_0, \, g(x) \leq c f(x)\).

Tergantung pada data input, algoritma dapat berjalan untuk waktu yang berbeda. Biasanya dinilai rata-rata kesulitan dan kerumitan paling buruk. Ada juga ketergantungan pada kuantitas masukan data \(n\) . Biasanya urutan pertumbuhan dari \(n\) yang dievaluasi.

Jadi, misalnya, membaca data dan menyimpannya dalam memori sebagai array akan memiliki kompleksitas \(\mathcal(O)(n)\) , atau kompleksitas linier, dan perkalian matriks sudah kubik\(\mathcal(O)(n^3)\) .

Selain kompleksitas waktu dari algoritma, itu juga penting spasial kompleksitas algoritma.

Kompleksitas spasial dari algoritma adalah angka tambahan memori \(S\) , yang dibutuhkan algoritme untuk bekerja. Memori \(D\) yang diperlukan untuk menyimpan data input tidak termasuk dalam \(S\) .

\(S\) umumnya juga tergantung pada perangkat eksekusi. Katakanlah, jika dua unit eksekusi mendukung bilangan bulat masing-masing 4 dan 8 byte, maka kompleksitas ruang algoritma pada bilangan bulat 8-byte akan menjadi dua kali lipat pada bilangan bulat 4-byte. Oleh karena itu, kompleksitas spasial juga diperkirakan dengan urutan pertumbuhan.

Kelas kompleksitas algoritma

Yakin kelas kompleksitas: Ini adalah kategori yang memiliki kesulitan serupa.

Ada kelas utama kompleksitas berikut:

DTIME Sebuah mesin Turing menemukan solusi untuk masalah dalam waktu yang terbatas (jumlah langkah). Asimtotik dari algoritma sering disempurnakan, jadi, katakanlah, jika urutan pertumbuhan waktu berjalan adalah \(T(n) = \mathcal(O)(f(n))\) , maka \(DTIME(f (n))\) ditentukan. P Mesin Turing menemukan solusi untuk masalah dalam waktu polinomial (jumlah langkah), yaitu. \(T(n) = \mathcal(O)(n^k)\) , di mana \(k\in \mathbb(N)\) . \(P=DTIME(n^k)\) EXPTIME Mesin Turing menemukan solusi untuk masalah dalam waktu eksponensial (jumlah langkah), yaitu. \(T(n) = \mathcal(O)(2^(n^k))\), di mana \(k\in \mathbb(N)\) . \(EXPTIME=DTIME(2^(n^k))\) . DSPACE Mesin Turing menemukan solusi untuk masalah dengan menggunakan memori ekstra (sel) dalam jumlah terbatas. Asimtotik dari algoritme sering disempurnakan, jadi, katakanlah, jika urutan pertumbuhan konsumsi memori adalah \(S(n) = \mathcal(O)(f(n))\) , maka \(DSPACE(f( n))\) ditentukan. L Mesin Turing menemukan solusi untuk masalah dengan kompleksitas ruang logaritmik, yaitu. \(S(n) = \mathcal(O)(\log n)\). \(L=DSPACE(\log n)\) . PSPACE Mesin Turing menemukan solusi untuk masalah dengan kompleksitas ruang polinomial, yaitu \(S(n) = \mathcal(O)(n^k)\) , di mana \(k\in \mathbb(N)\) . \(PSPACE=DSPACE(n^k)\) . EXPSPACE Mesin Turing menemukan solusi untuk masalah dengan kompleksitas ruang eksponensial, mis. \(S(n) = \mathcal(O)(2^(n^k))\), di mana \(k\in \mathbb(N)\) . \(EXPSPACE=DSPACE(2^(n^k))\) .

Selain itu, ada kelas kompleksitas teoretis yang beroperasi dengan konsep non-deterministik Mesin Turing (HMT). Definisinya sama seperti di atas, dengan mesin Turing diganti dengan HMT, dan namanya diawali dengan N (misalnya, NP), kecuali untuk NTIME dan NSPACE, di mana D diganti dengan N.

NMT adalah konstruksi teoretis murni, yang, menurut prinsip operasi, mirip dengan MT, dengan perbedaan bahwa untuk masing-masing negara bagian dapat ada beberapa tindakan yang mungkin. Pada saat yang sama, NMT selalu memilih dari kemungkinan tindakan yang mengarah ke solusi dalam jumlah langkah seminimal mungkin. Secara setara, HMT menghitung semua cabang dan memilih cabang yang mengarah ke solusi dalam jumlah langkah sesedikit mungkin.

Anda terkadang dapat mendengar bahwa komputer kuantum adalah implementasi dari NMT. Meskipun ini mungkin tampak benar dalam beberapa kasus, secara umum BMT lebih sistem yang kuat daripada komputer kuantum.

Diketahui bahwa \(P \subseteq NP \subseteq PSPACE \subseteq EXPTIME \subseteq NEXPTIME \subseteq EXPSPACE\)

Juga, \(P \subsetneq EXPTIME\) , \(NP \subsetneq NEXPTIME\) , \(PSPACE \subsetneq EXPSPACE\)

Diketahui juga bahwa jika \(P = NP\) , maka \(EXPTIME = NEXPTIME\) .

Pertanyaan tentang kesetaraan P dan NP adalah salah satu masalah utama yang belum terselesaikan dari ilmu komputer modern.

Contoh Algoritma

Mari kita berikan beberapa contoh algoritma sederhana dan pertimbangkan kompleksitasnya.

Menaikkan ke kekuatan bilangan bulat

Algoritme ini dijelaskan di India kuno sebelum zaman kita dan digunakan untuk menghitung daya alami \(n\) dari bilangan real \(x\)

  1. Tulis \(n\) dalam biner
  2. Ganti dalam entri ini masing-masing 1 dengan sepasang huruf KX, dan masing-masing 0 dengan huruf K
  3. Coret pasangan CH paling kiri
  4. Membaca string yang diterima dari kiri ke kanan, memenuhi huruf K, kuadratkan hasilnya, dan bertemu dengan huruf X, kalikan hasilnya dengan x. Pada awalnya, hasilnya adalah x.

Dalam algoritma ini, kami memiliki jumlah operasi perkalian yang sama dengan jumlah digit dalam representasi biner\(n\) paling baik, dan \(2(n-1)\) paling buruk. Bagaimanapun, kompleksitas waktu .

Memori tambahan praktis tidak diperlukan dalam implementasi algoritma yang efisien, dan tidak tergantung pada data input, sehingga kompleksitas ruang adalah \(S(n) = \mathcal(O)(1)\) .

Perlu dicatat bahwa ada algoritma yang lebih efisien. Namun, dibandingkan dengan implementasi “naif”, yang membutuhkan operasi perkalian \(\mathcal(O)(n)\), algoritma ini relatif efisien.

Perkalian bilangan bulat

Algoritma perkalian ini kadang-kadang disebut Rusia atau petani, meskipun dikenal di Mesir kuno.

Faktor pertama berturut-turut dikalikan dua, dan faktor kedua dibagi 2. Hasilnya ditulis dalam dua kolom sampai yang kedua adalah 1.

Hasil perkalian adalah jumlah bilangan pada kolom pertama yang berlawanan dengan bilangan ganjil pada kolom kedua.

Karena pembagian bilangan bulat dan perkalian dengan 2 dapat diimplementasikan dengan pergeseran, algoritma ini menghasilkan \(2 \log_2 n\) operasi pergeseran, di mana \(n\) adalah yang lebih kecil dari dua angka. Dalam kasus terburuk, \(\log_2 n - 1\) operasi penjumlahan juga diperoleh. Bagaimanapun, kompleksitas waktu \(T(n) = \mathcal(O)(\log n)\).

Untuk implementasi algoritma yang efisien, memori tambahan praktis tidak diperlukan, dan tidak tergantung pada data input, oleh karena itu \(S(n) = \mathcal(O)(1)\)

Sekali lagi, perlu dicatat bahwa ada algoritma yang lebih efisien. Namun, dibandingkan dengan implementasi “naif”, yang membutuhkan operasi penjumlahan \(\mathcal(O)(n)\), algoritma ini relatif efisien.

Contoh

Kalikan 23 dengan 43.

Mari kita ambil 23 sebagai faktor kedua.

43 23 aneh
86 11 aneh
172 5 aneh
344 2
688 1 aneh

Hasil \(43+86+172+688 = 989\)

Kami mendapat 10 operasi shift dan 4 operasi penambahan. Untuk referensi, \(\log_2(23) \kira-kira 4,52\) .

Fungsi kompleksitas 0(1). Dalam algoritma dengan kompleksitas konstan, sebagian besar operasi dalam program dilakukan satu kali atau lebih. Setiap algoritma yang selalu membutuhkan (terlepas dari ukuran data) jumlah waktu yang sama memiliki kompleksitas yang konstan.

Fungsi kompleksitas 0(N). Waktu berjalan program biasanya linier, ketika setiap elemen data input perlu diproses hanya beberapa kali linier. Fungsi kompleksitas ini mencirikan loop sederhana.

Fungsi kompleksitas 0(N 2), 0(N 3), 0(№) - fungsi polinomial kompleksitas: jumlah operasi tumbuh secara proporsional dengan kuadrat N. Dalam kasus umum, mungkin ada O(A^) tergantung pada kompleksitas masalah. Fungsi kompleksitas ini mencirikan siklus yang kompleks.

Fungsi kompleksitas O(Log 2 (A0), 0(T log 2 (A0). Ini adalah waktu ketika algoritma bekerja yang membagi masalah besar menjadi banyak masalah kecil, dan kemudian, setelah menyelesaikannya, menggabungkan solusinya.

Fungsi kompleksitas 0(e N). Algoritma dengan kompleksitas eksponensial paling sering dihasilkan dari pendekatan yang disebut brute force.

Fungsi kompleksitas 0(M) - jumlah operasi tumbuh secara proporsional dengan faktorial N.

Pemrogram harus mampu menganalisis algoritma dan menentukan kompleksitasnya. Kompleksitas waktu suatu algoritma dapat dihitung berdasarkan analisis struktur kontrolnya.

Algoritma tanpa loop dan panggilan rekursif memiliki kompleksitas yang konstan. Jika tidak ada rekursi dan loop, semua struktur kontrol dapat direduksi menjadi struktur dengan kompleksitas konstan. Akibatnya, seluruh algoritma juga ditandai dengan kompleksitas yang konstan. Menentukan kompleksitas suatu algoritma pada dasarnya bermuara pada menganalisis loop dan panggilan rekursif.

Misalnya, pertimbangkan algoritma untuk memproses elemen array.

Untuk /": = 1 sampai N mulai

Kompleksitas algoritma ini HAI(A) karena badan perulangan dieksekusi A kali, dan kompleksitas badan perulangan adalah 0(1). Jika satu loop bersarang di dalam loop lain dan kedua loop bergantung pada ukuran variabel yang sama, maka keseluruhan konstruksi dicirikan oleh kompleksitas kuadrat.

Untuk /: = 1 sampai N lakukan untuk j:= 1 sampai N mulai

Kompleksitas program ini 0(N2).

Contoh 1 Mari kita perkirakan kompleksitas program yang memasuki array dari keyboard dan menemukan elemen terbesar di dalamnya. Algoritma terdiri dari langkah-langkah berikut:

  • - input array (perlu membaca elemen A);
  • - cari elemen terbesar (Anda perlu melakukan perbandingan A - 1);
  • - keluaran hasil (Anda perlu menampilkan satu angka atau string).

Kami menambahkan jumlah operasi A + (A - 1) + 1 = 2A, mis. ada

suatu konstanta sehingga untuk sembarang A jumlah operasi tidak melebihi CA. Oleh karena itu, kompleksitas algoritma adalah 0(A).

Contoh 2 Mari kita perkirakan kompleksitas program yang memasuki array dari keyboard dan menemukan elemen di dalamnya dengan properti yang diberikan(misalnya, sama dengan nilai tertentu). Algoritma terdiri dari langkah-langkah berikut:

  • - masukan array (Operasi masukan);
  • - mencari elemen dengan properti tertentu (elemen dapat lebih dekat ke awal array atau di akhir; jika elemen tidak ada, maka semua perbandingan A harus dibuat untuk memastikan hal ini);
  • - hasil keluaran.

Dalam kasus terbaik, algoritma yang ditentukan akan membutuhkan operasi A + 2 (input dari seluruh array, satu perbandingan, output), dalam kasus terburuk (ketika tidak ada elemen seperti itu, operasi 2A + 1). Jika A mau jumlah yang besar, misalnya, sekitar 10 6 , maka unit dapat diabaikan. Oleh karena itu, kompleksitas algoritmanya adalah 0 (N).

Contoh 3 Mari kita definisikan fungsi kompleksitas dari algoritma enkripsi untuk sebuah kata yang panjangnya L metode substitusi. Misalkan ada tabel di mana untuk setiap karakter alfabet ada karakter yang harus diganti. Tunjukkan jumlah huruf alfabet S. Algoritma terdiri dari langkah-langkah berikut:

  • - masukan kata (satu operasi);
  • - organisasi siklus:
    • 1) untuk setiap karakter, temukan penggantinya di tabel (jika tabel tidak dipesan dan tidak memiliki properti yang memfasilitasi pencarian, maka dalam kasus terburuk akan diperlukan S operasi untuk satu karakter, jika elemen yang diperlukan ada di paling akhir);
    • 2) keluaran dari simbol yang ditemukan;
  • - akhir siklus.

Jumlah total operasi 1 + (S+)L. Dalam kasus yang cukup besar S dan L unit dapat diabaikan, dan ternyata fungsi kompleksitas dari algoritma di atas adalah O(S L).

Contoh 4 Mari kita definisikan fungsi kompleksitas dari algoritma terjemahan bilangan asli 1 V ke sistem bilangan biner (tanpa operasi input dan output data). Algoritma terdiri dari langkah-langkah berikut:

  • - loop hingga hasil pembagian bilangan dengan 2 menjadi 0:
  • - bagi angka dengan 2 dan ingat sisanya;
  • - menerima hasil pembagian sebagai bilangan baru;
  • - akhir siklus.

Jumlah total operasi tidak melebihi 1 + log 2 A. Oleh karena itu, algoritma yang dijelaskan memiliki kompleksitas 0 (misalnya 2 N).

Secara tradisional, merupakan kebiasaan untuk mengevaluasi tingkat kompleksitas suatu algoritma dengan volume sumber daya komputer utama yang digunakan olehnya: waktu prosesor dan memori akses acak. Dalam hal ini, konsep seperti kompleksitas waktu dari algoritma dan kompleksitas volume dari algoritma diperkenalkan.

Parameter kompleksitas waktu menjadi sangat penting untuk tugas yang melibatkan mode operasi program interaktif, atau untuk tugas kontrol waktu nyata. Seringkali seorang programmer yang menulis program kontrol untuk beberapa perangkat teknis, kita harus menemukan kompromi antara keakuratan perhitungan dan waktu berjalan program. Sebagai aturan, peningkatan akurasi menyebabkan peningkatan waktu.

Kompleksitas volumetrik program menjadi kritis ketika jumlah data yang diproses berada pada batas RAM komputer. Pada komputer modern, tingkat keparahan masalah ini berkurang karena peningkatan jumlah RAM dan penggunaan yang efisien sistem penyimpanan bertingkat. Program ini memiliki akses ke area memori yang sangat besar dan hampir tidak terbatas ( memori maya). Kurangnya memori utama hanya menyebabkan beberapa perlambatan karena pertukaran disk. Teknik digunakan untuk meminimalkan hilangnya waktu selama pertukaran semacam itu. Ini adalah penggunaan memori cache dan tampilan perangkat keras dari instruksi program untuk jumlah langkah yang diperlukan, yang memungkinkan Anda untuk mentransfer nilai yang diperlukan dari disk ke memori utama terlebih dahulu. Berdasarkan hal di atas, kita dapat menyimpulkan bahwa meminimalkan kompleksitas kapasitif bukanlah prioritas utama. Oleh karena itu, berikut ini, kami terutama akan tertarik pada kompleksitas waktu dari algoritma.

Waktu eksekusi program sebanding dengan jumlah operasi yang dieksekusi. Tentu saja, dalam satuan dimensi waktu (detik), itu juga tergantung pada kecepatan prosesor (frekuensi clock). Agar indikator kompleksitas waktu dari algoritma menjadi invarian terhadap spesifikasi komputer, diukur dalam satuan relatif. Biasanya, kompleksitas waktu diperkirakan dengan jumlah operasi yang dilakukan.

Sebagai aturan, kompleksitas waktu dari algoritma tergantung pada data awal. Ini mungkin ketergantungan pada ukuran data awal dan volumenya. Jika kita menyatakan nilai parameter kompleksitas waktu dari algoritma dengan simbol Tα, dan huruf V menunjukkan beberapa parameter numerik yang mencirikan data awal, maka kompleksitas waktu dapat direpresentasikan sebagai fungsi Tα(V). Pilihan parameter V tergantung pada masalah yang dipecahkan atau pada jenis algoritma yang digunakan untuk menyelesaikan masalah ini.

Contoh 1. Mari kita perkirakan kompleksitas waktu dari algoritma untuk menghitung faktorial bilangan bulat positif.

Fungsi Faktorial(x:Integer): Integer;

Varm, saya: Bilangan bulat;

Untuk i:=2 Ke x Lakukan m:=ro*i;

Mari kita hitung jumlah total operasi yang dilakukan oleh program ketika nilai yang diberikan x. Pernyataan m:=1; dieksekusi sekali; badan loop (di mana ada dua operasi: perkalian dan penugasan) dieksekusi x - 1 kali; tugas dilakukan sekali Faktorial:=m. Jika setiap operasi diambil sebagai satuan kompleksitas, maka kompleksitas waktu dari keseluruhan algoritma akan menjadi 1 + 2 (x - 1) + 1 = 2x Dari sini jelas bahwa nilai x harus diambil sebagai parameter . Fungsi kompleksitas waktu ternyata sebagai berikut:

Dalam hal ini, kita dapat mengatakan bahwa kompleksitas waktu bergantung secara linier pada parameter data - nilai argumen dari fungsi faktorial.

Contoh 2. Perhitungan perkalian skalar dua buah vektor A = (a1, a2, ..., ak), B = (b1, b2, ..., bk).

Untuk i:=l Untuk k Lakukan AB:=AB+A[i]*B[i];

Dalam masalah ini, ukuran data input adalah n = 2k. Jumlah operasi yang dilakukan 1 + 3k = 1 + 3(n/2). Di sini kita dapat mengambil V= k= n/2. Tidak ada ketergantungan kompleksitas algoritma pada nilai elemen vektor A dan B. Seperti pada contoh sebelumnya, di sini kita dapat berbicara tentang ketergantungan linier dari kompleksitas waktu pada parameter data.

Dua masalah teoritis biasanya dikaitkan dengan parameter kompleksitas waktu dari suatu algoritma. Yang pertama terdiri dalam menemukan jawaban atas pertanyaan: berapa batas nilai kompleksitas waktu yang dapat dicapai dengan meningkatkan algoritma untuk memecahkan masalah? Batas ini tergantung pada tugas itu sendiri dan, oleh karena itu, adalah karakteristiknya sendiri.

Masalah kedua terkait dengan klasifikasi algoritma berdasarkan kompleksitas waktu. Fungsi Tα(V) biasanya tumbuh dengan V. Seberapa cepat ia tumbuh? Ada algoritma dengan ketergantungan linier Tα pada V (seperti dalam contoh yang telah kita bahas), dengan ketergantungan kuadrat, dan dengan ketergantungan derajat yang lebih tinggi. Algoritma semacam itu disebut polinomial. Dan ada algoritma yang kompleksitasnya tumbuh lebih cepat daripada polinomial mana pun. Masalah yang sering dipecahkan oleh para ahli teori - peneliti algoritma, adalah pertanyaan berikut: apakah algoritma polinomial mungkin untuk masalah yang diberikan?

Fungsi yang sering ditemui dalam analisis algoritma:

  • catatan n(waktu logaritmik),
  • n(waktu linier),
  • n catatan n,
  • n 2 (waktu persegi),
  • 2n(waktu eksponensial).

Empat fungsi pertama memiliki tingkat pertumbuhan yang rendah, dan algoritme yang waktu berjalannya diperkirakan oleh fungsi-fungsi ini dapat dianggap cepat. Laju pertumbuhan fungsi eksponensial kadang-kadang dicirikan sebagai "eksplosif". Sebagai perbandingan, mari kita asumsikan bahwa ada algoritma yang kompleksitasnya (jumlah operasi) secara akurat tercermin oleh fungsi-fungsi ini. Biarkan algoritma ini dijalankan pada komputer yang berjalan dengan kecepatan 10 12 operasi per detik. Dengan panjang masukan n 100000, algoritma yang kinerjanya diperkirakan oleh empat fungsi pertama akan menerima jawaban dalam sepersekian detik. Untuk algoritma dengan kompleksitas 2 n waktu berjalan diperkirakan sebagai berikut:

  • n= 50 19 menit,
  • n= 60 320 jam,
  • n= 70 37 tahun.

Soal 15=49. Algoritma sekuensial, siklik dan rekursif.

Algoritma Sekuensial - algoritma di mana blok dieksekusi secara berurutan satu demi satu, dalam urutan skema yang diberikan.

Contoh. Hitung keliling segitiga dengan sisi a,b,c.13

Algoritma Struktur Percabangan

Dalam prakteknya, sangat jarang mungkin untuk merepresentasikan solusi dari suatu masalah dalam bentuk algoritma.

struktur linier. Seringkali tergantung pada beberapa perantara

hasil perhitungan dilakukan baik di satu atau di sisi lain

rumus, yaitu tergantung pada pemenuhan beberapa kondisi logis

proses komputasi dilakukan menurut satu atau lain rumus.

Algoritma dari proses komputasi seperti itu disebut algoritma

struktur percabangan.

Percabangan - struktur pemerintahan, yang mengatur eksekusi hanya

salah satu dari dua tindakan yang ditentukan tergantung pada keadilan

beberapa kondisi.

Kondisi adalah pertanyaan yang memiliki dua kemungkinan jawaban: ya atau tidak.

Percabangan dicatat dalam dua bentuk: lengkap dan tidak lengkap (Gbr. 1 a, b).

a) formulir lengkap b) formulir tidak lengkap

Algoritma siklik algoritma di mana perlu untuk menghitung nilai berulang kali sesuai dengan dependensi matematika yang sama (diagram blok) untuk nilai yang berbeda dari jumlah yang termasuk di dalamnya. Penggunaan siklus dapat secara signifikan mengurangi volume sirkuit

algoritma dan panjang program yang sesuai. Ada siklus dengan

diberikan dan jumlah pengulangan yang tidak diketahui. Dengan jumlah pengulangan tertentu -

lingkaran dengan penghitung. Dengan jumlah pengulangan yang tidak diketahui - loop dengan prasyarat,

loop dengan postcondition.

Sebuah fungsi (atau prosedur) yang mengacu langsung atau tidak langsung ke dirinya sendiri disebut rekursif. Rekursi adalah metode mendefinisikan suatu fungsi melalui nilai-nilai sebelumnya dan sebelumnya didefinisikan, serta cara

organisasi perhitungan, di mana fungsi memanggil dirinya sendiri dengan argumen yang berbeda

Saat menerapkan algoritma rekursif, setiap langkah rekursi tidak memberikan solusi langsung untuk masalah, tetapi menguranginya menjadi masalah yang sama lebih kecil. Proses ini harus mengarah pada tugas dengan ukuran sedemikian rupa sehingga

solusinya cukup mudah. Selanjutnya, "gerakan mundur" memberikan solusi berturut-turut untuk masalah peningkatan ukuran, hingga yang awal. Implementasi prosedur dengan rekursi didasarkan pada tumpukan (memori tipe penyimpanan), yang menyimpan data yang terlibat dalam semua panggilan ke prosedur, di mana prosedur tersebut belum menyelesaikan pekerjaannya. Rekursi adalah cara mengatur proses perhitungan ketika algoritma mengacu pada dirinya sendiri. Prinsip rekursi memungkinkan Anda untuk memecahkan masalah yang kompleks dengan secara berurutan memecahkan submasalah yang lebih sederhana.Sebagai aturan, rekursi diperlukan dalam kasus di mana Anda harus melalui terlalu banyak pilihan. Rekursi dianggap sebagai salah satu varietas algoritma siklik. Bentuk organisasi rekursif memungkinkan untuk memberikan algoritma bentuk yang lebih kompak. Dengan demikian, masalah diselesaikan dari kompleks ke sederhana - isi dari algoritma rekursif mencerminkan objek yang lebih kompleks melalui yang lebih sederhana dari jenis yang sama. Biasanya, algoritma rekursif berisi bagian-bagian utama berikut:

– kondisi untuk mengakhiri siklus;

- tubuh rekursi, yang mencakup tindakan yang dimaksudkan untuk

eksekusi pada setiap iterasi;

adalah langkah rekursi di mana algoritma rekursif memanggil dirinya sendiri.

Bedakan antara rekursi langsung dan tidak langsung. Dalam kasus pertama, algoritma

berisi fungsi yang memanggil dirinya sendiri. Jika suatu fungsi memanggil fungsi lain, yang pada gilirannya memanggil yang pertama, maka fungsi itu

disebut rekursi tidak langsung.

Persyaratan utama untuk algoritma rekursif adalah bahwa proses inversi tidak

harus tak terbatas. Dengan kata lain, itu harus dilaksanakan

memeriksa penyelesaian panggilan, atau dalam definisi rekursif harus

ada batasan di mana inisialisasi lebih lanjut

rekursi dihentikan.

Contoh fungsi rekursif adalah menghitung faktorial suatu bilangan.

int faktoria (int n)

jika (n) mengembalikan n* faktoria(n-1);

lain kembali 1;

Contoh prosedur rekursif:

prosedur Rec(a: integer); mulai jika a>0 lalu Rec(a-1); tulis(a); akhir;

Mari kita pertimbangkan apa yang terjadi jika kita melakukan panggilan di program utama, misalnya, dalam bentuk Rec(3). Di bawah ini adalah diagram alur yang menunjukkan urutan di mana pernyataan dieksekusi.