-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
240 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
pub mod node; | ||
pub mod tree; | ||
|
||
pub mod constants { | ||
pub const BF: i32 = 2; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
// This is an attempt at an implementation for an AVL tree: | ||
// | ||
// ```rust | ||
// struct AvlTree<K, V> { | ||
// height: usize, | ||
// root: Option<Box<Node<K, V, height>>> | ||
// } | ||
// | ||
// struct Node<K, V, height: usize> { | ||
// key: K, | ||
// val: V, | ||
// parent: Option<(NonNull<Node<K, V, height + 1>>, u16)> | ||
// left: Option<(NonNull<Node<K, V, height - 1>>, u16)> | ||
// right: Option<(NonNull<Node<K, V, height - 1>>, u16)> | ||
// height: usize | ||
// } | ||
// ``` | ||
// | ||
// This implementation of an AVL Tree borrows heavily from the rust | ||
// alloc::collections::btree implementation, but contains significant differences. | ||
// In particular, this AVL Tree does not store arrays of keys and values, | ||
// instead preferring that each node contains a single value. | ||
// | ||
// TODO(@ielm) | ||
// [ ] - Node should be renamed to InternalNode | ||
// [ ] - Create a LeadNode variant | ||
// [ ] - Make InternalNode & NodeLeaf private | ||
// [ ] - Create a public NodeRef | ||
|
||
#![allow(dead_code)] | ||
#![allow(clippy::option_map_unit_fn)] | ||
|
||
use std::cmp::Ordering; | ||
use std::ptr::NonNull; | ||
|
||
/// `OptNode` is a type alias for `Option<NonNull<Node<K, V>>>`. | ||
/// | ||
/// It represents an optional reference to a `Node` in the AVL tree, where `None` | ||
/// indicates the absence of a node, and `Some(NonNull<Node<K, V>>)` represents | ||
/// a non-null pointer to a `Node` instance. | ||
/// | ||
/// The `NonNull` wrapper ensures that the pointer is always non-null. | ||
/// | ||
/// # Type Parameters | ||
/// | ||
/// - `K`: The type of the keys in the AVL tree. It must implement the `Ord` trait. | ||
/// - `V`: The type of the values associated with the keys in the AVL tree. | ||
pub type OptNode<K, V> = Option<NonNull<Node<K, V>>>; | ||
|
||
/// `Node` represents a node in the AVL tree. | ||
/// | ||
/// Each node contains a key of type `K`, a value of type `V`, and references to | ||
/// its parent node, left child, and right child. The node also stores its height, | ||
/// which is used to maintain the balance of the AVL tree. | ||
/// | ||
/// # Type Parameters | ||
/// | ||
/// - `K`: The type of the key stored in the node. It must implement the `Ord` trait | ||
/// for comparison. | ||
/// - `V`: The type of the value associated with the key in the node. | ||
/// | ||
/// # Fields | ||
/// | ||
/// - `key`: The key stored in the node, of type `K`. | ||
/// - `value`: The value associated with the key, of type `V`. | ||
/// - `parent`: An optional reference to the parent node, represented by `OptNode<K, V>`. | ||
/// - `left`: An optional reference to the left child node, represented by `OptNode<K, V>`. | ||
/// - `right`: An optional reference to the right child node, represented by `OptNode<K, V>`. | ||
/// - `height`: The height of the node, used for maintaining the balance of the AVL tree. | ||
/// It is of type `i32`. | ||
#[derive(Debug)] | ||
pub struct Node<K: Ord, V> { | ||
key: K, | ||
value: V, | ||
parent: OptNode<K, V>, | ||
left: OptNode<K, V>, | ||
right: OptNode<K, V>, | ||
height: usize, | ||
} | ||
|
||
impl<K: Ord, V> Node<K, V> { | ||
fn new(key: K, value: V) -> Self { | ||
Node { | ||
key, | ||
value, | ||
parent: None, | ||
left: None, | ||
right: None, | ||
height: 1, | ||
} | ||
} | ||
|
||
#[inline] | ||
fn get_parent(node: OptNode<K, V>) -> OptNode<K, V> { | ||
node.as_ref().and_then(|n| unsafe { (*n.as_ptr()).parent }) | ||
} | ||
|
||
#[inline] | ||
fn set_parent(child: OptNode<K, V>, parent: OptNode<K, V>) { | ||
if parent.is_none() { | ||
Node::set_parent(child, None); | ||
} else { | ||
let ordering = Node::order(parent, child); | ||
|
||
if let Some(o) = ordering { | ||
match o { | ||
Ordering::Less => Node::set_right(parent, child), | ||
Ordering::Greater => Node::set_left(parent, child), | ||
Ordering::Equal => { | ||
// Duplicate keys are not allowed. | ||
// TODO(@ielm) - handle error here? | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[inline] | ||
fn get_left(node: OptNode<K, V>) -> OptNode<K, V> { | ||
node.as_ref().and_then(|n| unsafe { (*n.as_ptr()).left }) | ||
} | ||
|
||
#[inline] | ||
fn set_left(node: OptNode<K, V>, left: OptNode<K, V>) { | ||
node.as_ref().map(|n| unsafe { (*n.as_ptr()).left = left }); | ||
left.as_ref() | ||
.map(|l| unsafe { (*l.as_ptr()).parent = node }); | ||
} | ||
|
||
#[inline] | ||
fn get_right(node: OptNode<K, V>) -> OptNode<K, V> { | ||
node.as_ref().and_then(|n| unsafe { (*n.as_ptr()).right }) | ||
} | ||
|
||
#[inline] | ||
fn set_right(node: OptNode<K, V>, right: OptNode<K, V>) { | ||
node.as_ref() | ||
.map(|n| unsafe { (*n.as_ptr()).right = right }); | ||
right | ||
.as_ref() | ||
.map(|r| unsafe { (*r.as_ptr()).parent = node }); | ||
} | ||
|
||
#[inline] | ||
fn order(n1: OptNode<K, V>, n2: OptNode<K, V>) -> Option<Ordering> { | ||
let n1_key = n1.as_ref().map(|n| unsafe { &(n.as_ref()).key }); | ||
let n2_key = n2.as_ref().map(|n| unsafe { &(n.as_ref()).key }); | ||
n1_key.and_then(|n1k| n2_key.map(|n2k| n1k.cmp(n2k))) | ||
} | ||
|
||
#[inline] | ||
fn unlink(parent: OptNode<K, V>, child: OptNode<K, V>) { | ||
let ordering = Node::order(parent, child); | ||
|
||
if let Some(o) = ordering { | ||
match o { | ||
Ordering::Less => { | ||
Node::set_right(parent, None); | ||
Node::set_parent(child, None); | ||
} | ||
Ordering::Greater => { | ||
Node::set_left(parent, None); | ||
Node::set_parent(child, None); | ||
} | ||
Ordering::Equal => { | ||
// Duplicate keys are not allowed | ||
// TODO(@ielm) - Handle error here? | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[inline] | ||
fn get_height(node: OptNode<K, V>) -> usize { | ||
if node.is_none() { | ||
0 | ||
} else { | ||
node.as_ref() | ||
.map(|n| unsafe { (*n.as_ptr()).height }) | ||
.unwrap() | ||
} | ||
} | ||
|
||
#[inline] | ||
fn set_height(node: OptNode<K, V>, height: usize) { | ||
node.as_ref() | ||
.map_or_else(|| {}, |n| unsafe { (*n.as_ptr()).height = height }) | ||
} | ||
|
||
#[inline] | ||
fn update_height(node: OptNode<K, V>) { | ||
let height = std::cmp::max( | ||
Node::get_height(Node::get_left(node)), | ||
Node::get_height(Node::get_right(node)), | ||
) + 1; | ||
|
||
Node::set_height(node, height); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use super::node::{Node, OptNode}; | ||
use std::marker::PhantomData; | ||
|
||
/// An AVL tree is a self-balancing binary search tree that maintains the | ||
/// balance factor of each node between -1 and +1. | ||
/// | ||
/// The `AvlTree` struct represents an AVL tree with keys of type `K` and | ||
/// values of type `V`. The keys must implement the `Ord` trait for comparison. | ||
/// | ||
/// The tree automatically rebalances itself after insertions and deletions to | ||
/// ensure logarithmic time complexity for search, insertion, and deletion | ||
/// operations. | ||
/// | ||
/// # Type Parameters | ||
/// | ||
/// - `K`: The type of the keys in the AVL tree. It must implement the `Ord` trait. | ||
/// - `V`: The type of the values associated with the keys in the AVL tree. | ||
/// | ||
/// # Fields | ||
/// | ||
/// - `root`: The root node of the AVL tree, wrapped in an `OptNode` type alias. | ||
/// - `len`: The number of key-value pairs stored in the AVL tree. | ||
/// - `_marker`: A `PhantomData` marker used to express ownership and lifetime | ||
/// relationships between the `AvlTree` and the `Node` instances. | ||
pub struct AvlTree<K: Ord, V> { | ||
root: OptNode<K, V>, | ||
len: usize, | ||
_marker: PhantomData<Box<Node<K, V>>>, | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
// Placeholder for ielm's tree data structures | ||
pub mod avl_tree; | ||
|