This commit is contained in:
bronku 2025-12-06 20:26:29 +01:00
parent be9e685b94
commit 4d3fdcb356
6 changed files with 397 additions and 153 deletions

203
Cargo.lock generated
View file

@ -2,6 +2,209 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 4 version = 4
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"bincode_derive",
"serde",
"unty",
]
[[package]]
name = "bincode_derive"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
dependencies = [
"virtue",
]
[[package]] [[package]]
name = "btree" name = "btree"
version = "0.1.0" version = "0.1.0"
dependencies = [
"bincode",
"rand",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "getrandom"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasip2",
]
[[package]]
name = "libc"
version = "0.2.178"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rand"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom",
]
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "2.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "virtue"
version = "0.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
[[package]]
name = "wasip2"
version = "1.0.1+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wit-bindgen"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
[[package]]
name = "zerocopy"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View file

@ -4,3 +4,5 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
bincode = "2.0.1"
rand = "0.9.2"

63
src/btree.rs Normal file
View file

@ -0,0 +1,63 @@
use crate::node::Node;
use crate::record::Record;
#[derive(Debug)]
pub struct BTree {
root: Option<Box<Node>>,
}
impl BTree {
pub fn new() -> Self {
BTree { root: None }
}
pub fn insert(&mut self, rec: Record) {
match &mut self.root {
None => {
let mut root = Box::new(Node::new(true));
root.keys.push(rec);
self.root = Some(root);
}
Some(root) => {
if root.is_full() {
let mut new_root = Box::new(Node::new(false));
let old_root = self.root.take().unwrap();
new_root.children.push(old_root);
new_root.split_child(0);
new_root.insert_non_full(rec);
self.root = Some(new_root);
} else {
root.insert_non_full(rec);
}
}
}
}
pub fn search(&self, key: i32) -> Option<Record> {
match &self.root {
None => None,
Some(root) => root.search(key),
}
}
pub fn print_tree(&self) {
if let Some(root) = &self.root {
Self::print_node(root, 0);
} else {
println!("Empty tree");
}
}
fn print_node(node: &Node, level: usize) {
print!("{}", " ".repeat(level));
let key_values: Vec<i32> = node.keys.iter().map(|r| r.key).collect();
println!("Keys: {:?}", key_values);
if !node.is_leaf {
for child in &node.children {
Self::print_node(child, level + 1);
}
}
}
}

View file

@ -1,166 +1,27 @@
const MIN_DEGREE: usize = 3; // Minimum degree (minimum children per node) mod btree;
mod node;
mod record;
#[derive(Debug)] use btree::BTree;
pub struct BTree<K: Ord> { use record::Record;
root: Option<Box<Node<K>>>,
}
#[derive(Debug)]
struct Node<K: Ord> {
keys: Vec<K>,
children: Vec<Box<Node<K>>>,
is_leaf: bool,
}
impl<K: Ord> Node<K> {
fn new(is_leaf: bool) -> Self {
Node {
keys: Vec::new(),
children: Vec::new(),
is_leaf,
}
}
fn is_full(&self) -> bool {
self.keys.len() >= 2 * MIN_DEGREE - 1
}
fn search(&self, key: &K) -> bool {
let mut i = 0;
while i < self.keys.len() && key > &self.keys[i] {
i += 1;
}
if i < self.keys.len() && key == &self.keys[i] {
return true;
}
if self.is_leaf {
return false;
}
self.children[i].search(key)
}
fn insert_non_full(&mut self, key: K) {
let mut i = self.keys.len();
if self.is_leaf {
self.keys.push(key);
i = self.keys.len() - 1;
while i > 0 && self.keys[i] < self.keys[i - 1] {
self.keys.swap(i, i - 1);
i -= 1;
}
} else {
while i > 0 && key < self.keys[i - 1] {
i -= 1;
}
if self.children[i].is_full() {
self.split_child(i);
if key > self.keys[i] {
i += 1;
}
}
self.children[i].insert_non_full(key);
}
}
fn split_child(&mut self, i: usize) {
let t = MIN_DEGREE;
let full_child = &mut self.children[i];
let mut new_child = Box::new(Node::new(full_child.is_leaf));
// Move the second half of keys to new child
new_child.keys = full_child.keys.split_off(t);
let median = full_child.keys.pop().unwrap();
// Move the second half of children if not a leaf
if !full_child.is_leaf {
new_child.children = full_child.children.split_off(t);
}
// Insert median key and new child into parent
self.keys.insert(i, median);
self.children.insert(i + 1, new_child);
}
}
impl<K: Ord + std::fmt::Debug> BTree<K> {
pub fn new() -> Self {
BTree { root: None }
}
pub fn insert(&mut self, key: K) {
match &mut self.root {
None => {
let mut root = Box::new(Node::new(true));
root.keys.push(key);
self.root = Some(root);
}
Some(root) => {
if root.is_full() {
let mut new_root = Box::new(Node::new(false));
let old_root = self.root.take().unwrap();
new_root.children.push(old_root);
new_root.split_child(0);
new_root.insert_non_full(key);
self.root = Some(new_root);
} else {
root.insert_non_full(key);
}
}
}
}
pub fn search(&self, key: &K) -> bool {
match &self.root {
None => false,
Some(root) => root.search(key),
}
}
pub fn print_tree(&self) {
if let Some(root) = &self.root {
Self::print_node(root, 0);
} else {
println!("Empty tree");
}
}
fn print_node(node: &Node<K>, level: usize)
where
K: std::fmt::Debug,
{
print!("{}", " ".repeat(level));
println!("Keys: {:?}", node.keys);
if !node.is_leaf {
for child in &node.children {
Self::print_node(child, level + 1);
}
}
}
}
fn main() { fn main() {
let mut btree = BTree::new(); let mut btree = BTree::new();
// Insert some values let mut values: Vec<i32> = vec![];
let values = vec![10, 20, 5, 6, 12, 30, 7, 17, 3, 16, 21, 22, 23, 24];
println!("Inserting values: {:?}", values); println!("Inserting values");
for val in values { for _ in 0..10 {
btree.insert(val); let rec = Record::random();
values.push(rec.key);
btree.insert(rec);
} }
println!("\nB-Tree structure:"); println!("\nB-Tree structure:");
btree.print_tree(); btree.print_tree();
// Search for some values
println!("\nSearch results:"); println!("\nSearch results:");
println!("Search for 6: {}", btree.search(&6)); println!("Search for 6: {:?}", btree.search(values[0]));
println!("Search for 15: {}", btree.search(&15)); println!("Search for 15: {:?}", btree.search(values[4]));
println!("Search for 21: {}", btree.search(&21)); println!("Search for 21: {:?}", btree.search(100));
} }

85
src/node.rs Normal file
View file

@ -0,0 +1,85 @@
use crate::record::Record;
const MIN_DEGREE: usize = 3; // Minimum degree (minimum children per node)
#[derive(Debug)]
pub struct Node {
pub keys: Vec<Record>,
pub children: Vec<Box<Node>>,
pub is_leaf: bool,
}
impl Node {
pub fn new(is_leaf: bool) -> Self {
Node {
keys: Vec::new(),
children: Vec::new(),
is_leaf,
}
}
pub fn is_full(&self) -> bool {
self.keys.len() >= 2 * MIN_DEGREE - 1
}
pub fn search(&self, key: i32) -> Option<Record> {
let mut i = 0;
while i < self.keys.len() && key > self.keys[i].key {
i += 1;
}
if i < self.keys.len() && key == self.keys[i].key {
return Some(self.keys[i]);
}
if self.is_leaf {
return None;
}
self.children[i].search(key)
}
pub fn insert_non_full(&mut self, rec: Record) {
let mut i = self.keys.len();
if self.is_leaf {
self.keys.push(rec);
i = self.keys.len() - 1;
while i > 0 && self.keys[i] < self.keys[i - 1] {
self.keys.swap(i, i - 1);
i -= 1;
}
} else {
while i > 0 && rec < self.keys[i - 1] {
i -= 1;
}
if self.children[i].is_full() {
self.split_child(i);
if rec > self.keys[i] {
i += 1;
}
}
self.children[i].insert_non_full(rec);
}
}
pub fn split_child(&mut self, i: usize) {
let t = MIN_DEGREE;
let full_child = &mut self.children[i];
let mut new_child = Box::new(Node::new(full_child.is_leaf));
// Move the second half of keys to new child
new_child.keys = full_child.keys.split_off(t);
let median = full_child.keys.pop().unwrap();
// Move the second half of children if not a leaf
if !full_child.is_leaf {
new_child.children = full_child.children.split_off(t);
}
// Insert median key and new child into parent
self.keys.insert(i, median);
self.children.insert(i + 1, new_child);
}
}

30
src/record.rs Normal file
View file

@ -0,0 +1,30 @@
use bincode::{Decode, Encode};
use rand::Rng;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Encode, Decode)]
pub struct Record {
pub key: i32,
pub a: [i32; 5],
pub x: i32,
}
impl Record {
pub fn new(a: [i32; 5], x: i32) -> Self {
let mut key: i32 = 0;
let mut x_n: i32 = 1;
for i in 0..5 {
// rust is annyoing like that, and panics on overflow in arithmetic operations
key = key.wrapping_add(a[i].wrapping_mul(x_n));
x_n = x_n.wrapping_mul(x);
}
Self { key, a, x }
}
pub fn random() -> Self {
let mut rng = rand::rng();
let a = rng.random::<[i32; 5]>();
let x = rng.random::<i32>();
Self::new(a, x)
}
}