got binary tree insert working need to isolate traversal and setup delete
This commit is contained in:
parent
74d3013a2e
commit
6067c1bebe
8 changed files with 424 additions and 225 deletions
194
src/binary_tree.rs
Normal file
194
src/binary_tree.rs
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
use std::collections::VecDeque;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::BinaryTree;
|
||||
|
||||
#[test]
|
||||
fn create_new_tree() {
|
||||
let tree = BinaryTree::new(1);
|
||||
|
||||
assert_eq!(tree.value, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_left() {
|
||||
let tree = BinaryTree::new(1).left(BinaryTree::new(2));
|
||||
|
||||
if let Some(node) = tree.left {
|
||||
assert_eq!(node.value, 2);
|
||||
}
|
||||
|
||||
assert_eq!(tree.right, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_right() {
|
||||
let tree = BinaryTree::new(1).right(BinaryTree::new(2));
|
||||
|
||||
if let Some(node) = tree.right {
|
||||
assert_eq!(node.value, 2);
|
||||
}
|
||||
|
||||
assert_eq!(tree.left, None);
|
||||
}
|
||||
#[test]
|
||||
fn insert() {
|
||||
let mut tree = BinaryTree::new(1);
|
||||
tree.insert(2);
|
||||
tree.insert(3);
|
||||
tree.insert(4);
|
||||
tree.insert(5);
|
||||
|
||||
assert_eq!(
|
||||
tree,
|
||||
BinaryTree::new(1)
|
||||
.left(BinaryTree::new(2).left(BinaryTree::new(4)).right(BinaryTree::new(5)))
|
||||
.right(BinaryTree::new(3))
|
||||
);
|
||||
|
||||
tree.insert(6);
|
||||
|
||||
assert_eq!(
|
||||
tree,
|
||||
BinaryTree::new(1)
|
||||
.left(BinaryTree::new(2).left(BinaryTree::new(4)).right(BinaryTree::new(5)))
|
||||
.right(BinaryTree::new(3).left(BinaryTree::new(6)))
|
||||
)
|
||||
}
|
||||
#[test]
|
||||
fn create_new_tree_with_from() {
|
||||
// `BinaryTree::from` takes in a reference of an array because borrowing is sufficient
|
||||
let tree = BinaryTree::from(&[1, 2, 3, 4, 5, 6]);
|
||||
|
||||
assert_eq!(
|
||||
tree,
|
||||
BinaryTree::new(1)
|
||||
.left(BinaryTree::new(2).left(BinaryTree::new(4)).right(BinaryTree::new(5)))
|
||||
.right(BinaryTree::new(3).left(BinaryTree::new(6)))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A binary tree data structure.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct BinaryTree<T> {
|
||||
/// The value stored in the node.
|
||||
pub value: T,
|
||||
/// The left child of the node.
|
||||
pub left: Option<Box<BinaryTree<T>>>,
|
||||
/// The right child of the node.
|
||||
pub right: Option<Box<BinaryTree<T>>>,
|
||||
}
|
||||
|
||||
impl<T> BinaryTree<T>
|
||||
where
|
||||
T: Copy + PartialEq,
|
||||
{
|
||||
/// Creates a new binary tree node with the given value.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `value` - The value to store in the node.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A new binary tree node with the given value and no children.
|
||||
pub fn new(value: T) -> Self {
|
||||
BinaryTree {
|
||||
value,
|
||||
left: None,
|
||||
right: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts a new value into the binary tree.
|
||||
///
|
||||
/// The value is inserted into the first available position in the tree,
|
||||
/// following a breadth-first traversal.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `new_value` - The value to insert into the tree.
|
||||
pub fn insert(&mut self, new_value: T) {
|
||||
let mut queue: VecDeque<&mut BinaryTree<T>> = VecDeque::new();
|
||||
queue.push_front(self);
|
||||
|
||||
loop {
|
||||
let BinaryTree {
|
||||
ref mut left,
|
||||
ref mut right,
|
||||
..
|
||||
} = queue.pop_back().unwrap();
|
||||
|
||||
match left {
|
||||
Some(node) => {
|
||||
queue.push_front(node);
|
||||
}
|
||||
None => {
|
||||
*left = Some(Box::new(BinaryTree::new(new_value)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
match right {
|
||||
Some(node) => {
|
||||
queue.push_front(node);
|
||||
}
|
||||
None => {
|
||||
*right = Some(Box::new(BinaryTree::new(new_value)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a binary tree from a slice of values.
|
||||
///
|
||||
/// The first value in the slice is used as the root of the tree,
|
||||
/// and the remaining values are inserted into the tree in breadth-first order.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `new_values` - A slice containing the values to insert into the tree.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A binary tree containing the values from the input slice.
|
||||
pub fn from(new_values: &[T]) -> Self {
|
||||
let (first, rest) = new_values.split_first().unwrap();
|
||||
let mut root: BinaryTree<T> = BinaryTree::new(*first);
|
||||
|
||||
for value in rest {
|
||||
root.insert(*value)
|
||||
}
|
||||
root
|
||||
}
|
||||
|
||||
/// Adds a left child to the current node.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `node` - The binary tree node to add as the left child.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A new binary tree node with the specified left child.
|
||||
fn left(mut self, node: BinaryTree<T>) -> Self {
|
||||
self.left = Some(Box::new(node));
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds a right child to the current node.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `node` - The binary tree node to add as the right child.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A new binary tree node with the specified right child.
|
||||
fn right(mut self, node: BinaryTree<T>) -> Self {
|
||||
self.right = Some(Box::new(node));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
@ -1,224 +1 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
pub struct WeightedAdjacencyList<T, W> {
|
||||
vertices: HashMap<T, HashMap<T, W>>,
|
||||
}
|
||||
|
||||
impl<T, W> Clone for WeightedAdjacencyList<T, W>
|
||||
where
|
||||
T: Clone,
|
||||
W: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
WeightedAdjacencyList {
|
||||
vertices: self.vertices.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, W> WeightedAdjacencyList<T, W>
|
||||
where
|
||||
T: std::hash::Hash + Eq + Clone,
|
||||
{
|
||||
// Constructor to create a new weighted adjacency list
|
||||
pub fn new() -> Self {
|
||||
WeightedAdjacencyList {
|
||||
vertices: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// Method to add a vertex to the adjacency list
|
||||
pub fn add_vertex(&mut self, vertex: T) {
|
||||
self.vertices.entry(vertex).or_insert(HashMap::new());
|
||||
}
|
||||
|
||||
// Method to add an edge with weight between two vertices
|
||||
pub fn add_edge(&mut self, from: T, to: T, weight: W) {
|
||||
// Ensure both vertices exist in the adjacency list
|
||||
self.add_vertex(from.clone());
|
||||
self.add_vertex(to.clone());
|
||||
|
||||
// Add the edge from 'from' to 'to' with weight
|
||||
self.vertices.get_mut(&from).unwrap().insert(to, weight);
|
||||
}
|
||||
|
||||
// Method to get the weight of an edge between two vertices
|
||||
pub fn get_weight(&self, from: &T, to: &T) -> Option<&W> {
|
||||
self.vertices.get(from)?.get(to)
|
||||
}
|
||||
|
||||
// Method to get the neighbors of a vertex
|
||||
pub fn get_neighbors(&self, vertex: &T) -> Option<&HashMap<T, W>> {
|
||||
self.vertices.get(vertex)
|
||||
}
|
||||
// Method to get the number of vertices in the adjacency list
|
||||
pub fn len(&self) -> usize {
|
||||
self.vertices.len()
|
||||
}
|
||||
}
|
||||
|
||||
/// A min-heap data structure for managing elements based on their order.
|
||||
///
|
||||
/// This struct implements a min-heap, where the smallest element is always at the top.
|
||||
/// It is generic over type `T`, which must implement the `PartialOrd` trait.
|
||||
pub struct MinHeap<T> {
|
||||
data: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialOrd> MinHeap<T> {
|
||||
/// Creates a new, empty `MinHeap`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use min_heap::MinHeap;
|
||||
///
|
||||
/// let mut heap: MinHeap<i32> = MinHeap::new();
|
||||
/// ```
|
||||
pub fn new() -> Self {
|
||||
MinHeap { data: Vec::new() }
|
||||
}
|
||||
|
||||
/// Pushes an element onto the heap.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `element` - The element to be pushed onto the heap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use min_heap::MinHeap;
|
||||
///
|
||||
/// let mut heap: MinHeap<i32> = MinHeap::new();
|
||||
/// heap.push(5);
|
||||
/// heap.push(3);
|
||||
/// ```
|
||||
pub fn push(&mut self, element: T) {
|
||||
self.data.push(element);
|
||||
self.heapify_up(self.data.len() - 1);
|
||||
}
|
||||
|
||||
/// Pops the smallest element from the heap.
|
||||
///
|
||||
/// This removes and returns the smallest element from the heap.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The smallest element, if the heap is not empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use min_heap::MinHeap;
|
||||
///
|
||||
/// let mut heap: MinHeap<i32> = MinHeap::new();
|
||||
/// heap.push(5);
|
||||
/// heap.push(3);
|
||||
/// assert_eq!(heap.pop(), Some(3));
|
||||
/// ```
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
if self.data.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let last_index = self.data.len() - 1;
|
||||
self.data.swap(0, last_index);
|
||||
let result = self.data.pop();
|
||||
self.heapify_down(0);
|
||||
result
|
||||
}
|
||||
|
||||
/// Maintains the heap property by moving an element up.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `index` - The index of the element to be moved up.
|
||||
fn heapify_up(&mut self, mut index: usize) {
|
||||
while index != 0 {
|
||||
let parent_index = (index - 1) / 2;
|
||||
if self.data[index] < self.data[parent_index] {
|
||||
self.data.swap(parent_index, index);
|
||||
}
|
||||
index = parent_index;
|
||||
}
|
||||
}
|
||||
|
||||
/// Maintains the heap property by moving an element down.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `index` - The index of the element to be moved down.
|
||||
fn heapify_down(&mut self, mut index: usize) {
|
||||
let length = self.data.len();
|
||||
loop {
|
||||
let left_child = 2 * index + 1;
|
||||
let right_child = 2 * index + 2;
|
||||
|
||||
let mut smallest = index;
|
||||
|
||||
if left_child < length && self.data[left_child] < self.data[smallest] {
|
||||
smallest = left_child;
|
||||
}
|
||||
|
||||
if right_child < length && self.data[right_child] < self.data[smallest] {
|
||||
smallest = right_child;
|
||||
}
|
||||
|
||||
if smallest != index {
|
||||
self.data.swap(index, smallest);
|
||||
index = smallest;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct Queue<T> {
|
||||
queue: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Queue<T> {
|
||||
pub fn new() -> Self {
|
||||
Queue { queue: Vec::new() }
|
||||
}
|
||||
pub fn length(&self) -> usize {
|
||||
self.queue.len()
|
||||
}
|
||||
pub fn enqueue(&mut self, item: T) {
|
||||
self.queue.push(item)
|
||||
}
|
||||
pub fn dequeue(&mut self) -> T {
|
||||
self.queue.remove(0)
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.queue.is_empty()
|
||||
}
|
||||
pub fn peek(&self) -> Option<&T> {
|
||||
self.queue.first()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Stack<T> {
|
||||
stack: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Stack<T> {
|
||||
pub fn new() -> Self {
|
||||
Stack { stack: Vec::new() }
|
||||
}
|
||||
pub fn length(&self) -> usize {
|
||||
self.stack.len()
|
||||
}
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.stack.pop()
|
||||
}
|
||||
pub fn push(&mut self, item: T) {
|
||||
self.stack.push(item)
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.stack.is_empty()
|
||||
}
|
||||
pub fn peek(&self) -> Option<&T> {
|
||||
self.stack.last()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use crate::data_structures::{WeightedAdjacencyList,MinHeap};
|
||||
use crate::weighted_adj_list::{WeightedAdjacencyList};
|
||||
use crate::min_heap::MinHeap;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::data_structures::WeightedAdjacencyList;
|
||||
use crate::weighted_adj_list::WeightedAdjacencyList;
|
||||
use super::dijkstras_shortest_path;
|
||||
#[test]
|
||||
fn dijkstras_shortest_path_primeagen_class_test(){
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ mod binary_search;
|
|||
mod bubble_sort;
|
||||
mod quick_sort;
|
||||
mod dijkstras;
|
||||
mod queue;
|
||||
mod stack;
|
||||
mod binary_tree;
|
||||
mod min_heap;
|
||||
mod weighted_adj_list;
|
||||
mod data_structures;
|
||||
fn linear_search_demo(){
|
||||
println!("-------------------");
|
||||
|
|
|
|||
116
src/min_heap.rs
Normal file
116
src/min_heap.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/// A min-heap data structure for managing elements based on their order.
|
||||
///
|
||||
/// This struct implements a min-heap, where the smallest element is always at the top.
|
||||
/// It is generic over type `T`, which must implement the `PartialOrd` trait.
|
||||
pub struct MinHeap<T> {
|
||||
data: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialOrd> MinHeap<T> {
|
||||
/// Creates a new, empty `MinHeap`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use min_heap::MinHeap;
|
||||
///
|
||||
/// let mut heap: MinHeap<i32> = MinHeap::new();
|
||||
/// ```
|
||||
pub fn new() -> Self {
|
||||
MinHeap { data: Vec::new() }
|
||||
}
|
||||
|
||||
/// Pushes an element onto the heap.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `element` - The element to be pushed onto the heap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use min_heap::MinHeap;
|
||||
///
|
||||
/// let mut heap: MinHeap<i32> = MinHeap::new();
|
||||
/// heap.push(5);
|
||||
/// heap.push(3);
|
||||
/// ```
|
||||
pub fn push(&mut self, element: T) {
|
||||
self.data.push(element);
|
||||
self.heapify_up(self.data.len() - 1);
|
||||
}
|
||||
|
||||
/// Pops the smallest element from the heap.
|
||||
///
|
||||
/// This removes and returns the smallest element from the heap.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The smallest element, if the heap is not empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use min_heap::MinHeap;
|
||||
///
|
||||
/// let mut heap: MinHeap<i32> = MinHeap::new();
|
||||
/// heap.push(5);
|
||||
/// heap.push(3);
|
||||
/// assert_eq!(heap.pop(), Some(3));
|
||||
/// ```
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
if self.data.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let last_index = self.data.len() - 1;
|
||||
self.data.swap(0, last_index);
|
||||
let result = self.data.pop();
|
||||
self.heapify_down(0);
|
||||
result
|
||||
}
|
||||
|
||||
/// Maintains the heap property by moving an element up.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `index` - The index of the element to be moved up.
|
||||
fn heapify_up(&mut self, mut index: usize) {
|
||||
while index != 0 {
|
||||
let parent_index = (index - 1) / 2;
|
||||
if self.data[index] < self.data[parent_index] {
|
||||
self.data.swap(parent_index, index);
|
||||
}
|
||||
index = parent_index;
|
||||
}
|
||||
}
|
||||
|
||||
/// Maintains the heap property by moving an element down.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `index` - The index of the element to be moved down.
|
||||
fn heapify_down(&mut self, mut index: usize) {
|
||||
let length = self.data.len();
|
||||
loop {
|
||||
let left_child = 2 * index + 1;
|
||||
let right_child = 2 * index + 2;
|
||||
|
||||
let mut smallest = index;
|
||||
|
||||
if left_child < length && self.data[left_child] < self.data[smallest] {
|
||||
smallest = left_child;
|
||||
}
|
||||
|
||||
if right_child < length && self.data[right_child] < self.data[smallest] {
|
||||
smallest = right_child;
|
||||
}
|
||||
|
||||
if smallest != index {
|
||||
self.data.swap(index, smallest);
|
||||
index = smallest;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
24
src/queue.rs
Normal file
24
src/queue.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
pub struct Queue<T> {
|
||||
queue: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Queue<T> {
|
||||
pub fn new() -> Self {
|
||||
Queue { queue: Vec::new() }
|
||||
}
|
||||
pub fn length(&self) -> usize {
|
||||
self.queue.len()
|
||||
}
|
||||
pub fn enqueue(&mut self, item: T) {
|
||||
self.queue.push(item)
|
||||
}
|
||||
pub fn dequeue(&mut self) -> T {
|
||||
self.queue.remove(0)
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.queue.is_empty()
|
||||
}
|
||||
pub fn peek(&self) -> Option<&T> {
|
||||
self.queue.first()
|
||||
}
|
||||
}
|
||||
24
src/stack.rs
Normal file
24
src/stack.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
pub struct Stack<T> {
|
||||
stack: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Stack<T> {
|
||||
pub fn new() -> Self {
|
||||
Stack { stack: Vec::new() }
|
||||
}
|
||||
pub fn length(&self) -> usize {
|
||||
self.stack.len()
|
||||
}
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.stack.pop()
|
||||
}
|
||||
pub fn push(&mut self, item: T) {
|
||||
self.stack.push(item)
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.stack.is_empty()
|
||||
}
|
||||
pub fn peek(&self) -> Option<&T> {
|
||||
self.stack.last()
|
||||
}
|
||||
}
|
||||
58
src/weighted_adj_list.rs
Normal file
58
src/weighted_adj_list.rs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
pub struct WeightedAdjacencyList<T, W> {
|
||||
vertices: HashMap<T, HashMap<T, W>>,
|
||||
}
|
||||
|
||||
impl<T, W> Clone for WeightedAdjacencyList<T, W>
|
||||
where
|
||||
T: Clone,
|
||||
W: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
WeightedAdjacencyList {
|
||||
vertices: self.vertices.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, W> WeightedAdjacencyList<T, W>
|
||||
where
|
||||
T: std::hash::Hash + Eq + Clone,
|
||||
{
|
||||
// Constructor to create a new weighted adjacency list
|
||||
pub fn new() -> Self {
|
||||
WeightedAdjacencyList {
|
||||
vertices: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// Method to add a vertex to the adjacency list
|
||||
pub fn add_vertex(&mut self, vertex: T) {
|
||||
self.vertices.entry(vertex).or_insert(HashMap::new());
|
||||
}
|
||||
|
||||
// Method to add an edge with weight between two vertices
|
||||
pub fn add_edge(&mut self, from: T, to: T, weight: W) {
|
||||
// Ensure both vertices exist in the adjacency list
|
||||
self.add_vertex(from.clone());
|
||||
self.add_vertex(to.clone());
|
||||
|
||||
// Add the edge from 'from' to 'to' with weight
|
||||
self.vertices.get_mut(&from).unwrap().insert(to, weight);
|
||||
}
|
||||
|
||||
// Method to get the weight of an edge between two vertices
|
||||
pub fn get_weight(&self, from: &T, to: &T) -> Option<&W> {
|
||||
self.vertices.get(from)?.get(to)
|
||||
}
|
||||
|
||||
// Method to get the neighbors of a vertex
|
||||
pub fn get_neighbors(&self, vertex: &T) -> Option<&HashMap<T, W>> {
|
||||
self.vertices.get(vertex)
|
||||
}
|
||||
// Method to get the number of vertices in the adjacency list
|
||||
pub fn len(&self) -> usize {
|
||||
self.vertices.len()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue