Bagaimana caranya, dengan sekumpulan kunci yang telah ditentukan sebelumnya, menyusun ulang kunci sedemikian rupa sehingga jumlah minimum node yang digunakan saat memasukkan ke dalam B-Tree?

Jadi saya punya masalah yang saya yakin bisa dipecahkan, tapi setelah berjam-jam berpikir dan berdiskusi, hanya sebagian kemajuan yang dicapai.

Masalahnya adalah sebagai berikut. Saya sedang membangun BTree yang berpotensi berisi beberapa juta kunci. Saat mencari di BTree, halaman tersebut dimasukkan berdasarkan permintaan dari disk ke memori, dan setiap halaman dalam pengoperasiannya relatif mahal. Ini secara efektif berarti bahwa kita perlu melintasi node sesedikit mungkin (walaupun setelah sebuah node dilintasi, biaya untuk melintasi node tersebut, hingga node tersebut adalah 0). Oleh karena itu, kami tidak ingin menyia-nyiakan ruang dengan memiliki banyak node yang mendekati kapasitas minimum. Secara teori, hal ini seharusnya dapat dicegah (dengan alasan yang masuk akal) karena struktur pohon bergantung pada urutan penyisipan kunci.

Jadi, pertanyaannya adalah bagaimana menyusun ulang kunci sedemikian rupa sehingga setelah BTree dibuat, jumlah node yang digunakan paling sedikit. Berikut ini contohnya:

Contoh

Saya tersandung pada pertanyaan ini Dalam urutan apa Anda harus memasukkan sekumpulan kunci yang diketahui ke dalam B-Tree untuk mendapatkan ketinggian minimal? yang sayangnya menanyakan pertanyaan yang sedikit berbeda. Jawabannya, sepertinya juga tidak menyelesaikan masalah saya. Perlu juga ditambahkan bahwa kami menginginkan jaminan matematis karena tidak membuat pohon secara manual, dan hanya menggunakan opsi sisipkan. Kami tidak ingin membuat pohon secara manual, membuat kesalahan, dan kemudian menemukannya tidak dapat dicari!

Saya juga menemukan 2 makalah penelitian yang hampir menyelesaikan pertanyaan saya tetapi belum cukup sampai di sana! Optimalitas Ruang dan Waktu di B-Trees dan Optimal 2,3-Trees (yang sebenarnya saya ambil dari gambar di atas) membahas dan mengukur perbedaan antara ruang optimal dan BTrees yang pesimis terhadap ruang, tetapi sejauh yang saya bisa lihat, jangan menjelaskan lebih jauh cara mendesain urutan penyisipan.

Bantuan apa pun dalam hal ini akan sangat, sangat dihargai.

Terima kasih

Makalah penelitian dapat ditemukan di:

http://www.uqac.ca/rebaine/8INF805/Automne2007/Sujets2007Automne/p174-rosenberg.pdf

http://scholarship.claremont.edu/cgi/viewcontent.cgi?article=1143&context=hmc_fac_pub

EDIT:: Saya akhirnya mengisi kerangka btree yang dibuat seperti dijelaskan dalam makalah di atas dengan algoritma FILLORDER. Seperti disebutkan sebelumnya, saya berharap untuk menghindari hal ini, namun saya akhirnya menerapkannya sebelum 2 jawaban bagus diposting!


person Squimmy    schedule 28.07.2014    source sumber
comment
Anda dapat dengan mudah membuat b-tree secara batch dengan mengurutkan item dan membuat pohon dengan daftar yang diurutkan tersebut. Anda bahkan tidak perlu memasukkannya satu per satu.   -  person usr    schedule 28.07.2014
comment
Saya khawatir saya kurang mengikuti. Memasukkan item dalam urutan yang diurutkan pasti tidak menghasilkan ruang BTree yang optimal sejauh yang saya bisa lihat?   -  person Squimmy    schedule 28.07.2014
comment
Algoritme tidak bekerja dengan memasukkan item. Anda mengurutkan daftarnya, lalu membuat simpul daun dari daftar itu. Sekarang Anda memiliki simpul daun yang sempurna. Selanjutnya Anda membuat lapisan tambahan di atas simpul daun tersebut.; Apa yang dilakukan RDBMS adalah mereka memiliki aturan khusus untuk penyisipan di bagian akhir. Mereka tidak membagi halaman secara merata tetapi membuat halaman kosong yang baru. Jangan menganggap algoritma b-tree (dari wikipedia) terlalu harfiah. Anda bisa bermain dengan mereka.   -  person usr    schedule 28.07.2014
comment
Oh begitu. Saya sangat enggan untuk membangun pohon dari dedaunan ke atas meskipun ada kemungkinan satu dari sejuta bug aneh muncul yang tidak kami duga sebelumnya, dan akhirnya menciptakan beberapa B-Tree yang tidak valid dan tidak dapat ditelusuri yang akan terjadi. menjadi super, sangat bermasalah. Sebenarnya saya tidak khawatir tentang sisipan kata penutup. Setelah dibuat, sebenarnya kita tidak perlu melakukan penyisipan apa pun di dalamnya.   -  person Squimmy    schedule 28.07.2014
comment
Bagaimana dengan menggunakan perpustakaan b-tree? Sisipkan secara berurutan. Saya akan mengatakan bahwa perpustakaan yang baik mengoptimalkan kasus-kasus itu karena sangat umum.   -  person usr    schedule 28.07.2014
comment
Jika ruang optimal adalah pendorong utama Anda, apakah Anda yakin b - tree adalah struktur data yang paling tepat? Array terurut sederhana (vektor) memberikan lokalitas cache yang lebih baik dan mempertahankan kemampuan pencarian dengan kompleksitas log (n).   -  person Chad    schedule 30.07.2014
comment
Apakah ini berbeda dari pohon biner self-balancing standar seperti pohon merah-hitam? Anda hanya mencari jaminan tingginya log2(n) kan?   -  person Moby Disk    schedule 30.07.2014
comment
pohon merah-hitam tidak memiliki jaminan log2(n). Jaminannya hanya O(log2(n)) dan nyatanya bisa sebesar 2log2(n). Dan menurut saya itulah inti pertanyaannya, sampai batas tertentu. Bisakah Anda memasukkan dalam urutan tertentu yang menghasilkan karakteristik ketinggian lebih baik daripada yang dijamin oleh algoritme itu sendiri. Lihat komentar saya berikutnya (terlalu panjang)!   -  person Jeremy West    schedule 31.07.2014
comment
Ini akan sulit dijawab tanpa mengetahui secara pasti cara kerja operasi penyisipan. Saya berasumsi Anda memiliki implementasi kotak hitam yang memungkinkan Anda memasukkan item dan kemudian menempatkannya di pohon? Maka jawabannya akan bergantung pada kapan algoritme memutuskan untuk membagi blok dan bagaimana algoritma tersebut membaginya saat itu terjadi.   -  person Jeremy West    schedule 31.07.2014


Jawaban (5)


Algoritme di bawah ini seharusnya berfungsi untuk B-Trees dengan jumlah kunci minimum di node = d dan maksimum = 2*d. Saya kira ini dapat digeneralisasi untuk 2*d + 1 kunci maks jika cara memilih median diketahui.

Algoritma di bawah ini dirancang untuk meminimalkan jumlah node, bukan hanya tinggi pohon.

Metode ini didasarkan pada gagasan untuk meletakkan kunci ke dalam daun yang tidak penuh atau jika semua daun penuh untuk meletakkan kunci di bawah simpul tidak penuh yang paling bawah.

Lebih tepatnya, pohon yang dihasilkan oleh algoritma yang diusulkan memenuhi persyaratan berikut: Memiliki ketinggian minimum yang mungkin; Ia memiliki tidak lebih dari dua node nonfull pada setiap level. (Itu selalu merupakan dua simpul paling kanan.)

Karena kita tahu bahwa jumlah node pada level apa pun kecuali root sama dengan jumlah jumlah node dan total jumlah kunci pada level di atas, kita dapat membuktikan bahwa tidak ada penataan ulang node yang valid antar level yang mengurangi jumlah total node. Misalnya peningkatan jumlah kunci yang disisipkan di atas level tertentu akan menyebabkan peningkatan node pada level tersebut dan akibatnya meningkatkan jumlah total node. Meskipun upaya apa pun untuk mengurangi jumlah kunci di atas level tertentu akan menyebabkan penurunan jumlah node pada level tersebut dan gagal untuk menyesuaikan semua kunci pada level tersebut tanpa menambah tinggi pohon. Jelas juga bahwa susunan kunci pada level tertentu merupakan salah satu yang optimal. Dengan menggunakan alasan di atas, pembuktian yang lebih formal melalui induksi matematika juga dapat dibangun.

Idenya adalah untuk menyimpan daftar penghitung (ukuran daftar tidak lebih besar dari tinggi pohon) untuk melacak berapa banyak kunci yang ditambahkan pada setiap level. Setelah saya menambahkan kunci d ke level tertentu, itu berarti node terisi setengahnya dibuat di level itu dan jika ada cukup kunci untuk mengisi setengah lagi dari node ini, kita harus melewati kunci ini dan menambahkan root untuk level yang lebih tinggi. Dengan cara ini akar akan ditempatkan tepat di antara paruh pertama subpohon sebelumnya dan paruh pertama subpohon berikutnya, hal ini akan menyebabkan perpecahan, ketika akar akan menggantikan tempatnya dan dua paruh subpohon akan terpisah. Tempat untuk kunci yang dilewati akan aman saat kita melewati kunci yang lebih besar dan dapat diisi nanti.

Ini kode (semu) yang hampir berfungsi, array perlu diurutkan:

PushArray(BTree bTree, int d, key[] Array)
{
    List<int> counters = new List<int>{0};
    //skip list will contain numbers of nodes to skip 
    //after filling node of some order in half
    List<int> skip  = new List<int>();
    List<Pair<int,int>> skipList = List<Pair<int,int>>();

    int i = -1;
    while(true)
    {     
       int order = 0;
       while(counters[order] == d) order += 1;
       for(int j = order - 1; j >= 0; j--) counters[j] = 0;

       if (counters.Lenght <= order + 1) counters.Add(0);
       counters[order] += 1;

       if (skip.Count <= order)
              skip.Add(i + 2);    
       if (order > 0)
           skipList.Add({i,order}); //list of skipped parts that will be needed later
       i += skip[order];

       if (i > N) break;

       bTree.Push(Array[i]);
    }

    //now we need to add all skipped keys in correct order
    foreach(Pair<int,int> p in skipList)
    {
        for(int i = p.2; i > 0; i--)
            PushArray(bTree, d, Array.SubArray(p.1 + skip[i - 1], skip[i] -1))
    }
}

Contoh:

Berikut adalah bagaimana angka dan kunci penghitung yang sesuai harus diatur untuk d = 2 saat pertama kali melewati array. Saya menandai kunci yang dimasukkan ke dalam B-Tree selama lintasan pertama (sebelum loop dengan rekursi) dengan 'o' dan dilewati dengan 'x'.

                                                              24
        4         9             14             19                            29 
0 1 2 3   5 6 7 8   10 11 12 13    15 16 17 18    20 21 22 23    25 26 27 28    30 ...
o o x x o o o x x o  o  o  x  x  x  x  x  x  x  x  x  x  x  x  o  o  o  x  x  o  o ...
1 2     0 1 2     0  1  2                                      0  1  2        0  1 ...
0 0     1 1 1     2  2  2                                      0  0  0        1  1 ...
0 0     0 0 0     0  0  0                                      1  1  1        1  1 ...
skip[0] = 1 
skip[1] = 3 
skip[2] = 13

Karena kita tidak mengulangi kunci yang dilewati, kita memiliki kompleksitas waktu O(n) tanpa menambahkan ke B-Tree itu sendiri dan untuk array yang diurutkan;

Dalam formulir ini mungkin tidak jelas cara kerjanya ketika tidak ada cukup kunci untuk mengisi paruh kedua node setelah blok yang dilewati tetapi kita juga dapat menghindari melewatkan semua kunci lewati[order] jika total panjang array kurang dari ~ i + 2 * lewati[pesanan] dan lewati untuk kunci lewati[pesanan - 1] sebagai gantinya, string tersebut setelah mengubah penghitung tetapi sebelum mengubah variabel i mungkin ditambahkan:

while(order > 0 && i + 2*skip[order] > N) --order;

itu akan menjadi benar karena jika jumlah total kunci pada level saat ini kurang atau sama dengan 3*d, kunci tersebut masih dibagi dengan benar jika ditambahkan dalam urutan asli. Hal ini akan menyebabkan penataan ulang kunci yang sedikit berbeda antara dua node terakhir pada tingkat tertentu, namun tidak akan melanggar persyaratan yang dijelaskan, dan mungkin akan membuat perilaku lebih mudah dipahami.

Mungkin masuk akal untuk menemukan beberapa animasi dan melihat cara kerjanya, berikut adalah urutan yang harus dihasilkan pada rentang 0..29: 0 1 4 5 6 9 10 11 24 25 26 29 /akhir lintasan pertama< /em>/ 2 3 7 8 14 15 16 19 20 21 12 13 17 18 22 23 27 28 masukkan deskripsi gambar di sini

person Lurr    schedule 03.08.2014

Algoritme di bawah ini mencoba menyiapkan urutan kunci sehingga Anda tidak memerlukan tenaga atau bahkan pengetahuan tentang prosedur penyisipan. Satu-satunya asumsi adalah bahwa node pohon yang terlalu penuh akan terbelah di tengah atau pada posisi elemen yang terakhir disisipkan, jika tidak, pohon-B dapat dianggap sebagai kotak hitam.

Caranya adalah dengan memicu pemisahan node secara terkendali. Pertama, Anda mengisi sebuah node dengan tepat, separuh kiri dengan kunci-kunci yang dimiliki bersama dan separuh kanan dengan rentang kunci lain yang dimiliki bersama. Terakhir, Anda memasukkan kunci yang berada di antara dua rentang tersebut tetapi tidak termasuk dalam keduanya; kedua subrentang dipecah menjadi node terpisah dan kunci yang terakhir dimasukkan berakhir di node induk. Setelah pemisahan dengan cara ini Anda dapat mengisi sisa kedua node anak untuk membuat pohon sekompak mungkin. Ini juga berfungsi untuk node induk yang memiliki lebih dari dua node anak, cukup ulangi trik ini dengan salah satu node anak hingga jumlah node anak yang diinginkan tercipta. Di bawah ini, saya menggunakan apa yang secara konseptual merupakan simpul anak paling kanan sebagai "tempat pemisahan" (langkah 5 dan 6.1).

Terapkan trik pemisahan secara rekursif, dan semua elemen akan berada di tempat idealnya (yang bergantung pada jumlah elemen). Saya yakin algoritma di bawah ini menjamin bahwa tinggi pohon selalu minimal dan semua node kecuali root dibuat semaksimal mungkin. Namun, seperti yang mungkin Anda bayangkan, sulit untuk memastikan sepenuhnya tanpa benar-benar menerapkan dan mengujinya secara menyeluruh. Saya telah mencobanya di atas kertas dan saya merasa yakin bahwa algoritma ini, atau sesuatu yang sangat mirip, akan berhasil.

Pohon tersirat T dengan faktor percabangan maksimum M.

Prosedur teratas dengan kunci dengan panjang N:

  1. Urutkan kunci.
  2. Setel tinggi pohon minimal ke ceil(log(N+1)/log(M)).
  3. Panggil insert-chunk dengan chunk = kunci dan H = minimal-tree-height.

Prosedur insert-chunk dengan chunk dengan panjang L, tinggi subpohon H:

  1. If H is equal to 1:
    1. Insert all keys from the chunk into T
    2. Segera kembali.
  2. Tetapkan ukuran subchunk ideal S ke pow(M, H - 1).
  3. Tetapkan jumlah subpohon T menjadi ceil((L + 1) / S).
  4. Tetapkan ukuran subchunk sebenarnya S' ke ceil((L + 1) / T).
  5. Panggil insert-chunk secara rekursif dengan chunk' = kunci lantai terakhir((S - 1) / 2) dari chunk dan H' = H - 1.
  6. For each of the ceil(L / S') subchunks (of size S') except for the last with index I:
    1. Recursively call insert-chunk with chunk' = the first ceil((S - 1) / 2) keys of subchunk I and H' = H - 1.
    2. Masukkan kunci terakhir dari subchunk I ke dalam T (penyisipan ini sengaja memicu pemisahan).
    3. Panggil insert-chunk secara rekursif dengan chunk' = sisa kunci subchunk I (jika ada) dan H' = H - 1.
  7. Panggil insert-chunk secara rekursif dengan chunk' = kunci yang tersisa dari subchunk terakhir dan H' = H - 1.

Perhatikan bahwa prosedur rekursif dipanggil dua kali untuk setiap subpohon; tidak apa-apa, karena panggilan pertama selalu membuat setengah subpohon terisi sempurna.

person Julian    schedule 31.07.2014

Berikut adalah cara yang akan menghasilkan ketinggian minimum di BST mana pun (termasuk pohon b):-

  1. mengurutkan susunan
  2. Katakanlah Anda dapat memiliki kunci m di pohon b
  3. Bagilah array secara rekursif dalam m+1 bagian yang sama menggunakan kunci m di induk.
  4. buat pohon anak dari n/(m+1) kunci yang diurutkan menggunakan rekursi.

contoh : -

m = 2 array = [1 2 3 4 5 6 7 8 9 10]

divide array into three parts :-

root = [4,8]

recursively solve :-

child1 = [1 2 3]

root1 = [2]

left1 = [1]

right1 = [3]

similarly for all childs solve recursively.
person Vikram Bhat    schedule 31.07.2014

Jadi apakah ini tentang mengoptimalkan prosedur pembuatan, atau mengoptimalkan pohon?

Anda dapat dengan jelas membuat B-Tree yang efisien secara maksimal dengan terlebih dahulu membuat Pohon Biner Seimbang penuh, lalu mengontrak node.

Pada tingkat mana pun dalam pohon biner, kesenjangan angka antara dua node berisi semua angka di antara kedua nilai tersebut menurut definisi pohon biner, dan ini kurang lebih merupakan definisi B-Tree. Anda cukup mulai mengontrak divisi pohon biner menjadi node B-Tree. Karena pohon biner diseimbangkan berdasarkan konstruksi, jarak antar node pada level yang sama selalu berisi jumlah node yang sama (dengan asumsi pohon terisi). Dengan demikian BTree yang dibangun dijamin seimbang.

Dalam praktiknya, ini mungkin merupakan cara yang lambat untuk membuat BTree, namun hal ini tentu saja memenuhi kriteria Anda untuk membuat B-Tree yang optimal, dan literatur tentang cara membuat pohon biner seimbang sangat komprehensif.

=====================================

Dalam kasus Anda, di mana Anda mungkin mengambil versi "lebih baik" dari versi optimal yang dibangun, pernahkah Anda mempertimbangkan untuk sekadar mengubah jumlah node anak yang dapat dimiliki? Diagram Anda terlihat seperti pohon 2-3 klasik, tetapi sangat mungkin untuk memiliki pohon 3-4, atau pohon 3-5, yang berarti setiap node akan memiliki setidaknya tiga anak.

person phil_20686    schedule 06.08.2014
comment
Saya tidak tahu apakah 3-3 pohon itu mungkin? Ada yang tahu? - person phil_20686; 06.08.2014
comment
Anda tidak dapat mendukung 3-3 no 3-4 no 3-5, menggunakan algoritma B-tree klasik, hanya 3-6 atau 3-7. Saya tidak yakin apakah 3-3 pohon tidak dapat ditemukan sama sekali tetapi jelas Anda tidak dapat menyimpan n kunci di pohon jika setiap node berisi 3 kunci dan n tidak habis dibagi 3. Jadi, Anda memerlukan buffer tambahan untuk menyimpan kunci n%3 setidaknya. - person Lurr; 06.08.2014
comment
Ini bukan kendala yang sulit karena Anda dapat memiliki beberapa simpul daun yang setara dengan nol. misalnya tambahkan beberapa long.minvalue ke daftar, karena mereka selalu merupakan node terendah di pohon, Anda dapat dengan mudah melacaknya dan menghapusnya jika Anda perlu menambahkan node. 3-6 dan 3-7 lebih nyaman karena Anda menghindari komplikasi tersebut. Masalah dengan 3-3 adalah penyeimbangan ulang harus terjadi setiap kali sebuah node dihapus. - person phil_20686; 06.08.2014

Pertanyaan Anda adalah tentang optimasi btree. Kecil kemungkinan Anda melakukan ini hanya untuk bersenang-senang. Jadi saya hanya bisa berasumsi bahwa Anda ingin mengoptimalkan akses data - mungkin sebagai bagian dari pemrograman database atau sesuatu seperti ini. Anda menulis: "Saat mencari BTree, halaman tersebut berdasarkan permintaan dari disk ke memori", yang berarti Anda tidak memiliki cukup memori untuk melakukan cache apa pun atau Anda memiliki kebijakan untuk menggunakan memori sesedikit mungkin. Apa pun alasannya, hal ini mungkin menjadi penyebab utama mengapa jawaban atas pertanyaan Anda tidak akan memuaskan. Izinkan saya menjelaskan alasannya.

Dalam hal optimalisasi akses data, memori adalah teman Anda. Tidak masalah jika Anda melakukan optimasi baca atau tulis, Anda memerlukan memori. Segala jenis optimasi tulis selalu bekerja dengan asumsi bahwa ia dapat membaca informasi dengan cepat (dari memori) - penyortiran memerlukan data. Jika Anda tidak memiliki cukup memori untuk optimasi baca, Anda tidak akan memiliki memori untuk optimasi tulis juga.

Segera setelah Anda bersedia menerima setidaknya beberapa penggunaan memori, Anda dapat memikirkan kembali pernyataan Anda "Saat mencari BTree, halaman tersebut di-page berdasarkan permintaan dari disk ke memori", yang memberikan ruang untuk menyeimbangkan antara optimasi baca dan tulis. BTREE yang dioptimalkan secara maksimal adalah optimasi tulis yang dimaksimalkan. Dalam sebagian besar skenario akses data, saya tahu Anda mendapatkan tulisan pada 10-100 kali pembacaan. Artinya, optimasi tulis yang dimaksimalkan kemungkinan besar akan memberikan kinerja yang buruk dalam hal optimasi akses data. Itulah sebabnya database menerima siklus restrukturisasi, pemborosan ruang utama, pohon yang tidak seimbang, dan hal-hal seperti itu...

person Quicker    schedule 05.08.2014