-
Notifications
You must be signed in to change notification settings - Fork 72
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
Changes from 7 commits
12137b2
f9618e3
5ac84f4
2140f17
25d596c
04e3076
a23ea27
363ffd7
37881e2
e32110c
bdb00f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,4 +7,5 @@ edition = "2018" | |
|
||
[dependencies] | ||
paste = "1.0.12" | ||
bitvec = "1.0.1" | ||
bitvec = "1.0.1" | ||
rand = "0.8.4" |
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; | ||
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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Extract to a constant. 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Extract to a constant. |
||
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); | ||
} | ||
} |
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); | ||
} | ||
} |
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]); | ||
} | ||
} |
There was a problem hiding this comment.
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 of6
for example.There was a problem hiding this comment.
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.