init zad3
This commit is contained in:
parent
64bf67e67d
commit
cec8293382
6 changed files with 672 additions and 0 deletions
1
lab4/zad3/.gitignore
vendored
Normal file
1
lab4/zad3/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target
|
87
lab4/zad3/Cargo.lock
generated
Normal file
87
lab4/zad3/Cargo.lock
generated
Normal file
|
@ -0,0 +1,87 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "libgen"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libtree"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "zad3"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libgen",
|
||||
"libtree",
|
||||
]
|
8
lab4/zad3/Cargo.toml
Normal file
8
lab4/zad3/Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "zad3"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libgen = { path = "../../libgen" }
|
||||
libtree = { path = "../../libtree" }
|
34
lab4/zad3/src/main.rs
Normal file
34
lab4/zad3/src/main.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
use libgen::{gen_asc, gen_rand};
|
||||
use libtree::RedBlackTree;
|
||||
|
||||
fn main() {
|
||||
println!("1. insert 50 ascending; delete 50 random");
|
||||
let mut tree1 = RedBlackTree::new(50);
|
||||
|
||||
for i in gen_asc(50) {
|
||||
println!("insert {i}");
|
||||
tree1.insert(i);
|
||||
println!("{}", tree1);
|
||||
}
|
||||
|
||||
for i in gen_rand(50) {
|
||||
println!("delete {i}");
|
||||
tree1.delete(i);
|
||||
println!("{}", tree1);
|
||||
}
|
||||
|
||||
println!("2. insert 50 random; delete 50 random");
|
||||
let mut tree2 = RedBlackTree::new(50);
|
||||
|
||||
for i in gen_rand(50) {
|
||||
println!("insert {i}");
|
||||
tree2.insert(i);
|
||||
println!("{}", tree2);
|
||||
}
|
||||
|
||||
for i in gen_rand(50) {
|
||||
println!("delete {i}");
|
||||
tree2.delete(i);
|
||||
println!("{}", tree2);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
mod binary_search_tree;
|
||||
mod red_black_tree;
|
||||
|
||||
pub use binary_search_tree::*;
|
||||
pub use red_black_tree::*;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Stats {
|
||||
|
|
540
libtree/src/red_black_tree.rs
Normal file
540
libtree/src/red_black_tree.rs
Normal file
|
@ -0,0 +1,540 @@
|
|||
use std::{cmp::Ordering, fmt::Display, ptr};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum Colour { Red, Black }
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RedBlackTreeNode {
|
||||
key: u64,
|
||||
colour: Colour,
|
||||
left: RBT,
|
||||
right: RBT,
|
||||
parent: RBT,
|
||||
}
|
||||
|
||||
struct RBT(*mut RedBlackTreeNode);
|
||||
|
||||
impl Clone for RBT {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Copy for RBT {}
|
||||
|
||||
impl Ord for RBT {
|
||||
fn cmp(&self, other: &RBT) -> Ordering {
|
||||
unsafe { (*self.0).key.cmp(&(*other.0).key) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for RBT {
|
||||
fn partial_cmp(&self, other: &RBT) -> Option<Ordering> {
|
||||
unsafe { Some((*self.0).key.cmp(&(*other.0).key)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for RBT {
|
||||
fn eq(&self, other: &RBT) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for RBT {}
|
||||
|
||||
impl RBT {
|
||||
fn new(key: u64) -> Self {
|
||||
Self(Box::into_raw(Box::new(RedBlackTreeNode {
|
||||
key,
|
||||
colour: Colour::Black,
|
||||
left: Self::null(),
|
||||
right: Self::null(),
|
||||
parent: Self::null(),
|
||||
})))
|
||||
}
|
||||
|
||||
unsafe fn deep_clone(&self) -> Self {
|
||||
let mut node = Self::new((*self.0).key);
|
||||
if !self.left().is_null() {
|
||||
node.set_left(self.left().deep_clone());
|
||||
node.left().set_parent(node);
|
||||
}
|
||||
if !self.right().is_null() {
|
||||
node.set_right(self.right().deep_clone());
|
||||
node.right().set_parent(node);
|
||||
}
|
||||
node
|
||||
}
|
||||
|
||||
fn minimum(self) -> Self {
|
||||
let mut temp = self.clone();
|
||||
while !temp.left().is_null() {
|
||||
temp = temp.left();
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
fn set_colour(&mut self, colour: Colour) {
|
||||
if !self.is_null() {
|
||||
unsafe { (*self.0).colour = colour; }
|
||||
}
|
||||
}
|
||||
|
||||
fn colour(&self) -> Colour {
|
||||
match self.is_null() {
|
||||
true => Colour::Black,
|
||||
false => unsafe { (*self.0).colour }
|
||||
}
|
||||
}
|
||||
|
||||
fn set_parent(&mut self, parent: Self) {
|
||||
if !self.is_null() {
|
||||
unsafe { (*self.0).parent = parent; }
|
||||
}
|
||||
}
|
||||
|
||||
fn set_right(&mut self, right: Self) {
|
||||
if !self.is_null() {
|
||||
unsafe { (*self.0).right = right; }
|
||||
}
|
||||
}
|
||||
|
||||
fn set_left(&mut self, left: Self) {
|
||||
if !self.is_null() {
|
||||
unsafe { (*self.0).left = left; }
|
||||
}
|
||||
}
|
||||
|
||||
fn parent(&self) -> Self {
|
||||
match self.is_null() {
|
||||
true => Self::null(),
|
||||
false => unsafe { (*self.0).parent.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
fn right(&self) -> Self {
|
||||
match self.is_null() {
|
||||
true => Self::null(),
|
||||
false => unsafe { (*self.0).right.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
fn left(&self) -> Self {
|
||||
match self.is_null() {
|
||||
true => Self::null(),
|
||||
false => unsafe { (*self.0).left.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
fn null() -> Self {
|
||||
Self(ptr::null_mut())
|
||||
}
|
||||
|
||||
fn is_null(&self) -> bool {
|
||||
self.0.is_null()
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/66661638
|
||||
fn replace_nth_char_ascii(s: &mut str, idx: usize, newchar: char) {
|
||||
let s_bytes: &mut [u8] = unsafe { s.as_bytes_mut() };
|
||||
assert!(idx < s_bytes.len());
|
||||
assert!(s_bytes[idx].is_ascii());
|
||||
assert!(newchar.is_ascii());
|
||||
// we've made sure this is safe.
|
||||
s_bytes[idx] = newchar as u8;
|
||||
}
|
||||
|
||||
fn _print(&self, f: &mut std::fmt::Formatter<'_>, depth: usize, prefix: char, left_trace: &mut String, right_trace: &mut String) -> std::fmt::Result {
|
||||
if self.is_null() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if !self.left().is_null() {
|
||||
self.left()._print(f, depth + 1, '/', left_trace, right_trace)?;
|
||||
}
|
||||
if prefix == '/' {
|
||||
Self::replace_nth_char_ascii(left_trace, depth - 1, '|');
|
||||
}
|
||||
if prefix == '\\' {
|
||||
Self::replace_nth_char_ascii(right_trace, depth - 1, ' ');
|
||||
}
|
||||
if depth == 0 {
|
||||
write!(f, "-")?;
|
||||
}
|
||||
if depth > 0 {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
|
||||
|
||||
if depth > 0 {
|
||||
for i in 0..(depth - 1) {
|
||||
if left_trace.chars().nth(i).unwrap() == '|' || right_trace.chars().nth(i).unwrap() == '|' {
|
||||
write!(f, "| ")?;
|
||||
} else {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
write!(f, "{}-", prefix)?;
|
||||
}
|
||||
match self.colour() {
|
||||
Colour::Red => writeln!(f, "({})", unsafe { (*self.0).key })?,
|
||||
Colour::Black => writeln!(f, "[{}]", unsafe { (*self.0).key })?,
|
||||
}
|
||||
Self::replace_nth_char_ascii(left_trace, depth, ' ');
|
||||
|
||||
if !self.right().is_null() {
|
||||
Self::replace_nth_char_ascii(right_trace, depth, '|');
|
||||
self.right()._print(f, depth + 1, '\\', left_trace, right_trace)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RedBlackTree {
|
||||
root: RBT,
|
||||
pub size: usize,
|
||||
print_capacity: usize,
|
||||
}
|
||||
|
||||
impl Clone for RedBlackTree {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
let mut ret = RedBlackTree::new(self.print_capacity);
|
||||
ret.root = self.root.deep_clone();
|
||||
ret.size = self.size;
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RedBlackTree {
|
||||
pub fn new(print_capacity: usize) -> Self {
|
||||
Self {
|
||||
root: RBT::null(),
|
||||
size: 0,
|
||||
print_capacity,
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn rotate_left(&mut self, mut node: RBT) {
|
||||
let mut right = node.right();
|
||||
node.set_right(right.left());
|
||||
|
||||
if !right.left().is_null() {
|
||||
right.left().set_parent(node.clone());
|
||||
}
|
||||
|
||||
right.set_parent(node.parent());
|
||||
|
||||
if node == self.root {
|
||||
self.root = right.clone();
|
||||
} else if node == node.parent().left() {
|
||||
node.parent().set_left(right.clone());
|
||||
} else if node == node.parent().right() {
|
||||
node.parent().set_right(right.clone());
|
||||
}
|
||||
|
||||
right.set_left(node.clone());
|
||||
node.set_parent(right.clone());
|
||||
}
|
||||
|
||||
unsafe fn rotate_right(&mut self, mut node: RBT) {
|
||||
let mut left = node.left();
|
||||
node.set_left(left.right());
|
||||
|
||||
if !left.right().is_null() {
|
||||
left.right().set_parent(node.clone());
|
||||
}
|
||||
|
||||
left.set_parent(node.parent());
|
||||
|
||||
if node == self.root {
|
||||
self.root = left.clone();
|
||||
} else if node == node.parent().left() {
|
||||
node.parent().set_left(left.clone());
|
||||
} else if node == node.parent().right() {
|
||||
node.parent().set_right(left.clone());
|
||||
}
|
||||
|
||||
left.set_right(node.clone());
|
||||
node.set_parent(left.clone());
|
||||
}
|
||||
|
||||
unsafe fn insert_fixup(&mut self, mut node: RBT) {
|
||||
use Colour::*;
|
||||
|
||||
let mut parent;
|
||||
let mut grandparent;
|
||||
|
||||
while node.parent().colour() == Red {
|
||||
parent = node.parent();
|
||||
grandparent = parent.parent();
|
||||
|
||||
if parent == grandparent.left() {
|
||||
let mut uncle = grandparent.right();
|
||||
if !uncle.is_null() && uncle.colour() == Red {
|
||||
uncle.set_colour(Black);
|
||||
parent.set_colour(Black);
|
||||
grandparent.set_colour(Red);
|
||||
node = grandparent;
|
||||
continue;
|
||||
}
|
||||
|
||||
if parent.right() == node {
|
||||
self.rotate_left(parent);
|
||||
let temp = parent;
|
||||
parent = node;
|
||||
node = temp;
|
||||
}
|
||||
|
||||
parent.set_colour(Black);
|
||||
grandparent.set_colour(Red);
|
||||
self.rotate_right(grandparent);
|
||||
} else {
|
||||
let mut uncle = grandparent.left();
|
||||
if !uncle.is_null() && uncle.colour() == Red {
|
||||
uncle.set_colour(Black);
|
||||
parent.set_colour(Black);
|
||||
grandparent.set_colour(Black);
|
||||
node = grandparent;
|
||||
continue;
|
||||
}
|
||||
|
||||
if parent.left() == node {
|
||||
self.rotate_right(parent);
|
||||
let temp = parent;
|
||||
parent = node;
|
||||
node = temp;
|
||||
}
|
||||
|
||||
parent.set_colour(Black);
|
||||
grandparent.set_colour(Red);
|
||||
self.rotate_left(grandparent);
|
||||
}
|
||||
}
|
||||
self.root.set_colour(Black);
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: u64) {
|
||||
self.size += 1;
|
||||
let mut node = RBT::new(key);
|
||||
let mut y = RBT::null();
|
||||
let mut x = self.root;
|
||||
|
||||
while !x.is_null() {
|
||||
y = x;
|
||||
match node.cmp(&&mut x) {
|
||||
Ordering::Less => {
|
||||
x = x.left();
|
||||
}
|
||||
_ => {
|
||||
x = x.right();
|
||||
}
|
||||
};
|
||||
}
|
||||
node.set_parent(y);
|
||||
|
||||
if y.is_null() {
|
||||
self.root = node;
|
||||
} else {
|
||||
match node.cmp(&&mut y) {
|
||||
Ordering::Less => {
|
||||
y.set_left(node);
|
||||
}
|
||||
_ => {
|
||||
y.set_right(node);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
node.set_colour(Colour::Red);
|
||||
unsafe { self.insert_fixup(node); }
|
||||
}
|
||||
|
||||
fn find_node(&self, key: u64) -> RBT {
|
||||
if self.root.is_null() {
|
||||
return RBT::null();
|
||||
}
|
||||
let mut temp = &self.root;
|
||||
unsafe {
|
||||
loop {
|
||||
let next = match key.cmp(&(*temp.0).key) {
|
||||
Ordering::Less => &mut (*temp.0).left,
|
||||
Ordering::Greater => &mut (*temp.0).right,
|
||||
Ordering::Equal => return *temp,
|
||||
};
|
||||
if next.is_null() {
|
||||
break;
|
||||
}
|
||||
temp = next;
|
||||
}
|
||||
}
|
||||
|
||||
RBT::null()
|
||||
}
|
||||
|
||||
unsafe fn delete_fixup(&mut self, mut node: RBT, mut parent: RBT) {
|
||||
use Colour::*;
|
||||
|
||||
let mut other;
|
||||
while node != self.root && node.colour() == Black {
|
||||
if parent.left() == node {
|
||||
other = parent.right();
|
||||
|
||||
if other.colour() == Red {
|
||||
other.set_colour(Black);
|
||||
parent.set_colour(Red);
|
||||
self.rotate_left(parent);
|
||||
other = parent.right();
|
||||
}
|
||||
|
||||
if other.left().colour() == Black && other.right().colour() == Black {
|
||||
other.set_colour(Red);
|
||||
node = parent;
|
||||
parent = node.parent();
|
||||
} else {
|
||||
if other.right().colour() == Black {
|
||||
other.left().set_colour(Black);
|
||||
other.set_colour(Red);
|
||||
self.rotate_right(other);
|
||||
other = parent.right();
|
||||
}
|
||||
|
||||
other.set_colour(parent.colour());
|
||||
parent.set_colour(Black);
|
||||
other.right().set_colour(Black);
|
||||
self.rotate_left(parent);
|
||||
node = self.root;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
other = parent.left();
|
||||
|
||||
if other.colour() == Red {
|
||||
other.set_colour(Black);
|
||||
parent.set_colour(Red);
|
||||
self.rotate_right(parent);
|
||||
other = parent.left();
|
||||
}
|
||||
|
||||
if other.left().colour() == Black && other.right().colour() == Black {
|
||||
other.set_colour(Red);
|
||||
node = parent;
|
||||
parent = node.parent();
|
||||
} else {
|
||||
if other.left().colour() == Black {
|
||||
other.right().set_colour(Black);
|
||||
other.set_colour(Red);
|
||||
self.rotate_left(other);
|
||||
other = parent.left();
|
||||
}
|
||||
|
||||
other.set_colour(parent.colour());
|
||||
parent.set_colour(Black);
|
||||
other.left().set_colour(Black);
|
||||
self.rotate_right(parent);
|
||||
node = self.root;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.set_colour(Black);
|
||||
}
|
||||
|
||||
unsafe fn delete_node(&mut self, node: RBT) -> u64 {
|
||||
let mut child;
|
||||
let mut parent;
|
||||
let color;
|
||||
|
||||
self.size -= 1;
|
||||
|
||||
if !node.left().is_null() && !node.right().is_null() {
|
||||
let mut replace = node.right().minimum();
|
||||
if node == self.root {
|
||||
self.root = replace;
|
||||
} else {
|
||||
if node.parent().left() == node {
|
||||
node.parent().set_left(replace);
|
||||
} else {
|
||||
node.parent().set_right(replace);
|
||||
}
|
||||
}
|
||||
|
||||
child = replace.right();
|
||||
parent = replace.parent();
|
||||
color = replace.colour();
|
||||
if parent == node {
|
||||
parent = replace;
|
||||
} else {
|
||||
if !child.is_null() {
|
||||
child.set_parent(parent);
|
||||
}
|
||||
parent.set_left(child);
|
||||
replace.set_right(node.right());
|
||||
node.right().set_parent(replace);
|
||||
}
|
||||
|
||||
replace.set_parent(node.parent());
|
||||
replace.set_colour(node.colour());
|
||||
replace.set_left(node.left());
|
||||
node.left().set_parent(replace);
|
||||
|
||||
if color == Colour::Black {
|
||||
self.delete_fixup(child, parent);
|
||||
}
|
||||
|
||||
let obj = Box::from_raw(node.0);
|
||||
return obj.key;
|
||||
}
|
||||
|
||||
if !node.left().is_null() {
|
||||
child = node.left();
|
||||
} else {
|
||||
child = node.right();
|
||||
}
|
||||
|
||||
parent = node.parent();
|
||||
color = node.colour();
|
||||
if !child.is_null() {
|
||||
child.set_parent(parent);
|
||||
}
|
||||
|
||||
if self.root == node {
|
||||
self.root = child
|
||||
} else {
|
||||
if parent.left() == node {
|
||||
parent.set_left(child);
|
||||
} else {
|
||||
parent.set_right(child);
|
||||
}
|
||||
}
|
||||
|
||||
if color == Colour::Black {
|
||||
self.delete_fixup(child, parent);
|
||||
}
|
||||
|
||||
let obj = Box::from_raw(node.0);
|
||||
|
||||
obj.key
|
||||
}
|
||||
|
||||
pub fn delete(&mut self, key: u64) -> bool {
|
||||
let node = self.find_node(key);
|
||||
|
||||
if node.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsafe { self.delete_node(node); }
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RedBlackTree {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.root._print(f, 0, '-', &mut " ".repeat(self.print_capacity), &mut " ".repeat(self.print_capacity))
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue