Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added hashtable and removed some of the warnings + trapezoidal method for function integration + bingo sort #66

Merged
merged 11 commits into from
Jan 14, 2024
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ edition = "2018"

[dependencies]
paste = "1.0.12"
bitvec = "1.0.1"
bitvec = "1.0.1"
rand = "0.8.4"
2 changes: 1 addition & 1 deletion src/ciphers/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fn calc_chunk(chunk: &mut [u8; 64], state: &mut BufState) -> bool {
chunk[63] = (len << 3) as u8;
len >>= 5;
for i in 1..8 {
chunk[(63 - i)] = len as u8;
chunk[63 - i] = len as u8;
len >>= 8;
}
state.total = true;
Expand Down
145 changes: 145 additions & 0 deletions src/data_structures/hashtable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use std::collections::LinkedList;

pub struct HashTable<K, V> {
elements: Vec<LinkedList<(K, V)>>,
count: usize,
}

impl<K: Hashable + std::cmp::PartialEq, V> Default for HashTable<K, V> {
fn default() -> Self {
Self::new()
}
}

pub trait Hashable {
fn hash(&self) -> usize;
}

impl<K: Hashable + std::cmp::PartialEq, V> HashTable<K, V> {
pub fn new() -> HashTable<K, V> {
let initial_capacity = 3000;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Extract to a constant. const INITIAL_CAPACITY: usize = 3000;.

Why was this value chosen? std::collection::HashMap has an initial capacity of 6 for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To minimize resizing for larger datasets.

let mut elements = Vec::with_capacity(initial_capacity);

for _ in 0..initial_capacity {
elements.push(LinkedList::new());
}

HashTable { elements, count: 0 }
}

pub fn insert(&mut self, key: K, value: V) {
if self.count >= self.elements.len() * 3 / 4 {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Extract to a constant. const LOAD_FACTOR_BOUND: f32 = 0.75;.

This will make this section a bit uglier because of the casts, but the constant will be explained. wdyt?

self.resize();
}
let index = key.hash() % self.elements.len();
self.elements[index].push_back((key, value));
self.count += 1;
}

pub fn search(&self, key: K) -> Option<&V> {
let index = key.hash() % self.elements.len();
self.elements[index]
.iter()
.find(|(k, _)| *k == key)
.map(|(_, v)| v)
}

fn resize(&mut self) {
let new_size = self.elements.len() * 2;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Extract to a constant. const GROWTH_FACTOR: usize = 2;.

let mut new_elements = Vec::with_capacity(new_size);

for _ in 0..new_size {
new_elements.push(LinkedList::new());
}

for old_list in self.elements.drain(..) {
for (key, value) in old_list {
let new_index = key.hash() % new_size;
new_elements[new_index].push_back((key, value));
}
}

self.elements = new_elements;
}
}

#[cfg(test)]
mod tests {
use super::*;

#[derive(Debug, PartialEq, Eq)]
struct TestKey(usize);

impl Hashable for TestKey {
fn hash(&self) -> usize {
self.0
}
}

#[test]
fn test_insert_and_search() {
let mut hash_table = HashTable::new();
let key = TestKey(1);
let value = TestKey(10);

hash_table.insert(key, value);
let result = hash_table.search(TestKey(1));

assert_eq!(result, Some(&TestKey(10)));
}

#[test]
fn test_resize() {
let mut hash_table = HashTable::new();
let initial_capacity = hash_table.elements.capacity();

for i in 0..initial_capacity * 3 / 4 + 1 {
hash_table.insert(TestKey(i), TestKey(i + 10));
}

assert!(hash_table.elements.capacity() > initial_capacity);
}

#[test]
fn test_search_nonexistent() {
let mut hash_table = HashTable::new();
let key = TestKey(1);
let value = TestKey(10);

hash_table.insert(key, value);
let result = hash_table.search(TestKey(2));

assert_eq!(result, None);
}

#[test]
fn test_multiple_inserts_and_searches() {
let mut hash_table = HashTable::new();
for i in 0..10 {
hash_table.insert(TestKey(i), TestKey(i + 100));
}

for i in 0..10 {
let result = hash_table.search(TestKey(i));
assert_eq!(result, Some(&TestKey(i + 100)));
}
}

#[test]
fn test_not_overwrite_existing_key() {
let mut hash_table = HashTable::new();
hash_table.insert(TestKey(1), TestKey(100));
hash_table.insert(TestKey(1), TestKey(200));

let result = hash_table.search(TestKey(1));
assert_eq!(result, Some(&TestKey(100)));
}

#[test]
fn test_empty_search() {
let hash_table: HashTable<TestKey, TestKey> = HashTable::new();
let result = hash_table.search(TestKey(1));

assert_eq!(result, None);
}
}
2 changes: 2 additions & 0 deletions src/data_structures/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod binary_search_tree;
mod bloom_filter;
mod fenwick_tree;
mod graph;
mod hashtable;
mod heap;
mod linked_list;
mod queue;
Expand All @@ -15,6 +16,7 @@ mod trie;
mod union_find;

pub use self::bloom_filter::BloomFilter;
pub use self::hashtable::HashTable;
pub use self::heap::MaxHeap;
pub use self::heap::MinHeap;
pub use self::linked_list::LinkedList;
Expand Down
2 changes: 1 addition & 1 deletion src/data_structures/rb_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ impl<K: Ord, V> RBTree<K, V> {
}

/* release resource */
Box::from_raw(node);
let _ = Box::from_raw(node);
if matches!(deleted_color, Color::Black) {
delete_fixup(self, parent);
}
Expand Down
2 changes: 1 addition & 1 deletion src/dynamic_programming/coin_problem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub fn coin_problem(n: usize, coins: &mut Vec<usize>) -> usize {
for j in 0..combinations.len() {
if coins[i] <= j {
// update the combinations array
combinations[j] += combinations[(j - coins[i])];
combinations[j] += combinations[j - coins[i]];
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/graphs/depth_first_search_tic_tac_toe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ fn append_playaction(
return;
}

let mut play_actions = opt_play_actions.as_mut().unwrap();
let play_actions = opt_play_actions.as_mut().unwrap();

//New game action is scored from the current side and the current saved best score against the new game action.
match (current_side, play_actions.side, appendee.side) {
Expand Down
2 changes: 2 additions & 0 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ mod random;
mod sieve_of_eratosthenes;
mod simpson_integration;
mod square_root;
mod trapezoidal_integration;
mod trial_division;
mod zellers_congruence_algorithm;

Expand Down Expand Up @@ -60,5 +61,6 @@ pub use self::random::PCG32;
pub use self::sieve_of_eratosthenes::sieve_of_eratosthenes;
pub use self::simpson_integration::simpson_integration;
pub use self::square_root::square_root;
pub use self::trapezoidal_integration::trapezoidal_integral;
pub use self::trial_division::trial_division;
pub use self::zellers_congruence_algorithm::zellers_congruence_algorithm;
61 changes: 61 additions & 0 deletions src/math/trapezoidal_integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
pub fn trapezoidal_integral<F>(a: f64, b: f64, f: F, precision: u32) -> f64
where
F: Fn(f64) -> f64,
{
let delta = (b - a) / precision as f64;

let integral: f64 = (0..precision)
.map(|trapezoid| {
let left_side = a + (delta * trapezoid as f64);
let right_side = left_side + delta;

0.5 * (f(left_side) + f(right_side)) * delta
})
.sum();

if a > b {
-integral
} else {
integral
}
}
BogdanCiocea marked this conversation as resolved.
Show resolved Hide resolved

#[allow(dead_code)]
fn main() {
let f = |x: f64| x.powi(3);
let result = trapezoidal_integral(0.0, 1.0, f, 1000);
println!("{}", result);
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_integral() {
let f = |x: f64| x.powi(2);
let result = trapezoidal_integral(0.0, 1.0, f, 1000);
assert!((result - 1.0 / 3.0).abs() < 0.0001);
}

#[test]
fn test_precision() {
let f = |x: f64| x.powi(2);
let result = trapezoidal_integral(0.0, 1.0, f, 10000);
assert!((result - 1.0 / 3.0).abs() < 0.00001);
}

#[test]
fn test_negative() {
let f = |x: f64| x.powi(2);
let result = trapezoidal_integral(-1.0, 1.0, f, 10000);
assert!((result - 2.0 / 3.0).abs() < 0.00001);
}

#[test]
fn test_negative_precision() {
let f = |x: f64| x.powi(2);
let result = trapezoidal_integral(-1.0, 1.0, f, 100000);
assert!((result - 2.0 / 3.0).abs() < 0.000001);
}
}
2 changes: 1 addition & 1 deletion src/searching/binary_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::cmp::Ordering;
pub fn binary_search<T: Ord>(item: &T, arr: &[T]) -> Option<usize> {
let mut is_asc = true;
if arr.len() > 1 {
is_asc = arr[0] < arr[(arr.len() - 1)];
is_asc = arr[0] < arr[arr.len() - 1];
}
let mut left = 0;
let mut right = arr.len();
Expand Down
105 changes: 105 additions & 0 deletions src/sorting/bingo_sort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use std::cmp::{max, min};

// Function for finding the maximum and minimum element of the Array
fn max_min(vec: &[i32], bingo: &mut i32, next_bingo: &mut i32) {
for &element in vec.iter().skip(1) {
*bingo = min(*bingo, element);
*next_bingo = max(*next_bingo, element);
}
}

pub fn bingo_sort(vec: &mut Vec<i32>) {
if vec.is_empty() {
return;
}

let mut bingo = vec[0];
let mut next_bingo = vec[0];

max_min(vec, &mut bingo, &mut next_bingo);

let largest_element = next_bingo;
let mut next_element_pos = 0;

for (bingo, _next_bingo) in (bingo..=largest_element).zip(bingo..=largest_element) {
let start_pos = next_element_pos;

for i in start_pos..vec.len() {
if vec[i] == bingo {
vec.swap(i, next_element_pos);
next_element_pos += 1;
}
}
}
}

#[allow(dead_code)]
fn print_array(arr: &[i32]) {
print!("Sorted Array: ");
for &element in arr {
print!("{} ", element);
}
println!();
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_bingo_sort() {
let mut arr = vec![5, 4, 8, 5, 4, 8, 5, 4, 4, 4];
bingo_sort(&mut arr);
assert_eq!(arr, vec![4, 4, 4, 4, 4, 5, 5, 5, 8, 8]);

let mut arr2 = vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
bingo_sort(&mut arr2);
assert_eq!(arr2, vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

let mut arr3 = vec![0, 1, 0, 1, 0, 1];
bingo_sort(&mut arr3);
assert_eq!(arr3, vec![0, 0, 0, 1, 1, 1]);
}

#[test]
fn test_empty_array() {
let mut arr = Vec::new();
bingo_sort(&mut arr);
assert_eq!(arr, Vec::new());
}

#[test]
fn test_single_element_array() {
let mut arr = vec![42];
bingo_sort(&mut arr);
assert_eq!(arr, vec![42]);
}

#[test]
fn test_negative_numbers() {
let mut arr = vec![-5, -4, -3, -2, -1];
bingo_sort(&mut arr);
assert_eq!(arr, vec![-5, -4, -3, -2, -1]);
}

#[test]
fn test_already_sorted() {
let mut arr = vec![1, 2, 3, 4, 5];
bingo_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}

#[test]
fn test_reverse_sorted() {
let mut arr = vec![5, 4, 3, 2, 1];
bingo_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}

#[test]
fn test_duplicates() {
let mut arr = vec![1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
bingo_sort(&mut arr);
assert_eq!(arr, vec![1, 1, 2, 2, 3, 3, 4, 4, 5, 5]);
}
}
Loading
Loading