Kapan menggunakan strategi Preorder, Postorder, dan Inorder Binary Search Tree Traversal

98

Baru-baru ini saya menyadari bahwa meskipun telah menggunakan banyak BST dalam hidup saya, saya bahkan tidak pernah berpikir untuk menggunakan apa pun selain Inorder traversal (sementara saya sadar dan tahu betapa mudahnya mengadaptasi program untuk menggunakan pre / post-order traversal).

Setelah menyadari hal ini, saya mengeluarkan beberapa buku teks struktur data lama saya dan mencari alasan di balik kegunaan traversal pre-order dan post-order - mereka tidak banyak bicara.

Apa sajakah contoh kapan harus menggunakan praorder / postorder secara praktis? Kapan lebih masuk akal daripada berurutan?

John Humphreys - w00te
sumber

Jawaban:

136

Kapan menggunakan Strategi Traversal Pre-Order, In-Order, dan Post-Order

Sebelum Anda dapat memahami dalam situasi apa menggunakan pre-order, in-order dan post-order untuk pohon biner, Anda harus memahami dengan tepat bagaimana setiap strategi traversal bekerja. Gunakan pohon berikut sebagai contoh.

Akar pohon adalah 7 , simpul paling kiri 0 , simpul paling kanan 10 .

masukkan deskripsi gambar di sini

Traversal praorder :

Ringkasan: Dimulai di root ( 7 ), berakhir di node paling kanan ( 10 )

Urutan traversal: 7, 1, 0, 3, 2, 5, 4, 6, 9, 8, 10

Traversal berurutan :

Ringkasan: Dimulai di simpul paling kiri ( 0 ), berakhir di simpul paling kanan ( 10 )

Urutan Traversal: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Traversal pasca-pesanan :

Ringkasan: Diawali dengan simpul paling kiri ( 0 ), diakhiri dengan akar ( 7 )

Urutan traversal: 0, 2, 4, 6, 5, 3, 1, 8, 10, 9, 7

Kapan menggunakan Pre-Order, In-order atau Post-Order?

Strategi traversal yang dipilih programmer bergantung pada kebutuhan spesifik dari algoritma yang sedang dirancang. Tujuannya adalah kecepatan, jadi pilihlah strategi yang memberi Anda node yang paling cepat Anda butuhkan.

  1. Jika Anda tahu bahwa Anda perlu menjelajahi akar sebelum memeriksa daun apa pun, Anda memilih pemesanan di muka karena Anda akan menemukan semua akar sebelum semua daun.

  2. Jika Anda tahu Anda perlu menjelajahi semua daun sebelum ada node, Anda memilih pasca-pemesanan karena Anda tidak membuang waktu memeriksa akar untuk mencari daun.

  3. Jika Anda mengetahui bahwa pohon memiliki urutan yang melekat di node, dan Anda ingin meratakan pohon kembali ke urutan aslinya, sebaiknya gunakan traversal berurutan . Pohon itu akan diratakan dengan cara yang sama seperti saat dibuat. Traversal pre-order atau post-order mungkin tidak melepaskan pohon kembali ke urutan yang digunakan untuk membuatnya.

Algoritma Rekursif untuk Pre-order, In-order dan Post-order (C ++):

struct Node{
    int data;
    Node *left, *right;
};
void preOrderPrint(Node *root)
{
  print(root->name);                                  //record root
  if (root->left != NULL) preOrderPrint(root->left);  //traverse left if exists
  if (root->right != NULL) preOrderPrint(root->right);//traverse right if exists
}

void inOrderPrint(Node *root)
{
  if (root.left != NULL) inOrderPrint(root->left);   //traverse left if exists
  print(root->name);                                 //record root
  if (root.right != NULL) inOrderPrint(root->right); //traverse right if exists
}

void postOrderPrint(Node *root)
{
  if (root->left != NULL) postOrderPrint(root->left);  //traverse left if exists
  if (root->right != NULL) postOrderPrint(root->right);//traverse right if exists
  print(root->name);                                   //record root
}
Eric Leschinski
sumber
3
Bagaimana dengan traversal non-rekursif? Tampak bagi saya bahwa jauh lebih mudah untuk melintasi pohon secara non-rekursif dalam pre-order dibandingkan dengan in-order / post-order, karena tidak perlu kembali ke node sebelumnya.
bluenote10
@ bluenote10 Bisakah Anda menjelaskan apa yang Anda maksud? Dalam praorder, Anda masih "kembali" ke node untuk memproses anak kanannya setelah memproses anak kirinya. Tentu, Anda bisa menggunakan antrian "node belum dikunjungi", tapi itu sebenarnya hanya memperdagangkan penyimpanan implisit (tumpukan) untuk antrian eksplisit. Dalam semua metode traversal, anak kiri dan kanan harus diproses, yang berarti setelah melakukan salah satunya Anda harus "kembali" ke induk.
Joshua Taylor
@JoshuaTaylor: Ya, mereka semua adalah kelas kompleksitas yang sama, tetapi jika Anda melihat implementasi tipikal, post-order mungkin sedikit lebih rumit.
bluenote10
2
Traverse pre-order memberikan nilai node dalam urutan penyisipan. Jika Anda ingin membuat salinan pohon, Anda perlu melintasi pohon sumber dengan cara ini. Traverse berurutan memberikan nilai node yang diurutkan. Untuk traverse pasca-pesanan, Anda dapat menggunakan metode ini untuk menghapus seluruh pohon karena pohon mengunjungi simpul daun terlebih dahulu.
albin
Saya pikir itu benar meskipun pohon tidak diurutkan dengan benar, maksud saya urutan tidak akan memberikan urutan yang diurutkan jika urutannya tidak diurutkan pada awalnya.
CodeYogi
30

Pre-order: Digunakan untuk membuat salinan pohon. Misalnya, jika Anda ingin membuat replika pohon, letakkan node dalam array dengan traversal pre-order. Kemudian lakukan operasi Sisipkan pada pohon baru untuk setiap nilai dalam larik. Anda akan mendapatkan salinan dari pohon asli Anda.

In-order:: Digunakan untuk mendapatkan nilai node dalam urutan non-penurunan dalam BST.

Post-order:: Digunakan untuk menghapus pohon dari daun ke akar

Viraj Nimbalkar
sumber
2
ini adalah jawaban yang bagus dan ringkas serta membantu saya memahami kasus penggunaan pra-pemesanan dan pasca-pemesanan. meskipun, mungkin jelas mengingat bahwa pertanyaan menyebutkan hal ini secara langsung, tetapi perhatikan bahwa ini adalah kasus untuk pohon SEARCH biner dan tidak selalu berfungsi untuk pohon biner umum. misalnya, Anda tidak dapat menggunakan pre-order traversal untuk menyalin pohon biner umum, karena logika penyisipan selama proses penyalinan tidak akan berfungsi.
markckim
7
Sesuai urutan:: Untuk mendapatkan nilai node dalam urutan "non-penurunan" - bukan "tidak meningkat"
rahil008
26

Jika saya hanya ingin mencetak format hierarki pohon dalam format linier, saya mungkin akan menggunakan preorder traversal. Sebagai contoh:

- ROOT
    - A
         - B
         - C
    - D
         - E
         - F
             - G
Oliver Charlesworth
sumber
4
Atau dalam sebuah TreeViewkomponen dalam aplikasi GUI.
svick
4

Pre- dan post-order masing-masing berhubungan dengan algoritma rekursif top-down dan bottom-up. Jika Anda ingin menulis algoritme rekursif tertentu pada pohon biner secara berulang, inilah yang pada dasarnya akan Anda lakukan.

Amati lebih lanjut bahwa urutan sebelum dan sesudah pesanan bersama-sama secara lengkap menentukan pohon yang ada, menghasilkan pengkodean yang ringkas (setidaknya untuk pohon yang jarang).

Raphael
sumber
1
Saya pikir Anda mencoba mengatakan sesuatu yang penting, bisakah Anda menjelaskan paruh pertama?
CodeYogi
@CodeYogi Apa yang perlu dijelaskan secara spesifik?
Raphael
1
"Pra dan pasca pesanan berhubungan dengan algoritma rekursif top-down dan bottom-up" Saya rasa Anda ingin mengatakan bahwa dalam kasus pertama node diproses sebelum memanggil salah satu metode rekursif dan sebaliknya di yang terakhir, benar ?
CodeYogi
@CodeYogi Ya, pada dasarnya.
Raphael
2

Ada banyak tempat di mana Anda melihat perbedaan ini memainkan peran nyata.

Salah satu yang hebat yang akan saya tunjukkan adalah dalam pembuatan kode untuk kompiler. Pertimbangkan pernyataannya:

x := y + 32

Cara Anda menghasilkan kode untuk itu adalah (secara naif, tentu saja) pertama-tama menghasilkan kode untuk memuat y ke dalam register, memuat 32 ke dalam register, dan kemudian membuat instruksi untuk menambahkan keduanya. Karena sesuatu harus ada dalam register sebelum Anda memanipulasinya (anggap saja, Anda selalu dapat melakukan operan konstan tetapi apa pun) Anda harus melakukannya dengan cara ini.

Secara umum, jawaban yang Anda dapatkan untuk pertanyaan ini pada dasarnya direduksi menjadi ini: perbedaan sangat penting ketika ada beberapa ketergantungan antara pemrosesan bagian yang berbeda dari struktur data. Anda melihat ini saat mencetak elemen, saat membuat kode (keadaan eksternal membuat perbedaan, Anda juga dapat melihatnya secara monadik, tentu saja), atau saat melakukan jenis penghitungan lain di atas struktur yang melibatkan penghitungan bergantung pada turunan yang diproses terlebih dahulu .

Kristopher Micinski
sumber