Apakah kunci duplikat diperbolehkan dalam definisi pohon pencarian biner?

139

Saya mencoba menemukan definisi pohon pencarian biner dan saya terus menemukan definisi yang berbeda di mana-mana.

Beberapa mengatakan bahwa untuk subtree tertentu kunci anak kiri kurang dari atau sama dengan root.

Beberapa mengatakan bahwa untuk setiap subtree tertentu kunci anak kanan lebih besar atau sama dengan root.

Dan buku struktur data lama kampus saya mengatakan "setiap elemen memiliki kunci dan tidak ada dua elemen yang memiliki kunci yang sama."

Apakah ada definisi universal tentang bst? Khususnya mengenai apa yang harus dilakukan dengan pohon dengan banyak contoh dari kunci yang sama.

EDIT: Mungkin saya tidak jelas, definisi yang saya lihat adalah

1) kiri <= root <kanan

2) kiri <root <= kanan

3) kiri <root <kanan, sehingga tidak ada kunci duplikat.

Tim Merrifield
sumber

Jawaban:

78

Banyak algoritma akan menentukan bahwa duplikat dikecualikan. Sebagai contoh, algoritma contoh dalam buku Algoritma MIT biasanya menyajikan contoh tanpa duplikat. Cukup sepele untuk mengimplementasikan duplikat (baik sebagai daftar di simpul, atau dalam satu arah tertentu).

Sebagian besar (yang pernah saya lihat) menetapkan anak kiri sebagai <= dan anak kanan sebagai>. Secara praktis, BST yang memungkinkan anak-anak dari kanan atau kiri sama dengan simpul akar, akan memerlukan langkah komputasi ekstra untuk menyelesaikan pencarian di mana duplikat node diperbolehkan.

Yang terbaik adalah menggunakan daftar di simpul untuk menyimpan duplikat, karena menyisipkan nilai '=' ke satu sisi simpul memerlukan penulisan ulang pohon di sisi itu untuk menempatkan simpul sebagai anak, atau simpul ditempatkan sebagai grand -cild, di beberapa titik di bawah ini, yang menghilangkan beberapa efisiensi pencarian.

Anda harus ingat, sebagian besar contoh ruang kelas disederhanakan untuk menggambarkan dan menyampaikan konsep. Mereka tidak layak jongkok dalam banyak situasi dunia nyata. Tetapi pernyataan, "setiap elemen memiliki kunci dan tidak ada dua elemen yang memiliki kunci yang sama", tidak dilanggar dengan menggunakan daftar pada simpul elemen.

Jadi, pergilah dengan apa yang dikatakan buku struktur data Anda!

Edit:

Definisi Universal dari Pohon Pencarian Biner melibatkan penyimpanan dan pencarian kunci berdasarkan melintasi struktur data di salah satu dari dua arah. Dalam arti pragmatis, itu berarti jika nilainya <>, Anda melintasi struktur data di salah satu dari dua 'arah'. Jadi, dalam hal itu, nilai duplikat sama sekali tidak masuk akal.

Ini berbeda dari BSP, atau partisi pencarian biner, tetapi tidak semuanya berbeda. Algoritme untuk pencarian memiliki satu dari dua arah untuk 'perjalanan', atau itu dilakukan (berhasil atau tidak.) Jadi saya minta maaf karena jawaban asli saya tidak membahas konsep 'definisi universal', karena duplikat benar-benar berbeda topik (sesuatu yang Anda tangani setelah pencarian yang berhasil, bukan sebagai bagian dari pencarian biner.)

Chris
sumber
1
Apa kerugian menggunakan daftar di simpul?
Pacerier
1
@Pacerier Saya pikir alih-alih mempertahankan daftar, kita dapat mempertahankan jumlah referensi di setiap node dan memperbarui jumlah ketika duplikat terjadi. Algoritma seperti itu akan jauh lebih mudah dan efisien dalam mencari dan menyimpan. Juga, itu akan memerlukan perubahan minimal pada algoritma yang ada yang tidak mendukung duplikat.
SimpleGuy
50

Jika pohon pencarian biner Anda adalah pohon merah-hitam, atau Anda berniat untuk segala jenis operasi "rotasi pohon", duplikat node akan menyebabkan masalah. Bayangkan aturan pohon Anda adalah ini:

kiri <root <= kanan

Sekarang bayangkan sebuah pohon sederhana yang akarnya 5, anak kiri nihil, dan anak kanan 5. Jika Anda melakukan rotasi kiri pada root, Anda akan mendapatkan 5 di anak kiri dan 5 di root dengan anak kanan menjadi nihil. Sekarang sesuatu di pohon kiri sama dengan root, tetapi aturan Anda di atas diasumsikan sebagai <root.

Saya menghabiskan waktu berjam-jam untuk mencari tahu mengapa pohon-pohon merah / hitam saya kadang-kadang melintasi tidak teratur, masalahnya adalah apa yang saya jelaskan di atas. Semoga seseorang membaca ini dan menghemat berjam-jam untuk debugging di masa depan!

Kaya
sumber
18
Jangan memutar ketika Anda memiliki simpul yang sama! Lintasi ke tingkat berikutnya dan putar itu.
Kaya
2
Solusi lain adalah baik perubahan aturan pohon untuk menjadi left <= node <= right, atau hanya masukkan sebelum pertama terjadinya nilai.
paxdiablo
Masalah apa yang dapat menyebabkan ini dalam praktek? Tampak bagi saya bahwa jika Anda baik-baik saja dengan kiri <= simpul <= kanan, maka semua operasi pohon merah-hitam akan berhasil.
Björn Lindqvist
39

Ketiga definisi tersebut dapat diterima dan benar. Mereka menentukan variasi BST yang berbeda.

Buku struktur data perguruan tinggi Anda gagal menjelaskan bahwa definisi itu bukan satu-satunya yang mungkin.

Tentu saja, memperbolehkan duplikat menambah kerumitan. Jika Anda menggunakan definisi "kiri <= root <kanan" dan Anda memiliki pohon seperti:

      3
    /   \
  2       4

kemudian menambahkan kunci duplikat "3" ke pohon ini akan menghasilkan:

      3
    /   \
  2       4
    \
     3

Perhatikan bahwa duplikat tidak dalam level yang berdekatan.

Ini adalah masalah besar ketika memungkinkan duplikat dalam representasi BST seperti yang di atas: duplikat dapat dipisahkan oleh sejumlah level, jadi memeriksa keberadaan duplikat tidak sesederhana hanya memeriksa anak-anak langsung dari sebuah node.

Pilihan untuk menghindari masalah ini adalah untuk tidak mewakili duplikat secara struktural (sebagai node terpisah) melainkan menggunakan penghitung yang menghitung jumlah kemunculan kunci. Contoh sebelumnya akan memiliki pohon seperti:

      3(1)
    /     \
  2(1)     4(1)

dan setelah penyisipan kunci duplikat "3" itu akan menjadi:

      3(2)
    /     \
  2(1)     4(1)

Ini menyederhanakan operasi pencarian, penghapusan dan penyisipan, dengan mengorbankan beberapa byte tambahan dan operasi penghitung.

duilio
sumber
Saya sangat terkejut bahwa ini bahkan tidak pernah disebutkan dalam buku teks yang saya gunakan. Prof tidak menyebutkannya, atau fakta bahwa duplikat kunci bahkan menjadi masalah ...
Oloff Biermann
22

Dalam BST, semua nilai turun di sisi kiri node kurang dari (atau sama dengan, lihat nanti) node itu sendiri. Demikian pula, semua nilai turun di sisi kanan sebuah node lebih besar dari (atau sama dengan) nilai node (a) .

Beberapa BST dapat memilih untuk mengizinkan nilai duplikat, karenanya kualifikasi "atau sama dengan" di atas.

Contoh berikut dapat menjelaskan:

            |
      +--- 14 ---+
      |          |
+--- 13    +--- 22 ---+
|          |          |
1         16    +--- 29 ---+
                |          |
               28         29

Ini menunjukkan BST yang memungkinkan duplikat - Anda dapat melihat bahwa untuk menemukan nilai, Anda mulai pada simpul akar dan turun subtree kiri atau kanan tergantung pada apakah nilai pencarian Anda kurang dari atau lebih besar dari nilai node.

Ini dapat dilakukan secara rekursif dengan sesuatu seperti:

def hasVal (node, srchval):
    if node == NULL:
         return false
    if node.val == srchval:
        return true
    if node.val > srchval:
        return hasVal (node.left, srchval)
    return hasVal (node.right, srchval)

dan menyebutnya dengan:

foundIt = hasVal (rootNode, valToLookFor)

Duplikat menambah sedikit kerumitan karena Anda mungkin perlu terus mencari begitu Anda telah menemukan nilai Anda untuk node lain dengan nilai yang sama.


(a) Anda benar - benar dapat mengurutkannya ke arah yang berlawanan jika Anda ingin asalkan Anda menyesuaikan cara Anda mencari kunci tertentu. BST hanya perlu mempertahankan beberapa urutan, apakah naik atau turun tidak relevan.

paxdiablo
sumber
Untuk kasus duplikat, dapatkah Anda memeriksa apakah anak yang tepat sama dengan simpul saat ini di node.val == srchval: klausa, dan kemudian jika demikian langsung ke kanan?
bneil
9

Dalam buku "Pengantar algoritma", edisi ketiga, oleh Cormen, Leiserson, Rivest dan Stein, pohon pencarian biner (BST) secara eksplisit didefinisikan sebagai memungkinkan duplikat . Ini dapat dilihat pada gambar 12.1 dan berikut ini (halaman 287):

"Kunci dalam pohon pencarian biner selalu disimpan sedemikian rupa untuk memenuhi properti biner-search-pohon: Let x. Menjadi simpul dalam pohon pencarian biner Jika yadalah node dalam subtree kiri x, kemudian y:key <= x:key. Jika yini sebuah simpul di subtree kanan x, lalu y:key >= x:key. "

Selain itu, pohon merah-hitam kemudian didefinisikan pada halaman 308 sebagai:

"Pohon merah-hitam adalah pohon pencarian biner dengan satu bit tambahan penyimpanan per node: warnanya"

Oleh karena itu, pohon merah-hitam yang didefinisikan dalam buku ini mendukung duplikat.

Laurent Martin
sumber
4

Definisi apa pun valid. Selama Anda konsisten dalam implementasi Anda (selalu menempatkan simpul yang sama di sebelah kanan, selalu menempatkannya di sebelah kiri, atau tidak pernah mengizinkannya) maka Anda baik-baik saja. Saya pikir itu paling umum untuk tidak mengizinkan mereka, tetapi masih BST jika mereka diizinkan dan ditempatkan di kiri atau kanan.

Kotak sabun
sumber
1
jika Anda memiliki satu set data yang berisi kunci duplikat, maka semua item tersebut harus disimpan dalam 1 simpul di pohon melalui metode yang berbeda (daftar tertaut, dll). pohon seharusnya hanya berisi kunci unik.
nickf
1
Perhatikan juga dari wiki bahwa subtree kanan berisi nilai "lebih besar atau sama dengan" root. Oleh karena itu definisi wiki saling bertentangan.
SoapBox
1
+1: Orang yang berbeda menggunakan definisi yang berbeda. Jika Anda menerapkan BST baru, Anda harus memastikan Anda eksplisit tentang asumsi yang Anda buat tentang entri duplikat.
Tuan Fooz
1
Sepertinya konsensusnya adalah (kiri <= root <= kanan) ketika mengizinkan duplikat. Tapi itu definisi beberapa orang tentang BST tidak memungkinkan dups. Atau mungkin beberapa orang mengajarkan seperti itu untuk menghindari kompleksitas tambahan.
Tim Merrifield
1
salah! itu BAIK kiri <= root <kanan ATAU kiri <root <= kanan, ATAU kiri> root> = kanan ATAU kiri> = root> kanan
Mitch Wheat
3

Bekerja pada implementasi pohon merah-hitam Saya mendapatkan masalah memvalidasi pohon dengan beberapa kunci sampai saya menyadari bahwa dengan rotasi insert merah-hitam, Anda harus melonggarkan kendala untuk

left <= root <= right

Karena tidak ada dokumentasi yang saya lihat diperbolehkan untuk kunci duplikat dan saya tidak ingin menulis ulang metode rotasi untuk menjelaskannya, saya hanya memutuskan untuk memodifikasi node saya untuk memungkinkan beberapa nilai dalam node, dan tidak ada kunci duplikat di pohon.

Jherico
sumber
2

Tiga hal yang Anda katakan semuanya benar.

  • Kunci itu unik
  • Di sebelah kiri adalah kunci kurang dari yang ini
  • Di sebelah kanan adalah kunci yang lebih besar dari ini

Saya kira Anda dapat membalik pohon Anda dan meletakkan kunci yang lebih kecil di sebelah kanan, tetapi benar-benar konsep "kiri" dan "kanan" hanya itu: konsep visual untuk membantu kami berpikir tentang struktur data yang tidak benar-benar memiliki kiri atau benar, jadi itu tidak masalah.

nickf
sumber
1

1.) kiri <= root <kanan

2.) ke kiri <root <= kanan

3.) kiri <root <kanan, sehingga tidak ada kunci duplikat.

Saya mungkin harus pergi dan menggali buku-buku algoritma saya, tetapi dari atas kepala saya (3) adalah bentuk kanonik.

(1) atau (2) hanya muncul ketika Anda mulai mengizinkan duplikat node dan Anda menempatkan duplikat node di pohon itu sendiri (daripada node yang berisi daftar).

Robert Paulson
sumber
Bisakah Anda jelaskan mengapa kiri <= root <= kanan tidak ideal?
Helin Wang
Lihat jawaban yang diterima oleh @paxdiablo - Anda dapat melihat nilai duplikat yang ada >=. Ideal tergantung pada kebutuhan Anda, tetapi jika Anda memiliki banyak nilai duplikat, dan Anda membiarkan duplikat itu ada dalam struktur, pertama Anda dapat menjadi linier - yaitu O (n).
Robert Paulson
1

Duplikat Kunci • Apa yang terjadi jika ada lebih dari satu item data dengan kunci yang sama? - Ini menghadirkan sedikit masalah di pohon merah-hitam. - Sangat penting bahwa node dengan kunci yang sama didistribusikan di kedua sisi node lain dengan kunci yang sama. - Yaitu, jika kunci tiba dalam urutan 50, 50, 50, • Anda ingin 50 detik untuk pergi ke kanan yang pertama, dan 50 ketiga untuk pergi ke kiri yang pertama. • Kalau tidak, pohon menjadi tidak seimbang. • Ini bisa ditangani oleh beberapa jenis proses pengacakan dalam algoritma penyisipan. - Namun, proses pencarian menjadi lebih rumit jika semua item dengan kunci yang sama harus ditemukan. • Lebih mudah untuk melarang item dengan kunci yang sama. - Dalam diskusi ini kami akan menganggap duplikat tidak diperbolehkan

Seseorang dapat membuat daftar tertaut untuk setiap simpul pohon yang berisi kunci duplikat dan menyimpan data dalam daftar.

mszlazak
sumber
1

Saya hanya ingin menambahkan beberapa informasi ke apa yang dijawab @Robert Paulson.

Mari kita asumsikan bahwa simpul berisi kunci & data. Jadi node dengan kunci yang sama mungkin berisi data berbeda.
(Jadi pencarian harus menemukan semua node dengan kunci yang sama)

1) kiri <= cur <kanan

2) kiri <cur <= kanan

3) kiri <= cur <= kanan

4) kiri <rc <kanan &&rc berisi node saudara dengan kunci yang sama.

5) kiri <cur <kanan, sehingga tidak ada kunci duplikat.

1) & 2) berfungsi dengan baik jika pohon tidak memiliki fungsi terkait rotasi untuk mencegah kemiringan.
Tetapi formulir ini tidak berfungsi dengan pohon AVL atau pohon Merah-Hitam , karena rotasi akan mematahkan prinsipal.
Dan bahkan jika pencarian () menemukan node dengan kunci, itu harus melintasi ke simpul daun untuk node dengan kunci duplikat.
Membuat kerumitan waktu untuk pencarian = theta (logN)

3) akan bekerja dengan baik dengan segala bentuk BST dengan fungsi terkait rotasi.
Tetapi pencarian akan mengambil O (n) , merusak tujuan menggunakan BST.
Katakanlah kita memiliki pohon seperti di bawah ini, dengan 3) pokok.

         12
       /    \
     10     20
    /  \    /
   9   11  12 
      /      \
    10       12

Jika kita mencari (12) di pohon ini, bahkan kita menemukan 12 di root, kita harus terus mencari anak kiri & kanan untuk mencari kunci duplikat.
Ini membutuhkan waktu O (n) seperti yang saya katakan.

4) adalah favorit pribadi saya. Misalkan saudara berarti simpul dengan kunci yang sama.
Kita dapat mengubah pohon di atas menjadi di bawah.

         12 - 12 - 12
       /    \
10 - 10     20
    /  \    /
   9   11  12

Sekarang setiap pencarian akan mengambil O (logN) karena kami tidak perlu melintasi anak-anak untuk kunci duplikat.
Dan prinsipal ini juga bekerja dengan baik dengan AVL atau RB tree .

Malas Ren
sumber
0

Relasi pemesanan elemen <= adalah urutan total sehingga relasi harus refleksif tetapi umumnya pohon pencarian biner (alias BST) adalah pohon tanpa duplikat.

Kalau tidak, jika ada duplikat Anda perlu menjalankan dua kali atau lebih fungsi penghapusan yang sama!

Alberto
sumber