Rumah > Java > javaTutorial > Papan anjal untuk berfungsi melebihi primitif rekursif? Pelaksanaan untuk fungsi Ackermann Peter

Papan anjal untuk berfungsi melebihi primitif rekursif? Pelaksanaan untuk fungsi Ackermann Peter

Barbara Streisand
Lepaskan: 2025-01-18 20:09:14
asal
173 orang telah melayarinya

Trampolim para funções além do primitivo recursivo? Implementação para a função de Ackermann Peter

Apabila meneroka teknik papan anjal, saya pada mulanya menggunakannya dalam situasi yang lebih mudah, dengan hanya satu ulangan – mungkin subset yang betul bagi fungsi rekursif primitif. Walau bagaimanapun, keperluan timbul untuk melakukan pengiraan yang sangat panjang di tempat kerja. Idea pertama saya ialah fungsi sibuk memerang, tetapi, sebagai tambahan kepada kerumitan pengiraan yang tinggi, saya tidak begitu biasa. Saya kemudian memilih fungsi yang lebih dikenali: fungsi Ackermann-Peter.

Fungsi Ackermann-Peter

Ini ialah fungsi yang mudah difahami yang mengambil dua hujah integer sebagai input:

<code class="language-java">int ackermannPeter(int m, int n) {
    if (m == 0) {
        return n + 1;
    } else if (n == 0) {
        return ackermannPeter(m - 1, 1);
    }
    return ackermannPeter(m - 1, ackermannPeter(m, n - 1));
}</code>
Salin selepas log masuk

Untuk butiran lanjut, lihat halaman Wikipedia atau WolframAlpha.

Menggunakan Fungsi

Apabila menguji ackermannPeter(3, 3), keputusan dikira dengan betul. Walau bagaimanapun, apabila melaksanakan ackermannPeter(4, 3), letupan tindanan berlaku. Kedalaman panggilan rekursif ke fungsi Ackermann-Peter adalah sangat besar; hanya menukar hujah pertama daripada 3 kepada 4 menjadikan output, iaitu 61, menjadi 2 2 6553632^{2^{65536}} - 3 .

Mengatasi Had Tindanan

Masalahnya terletak pada pengulangan sengit fungsi Ackermann-Peter, yang cepat meletihkan timbunan. Penyelesaiannya adalah dengan menggunakan sambungan untuk mengelak daripada membebankan tindanan, melaksanakan idea papan anjal.

Satu langkah di atas trampolin memerlukan tiga tingkah laku:

  • Nyatakan sama ada pengiraan telah tamat.
  • Kembalikan nilai yang dikira.
  • Lakukan satu langkah dan dapatkan kesinambungan seterusnya.

Untuk kes kami (pulangan integer):

<code class="language-java">interface Continuation {
    boolean finished();
    int value();
    Continuation step();

    static Continuation found(int v) { /* ... */ }
    static Continuation goon(Supplier<Continuation> nextStep) { /* ... */ }
}</code>
Salin selepas log masuk

Trampolin itu sendiri:

<code class="language-java">static int compute(Continuation c) {
    while (!c.finished()) {
        c = c.step();
    }
    return c.value();
}</code>
Salin selepas log masuk

Memohon pada fungsi Ackermann-Peter: fungsi terbahagi kepada tiga kes: kes asas, rekursi mudah dan rekursi berganda. Papan anjal harus mengawal hasil rekursi kedua. Untuk melakukan ini, hujah kedua menjadi Continuation. Jika n sudah selesai, proses diteruskan seperti biasa; jika tidak, satu langkah diambil dalam kesinambungan, menjana yang baharu.

<code class="language-java">private static Continuation ackermannPeter(int m, Continuation c) {
    if (!c.finished()) {
        return Continuation.goon(() -> {
            final var next = c.step();
            return Continuation.goon(() -> ackermannPeter(m, next));
        });
    }
    int n = c.value();
    if (m == 0) {
        return Continuation.found(n + 1);
    } else if (n == 0) {
        return Continuation.goon(() -> ackermannPeter(m - 1, Continuation.found(1)));
    }
    return Continuation.goon(() ->
        ackermannPeter(m - 1,
            Continuation.goon(() -> ackermannPeter(m, Continuation.found(n - 1)
        )))
    );
}</code>
Salin selepas log masuk

Menambah Memoisasi

Menghafal meningkatkan prestasi. Dua situasi: 1) hasilnya sudah dalam ingatan; 2) langkah seterusnya membolehkan anda membuat kesimpulan hasil semasa. Memoisasi digunakan selepas menyelesaikan kesinambungan hujah kedua. Pelaksanaan dengan memoisasi menggunakan kekunci HashMap dan long (menggabungkan m dan n) dibentangkan, menunjukkan pengurangan ketara dalam bilangan panggilan rekursif. Versi akhir mengalih keluar kebergantungan memori global, memberikan HashMap sebagai hujah.

Atas ialah kandungan terperinci Papan anjal untuk berfungsi melebihi primitif rekursif? Pelaksanaan untuk fungsi Ackermann Peter. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan