Translate all code to English (#1836)

* Review the EN heading format.

* Fix pythontutor headings.

* Fix pythontutor headings.

* bug fixes

* Fix headings in **/summary.md

* Revisit the CN-to-EN translation for Python code using Claude-4.5

* Revisit the CN-to-EN translation for Java code using Claude-4.5

* Revisit the CN-to-EN translation for Cpp code using Claude-4.5.

* Fix the dictionary.

* Fix cpp code translation for the multipart strings.

* Translate Go code to English.

* Update workflows to test EN code.

* Add EN translation for C.

* Add EN translation for CSharp.

* Add EN translation for Swift.

* Trigger the CI check.

* Revert.

* Update en/hash_map.md

* Add the EN version of Dart code.

* Add the EN version of Kotlin code.

* Add missing code files.

* Add the EN version of JavaScript code.

* Add the EN version of TypeScript code.

* Fix the workflows.

* Add the EN version of Ruby code.

* Add the EN version of Rust code.

* Update the CI check for the English version  code.

* Update Python CI check.

* Fix cmakelists for en/C code.

* Fix Ruby comments
This commit is contained in:
Yudong Jin
2025-12-31 07:44:52 +08:00
committed by GitHub
parent 45e1295241
commit 2778a6f9c7
1284 changed files with 71557 additions and 3275 deletions
+2
View File
@@ -0,0 +1,2 @@
target/
Cargo.lock
+413
View File
@@ -0,0 +1,413 @@
[package]
name = "hello-algo-rust"
version = "0.1.0"
edition = "2021"
publish = false
# Run Command: cargo run --bin time_complexity
[[bin]]
name = "time_complexity"
path = "chapter_computational_complexity/time_complexity.rs"
# Run Command: cargo run --bin worst_best_time_complexity
[[bin]]
name = "worst_best_time_complexity"
path = "chapter_computational_complexity/worst_best_time_complexity.rs"
# Run Command: cargo run --bin space_complexity
[[bin]]
name = "space_complexity"
path = "chapter_computational_complexity/space_complexity.rs"
# Run Command: cargo run --bin iteration
[[bin]]
name = "iteration"
path = "chapter_computational_complexity/iteration.rs"
# Run Command: cargo run --bin recursion
[[bin]]
name = "recursion"
path = "chapter_computational_complexity/recursion.rs"
# Run Command: cargo run --bin two_sum
[[bin]]
name = "two_sum"
path = "chapter_searching/two_sum.rs"
# Run Command: cargo run --bin array
[[bin]]
name = "array"
path = "chapter_array_and_linkedlist/array.rs"
# Run Command: cargo run --bin linked_list
[[bin]]
name = "linked_list"
path = "chapter_array_and_linkedlist/linked_list.rs"
# Run Command: cargo run --bin list
[[bin]]
name = "list"
path = "chapter_array_and_linkedlist/list.rs"
# Run Command: cargo run --bin my_list
[[bin]]
name = "my_list"
path = "chapter_array_and_linkedlist/my_list.rs"
# Run Command: cargo run --bin stack
[[bin]]
name = "stack"
path = "chapter_stack_and_queue/stack.rs"
# Run Command: cargo run --bin linkedlist_stack
[[bin]]
name = "linkedlist_stack"
path = "chapter_stack_and_queue/linkedlist_stack.rs"
# Run Command: cargo run --bin queue
[[bin]]
name = "queue"
path = "chapter_stack_and_queue/queue.rs"
# Run Command: cargo run --bin linkedlist_queue
[[bin]]
name = "linkedlist_queue"
path = "chapter_stack_and_queue/linkedlist_queue.rs"
# Run Command: cargo run --bin deque
[[bin]]
name = "deque"
path = "chapter_stack_and_queue/deque.rs"
# Run Command: cargo run --bin array_deque
[[bin]]
name = "array_deque"
path = "chapter_stack_and_queue/array_deque.rs"
# Run Command: cargo run --bin linkedlist_deque
[[bin]]
name = "linkedlist_deque"
path = "chapter_stack_and_queue/linkedlist_deque.rs"
# Run Command: cargo run --bin simple_hash
[[bin]]
name = "simple_hash"
path = "chapter_hashing/simple_hash.rs"
# Run Command: cargo run --bin hash_map
[[bin]]
name = "hash_map"
path = "chapter_hashing/hash_map.rs"
# Run Command: cargo run --bin array_hash_map
[[bin]]
name = "array_hash_map"
path = "chapter_hashing/array_hash_map.rs"
# Run Command: cargo run --bin build_in_hash
[[bin]]
name = "build_in_hash"
path = "chapter_hashing/build_in_hash.rs"
# Run Command: cargo run --bin hash_map_chaining
[[bin]]
name = "hash_map_chaining"
path = "chapter_hashing/hash_map_chaining.rs"
# Run Command: cargo run --bin hash_map_open_addressing
[[bin]]
name = "hash_map_open_addressing"
path = "chapter_hashing/hash_map_open_addressing.rs"
# Run Command: cargo run --bin binary_search
[[bin]]
name = "binary_search"
path = "chapter_searching/binary_search.rs"
# Run Command: cargo run --bin binary_search_edge
[[bin]]
name = "binary_search_edge"
path = "chapter_searching/binary_search_edge.rs"
# Run Command: cargo run --bin binary_search_insertion
[[bin]]
name = "binary_search_insertion"
path = "chapter_searching/binary_search_insertion.rs"
# Run Command: cargo run --bin bubble_sort
[[bin]]
name = "bubble_sort"
path = "chapter_sorting/bubble_sort.rs"
# Run Command: cargo run --bin insertion_sort
[[bin]]
name = "insertion_sort"
path = "chapter_sorting/insertion_sort.rs"
# Run Command: cargo run --bin quick_sort
[[bin]]
name = "quick_sort"
path = "chapter_sorting/quick_sort.rs"
# Run Command: cargo run --bin merge_sort
[[bin]]
name = "merge_sort"
path = "chapter_sorting/merge_sort.rs"
# Run Command: cargo run --bin selection_sort
[[bin]]
name = "selection_sort"
path = "chapter_sorting/selection_sort.rs"
# Run Command: cargo run --bin bucket_sort
[[bin]]
name = "bucket_sort"
path = "chapter_sorting/bucket_sort.rs"
# Run Command: cargo run --bin heap_sort
[[bin]]
name = "heap_sort"
path = "chapter_sorting/heap_sort.rs"
# Run Command: cargo run --bin counting_sort
[[bin]]
name = "counting_sort"
path = "chapter_sorting/counting_sort.rs"
# Run Command: cargo run --bin radix_sort
[[bin]]
name = "radix_sort"
path = "chapter_sorting/radix_sort.rs"
# Run Command: cargo run --bin array_stack
[[bin]]
name = "array_stack"
path = "chapter_stack_and_queue/array_stack.rs"
# Run Command: cargo run --bin array_queue
[[bin]]
name = "array_queue"
path = "chapter_stack_and_queue/array_queue.rs"
# Run Command: cargo run --bin array_binary_tree
[[bin]]
name = "array_binary_tree"
path = "chapter_tree/array_binary_tree.rs"
# Run Command: cargo run --bin avl_tree
[[bin]]
name = "avl_tree"
path = "chapter_tree/avl_tree.rs"
# Run Command: cargo run --bin binary_search_tree
[[bin]]
name = "binary_search_tree"
path = "chapter_tree/binary_search_tree.rs"
# Run Command: cargo run --bin binary_tree_bfs
[[bin]]
name = "binary_tree_bfs"
path = "chapter_tree/binary_tree_bfs.rs"
# Run Command: cargo run --bin binary_tree_dfs
[[bin]]
name = "binary_tree_dfs"
path = "chapter_tree/binary_tree_dfs.rs"
# Run Command: cargo run --bin binary_tree
[[bin]]
name = "binary_tree"
path = "chapter_tree/binary_tree.rs"
# Run Command: cargo run --bin heap
[[bin]]
name = "heap"
path = "chapter_heap/heap.rs"
# Run Command: cargo run --bin my_heap
[[bin]]
name = "my_heap"
path = "chapter_heap/my_heap.rs"
# Run Command: cargo run --bin top_k
[[bin]]
name = "top_k"
path = "chapter_heap/top_k.rs"
# Run Command: cargo run --bin graph_adjacency_list
[[bin]]
name = "graph_adjacency_list"
path = "chapter_graph/graph_adjacency_list.rs"
# Run Command: cargo run --bin graph_adjacency_matrix
[[bin]]
name = "graph_adjacency_matrix"
path = "chapter_graph/graph_adjacency_matrix.rs"
# Run Command: cargo run --bin graph_bfs
[[bin]]
name = "graph_bfs"
path = "chapter_graph/graph_bfs.rs"
# Run Command: cargo run --bin graph_dfs
[[bin]]
name = "graph_dfs"
path = "chapter_graph/graph_dfs.rs"
# Run Command: cargo run --bin linear_search
[[bin]]
name = "linear_search"
path = "chapter_searching/linear_search.rs"
# Run Command: cargo run --bin hashing_search
[[bin]]
name = "hashing_search"
path = "chapter_searching/hashing_search.rs"
# Run Command: cargo run --bin climbing_stairs_dfs
[[bin]]
name = "climbing_stairs_dfs"
path = "chapter_dynamic_programming/climbing_stairs_dfs.rs"
# Run Command: cargo run --bin climbing_stairs_dfs_mem
[[bin]]
name = "climbing_stairs_dfs_mem"
path = "chapter_dynamic_programming/climbing_stairs_dfs_mem.rs"
# Run Command: cargo run --bin climbing_stairs_dp
[[bin]]
name = "climbing_stairs_dp"
path = "chapter_dynamic_programming/climbing_stairs_dp.rs"
# Run Command: cargo run --bin min_cost_climbing_stairs_dp
[[bin]]
name = "min_cost_climbing_stairs_dp"
path = "chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs"
# Run Command: cargo run --bin climbing_stairs_constraint_dp
[[bin]]
name = "climbing_stairs_constraint_dp"
path = "chapter_dynamic_programming/climbing_stairs_constraint_dp.rs"
# Run Command: cargo run --bin climbing_stairs_backtrack
[[bin]]
name = "climbing_stairs_backtrack"
path = "chapter_dynamic_programming/climbing_stairs_backtrack.rs"
# Run Command: cargo run --bin subset_sum_i_naive
[[bin]]
name = "subset_sum_i_naive"
path = "chapter_backtracking/subset_sum_i_naive.rs"
# Run Command: cargo run --bin subset_sum_i
[[bin]]
name = "subset_sum_i"
path = "chapter_backtracking/subset_sum_i.rs"
# Run Command: cargo run --bin subset_sum_ii
[[bin]]
name = "subset_sum_ii"
path = "chapter_backtracking/subset_sum_ii.rs"
# Run Command: cargo run --bin coin_change
[[bin]]
name = "coin_change"
path = "chapter_dynamic_programming/coin_change.rs"
# Run Command: cargo run --bin coin_change_ii
[[bin]]
name = "coin_change_ii"
path = "chapter_dynamic_programming/coin_change_ii.rs"
# Run Command: cargo run --bin unbounded_knapsack
[[bin]]
name = "unbounded_knapsack"
path = "chapter_dynamic_programming/unbounded_knapsack.rs"
# Run Command: cargo run --bin knapsack
[[bin]]
name = "knapsack"
path = "chapter_dynamic_programming/knapsack.rs"
# Run Command: cargo run --bin min_path_sum
[[bin]]
name = "min_path_sum"
path = "chapter_dynamic_programming/min_path_sum.rs"
# Run Command: cargo run --bin edit_distance
[[bin]]
name = "edit_distance"
path = "chapter_dynamic_programming/edit_distance.rs"
# Run Command: cargo run --bin n_queens
[[bin]]
name = "n_queens"
path = "chapter_backtracking/n_queens.rs"
# Run Command: cargo run --bin permutations_i
[[bin]]
name = "permutations_i"
path = "chapter_backtracking/permutations_i.rs"
# Run Command: cargo run --bin permutations_ii
[[bin]]
name = "permutations_ii"
path = "chapter_backtracking/permutations_ii.rs"
# Run Command: cargo run --bin preorder_traversal_i_compact
[[bin]]
name = "preorder_traversal_i_compact"
path = "chapter_backtracking/preorder_traversal_i_compact.rs"
# Run Command: cargo run --bin preorder_traversal_ii_compact
[[bin]]
name = "preorder_traversal_ii_compact"
path = "chapter_backtracking/preorder_traversal_ii_compact.rs"
# Run Command: cargo run --bin preorder_traversal_iii_compact
[[bin]]
name = "preorder_traversal_iii_compact"
path = "chapter_backtracking/preorder_traversal_iii_compact.rs"
# Run Command: cargo run --bin preorder_traversal_iii_template
[[bin]]
name = "preorder_traversal_iii_template"
path = "chapter_backtracking/preorder_traversal_iii_template.rs"
# Run Command: cargo run --bin binary_search_recur
[[bin]]
name = "binary_search_recur"
path = "chapter_divide_and_conquer/binary_search_recur.rs"
# Run Command: cargo run --bin hanota
[[bin]]
name = "hanota"
path = "chapter_divide_and_conquer/hanota.rs"
# Run Command: cargo run --bin build_tree
[[bin]]
name = "build_tree"
path = "chapter_divide_and_conquer/build_tree.rs"
# Run Command: cargo run --bin coin_change_greedy
[[bin]]
name = "coin_change_greedy"
path = "chapter_greedy/coin_change_greedy.rs"
# Run Command: cargo run --bin fractional_knapsack
[[bin]]
name = "fractional_knapsack"
path = "chapter_greedy/fractional_knapsack.rs"
# Run Command: cargo run --bin max_capacity
[[bin]]
name = "max_capacity"
path = "chapter_greedy/max_capacity.rs"
# Run Command: cargo run --bin max_product_cutting
[[bin]]
name = "max_product_cutting"
path = "chapter_greedy/max_product_cutting.rs"
[dependencies]
rand = "0.8.5"
@@ -0,0 +1,111 @@
/*
* File: array.rs
* Created Time: 2023-01-15
* Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
use rand::Rng;
/* Random access to element */
fn random_access(nums: &[i32]) -> i32 {
// Randomly select a number in interval [0, nums.len())
let random_index = rand::thread_rng().gen_range(0..nums.len());
// Retrieve and return the random element
let random_num = nums[random_index];
random_num
}
/* Extend array length */
fn extend(nums: &[i32], enlarge: usize) -> Vec<i32> {
// Initialize an array with extended length
let mut res: Vec<i32> = vec![0; nums.len() + enlarge];
// Copy all elements from original array to new
res[0..nums.len()].copy_from_slice(nums);
// Return the extended new array
res
}
/* Insert element num at index index in the array */
fn insert(nums: &mut [i32], num: i32, index: usize) {
// Move all elements at and after index index backward by one position
for i in (index + 1..nums.len()).rev() {
nums[i] = nums[i - 1];
}
// Assign num to the element at index index
nums[index] = num;
}
/* Remove the element at index index */
fn remove(nums: &mut [i32], index: usize) {
// Move all elements after index index forward by one position
for i in index..nums.len() - 1 {
nums[i] = nums[i + 1];
}
}
/* Traverse array */
fn traverse(nums: &[i32]) {
let mut _count = 0;
// Traverse array by index
for i in 0..nums.len() {
_count += nums[i];
}
// Direct traversal of array elements
_count = 0;
for &num in nums {
_count += num;
}
}
/* Find the specified element in the array */
fn find(nums: &[i32], target: i32) -> Option<usize> {
for i in 0..nums.len() {
if nums[i] == target {
return Some(i);
}
}
None
}
/* Driver Code */
fn main() {
/* Initialize array */
let arr: [i32; 5] = [0; 5];
print!("Array arr = ");
print_util::print_array(&arr);
// In Rust, specifying length ([i32; 5]) is an array, without length (&[i32]) is a slice
// Since Rust arrays are designed to have compile-time determined length, only constants can specify length
// Vector is the type Rust generally uses as a dynamic array
// To facilitate implementing the extend() method, the following treats vector as array
let nums: Vec<i32> = vec![1, 3, 2, 5, 4];
print!("\nArray nums = ");
print_util::print_array(&nums);
// Insert element
let random_num = random_access(&nums);
println!("\nGet random element {} from nums", random_num);
// Traverse array
let mut nums: Vec<i32> = extend(&nums, 3);
print!("Extend array length to 8, resulting in nums = ");
print_util::print_array(&nums);
// Insert element
insert(&mut nums, 6, 3);
print!("\nInsert number 6 at index 3, get nums = ");
print_util::print_array(&nums);
// Remove element
remove(&mut nums, 2);
print!("\nDelete element at index 2, get nums = ");
print_util::print_array(&nums);
// Traverse array
traverse(&nums);
// Find element
let index = find(&nums, 3).unwrap();
println!("\nFind element 3 in nums, index = {}", index);
}
@@ -0,0 +1,100 @@
/*
* File: linked_list.rs
* Created Time: 2023-03-05
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, ListNode};
use std::cell::RefCell;
use std::rc::Rc;
/* Insert node P after node n0 in the linked list */
#[allow(non_snake_case)]
pub fn insert<T>(n0: &Rc<RefCell<ListNode<T>>>, P: Rc<RefCell<ListNode<T>>>) {
let n1 = n0.borrow_mut().next.take();
P.borrow_mut().next = n1;
n0.borrow_mut().next = Some(P);
}
/* Remove the first node after node n0 in the linked list */
#[allow(non_snake_case)]
pub fn remove<T>(n0: &Rc<RefCell<ListNode<T>>>) {
// n0 -> P -> n1
let P = n0.borrow_mut().next.take();
if let Some(node) = P {
let n1 = node.borrow_mut().next.take();
n0.borrow_mut().next = n1;
}
}
/* Access the node at index index in the linked list */
pub fn access<T>(head: Rc<RefCell<ListNode<T>>>, index: i32) -> Option<Rc<RefCell<ListNode<T>>>> {
fn dfs<T>(
head: Option<&Rc<RefCell<ListNode<T>>>>,
index: i32,
) -> Option<Rc<RefCell<ListNode<T>>>> {
if index <= 0 {
return head.cloned();
}
if let Some(node) = head {
dfs(node.borrow().next.as_ref(), index - 1)
} else {
None
}
}
dfs(Some(head).as_ref(), index)
}
/* Find the first node with value target in the linked list */
pub fn find<T: PartialEq>(head: Rc<RefCell<ListNode<T>>>, target: T) -> i32 {
fn find<T: PartialEq>(head: Option<&Rc<RefCell<ListNode<T>>>>, target: T, idx: i32) -> i32 {
if let Some(node) = head {
if node.borrow().val == target {
return idx;
}
return find(node.borrow().next.as_ref(), target, idx + 1);
} else {
-1
}
}
find(Some(head).as_ref(), target, 0)
}
/* Driver Code */
fn main() {
/* Initialize linked list */
// Initialize each node
let n0 = ListNode::new(1);
let n1 = ListNode::new(3);
let n2 = ListNode::new(2);
let n3 = ListNode::new(5);
let n4 = ListNode::new(4);
// Build references between nodes
n0.borrow_mut().next = Some(n1.clone());
n1.borrow_mut().next = Some(n2.clone());
n2.borrow_mut().next = Some(n3.clone());
n3.borrow_mut().next = Some(n4.clone());
print!("Initialized linked list is ");
print_util::print_linked_list(&n0);
/* Insert node */
insert(&n0, ListNode::new(0));
print!("After inserting node, linked list is ");
print_util::print_linked_list(&n0);
/* Remove node */
remove(&n0);
print!("After deleting node, linked list is ");
print_util::print_linked_list(&n0);
/* Access node */
let node = access(n0.clone(), 3);
println!("Value of node at index 3 in linked list = {}", node.unwrap().borrow().val);
/* Search node */
let index = find(n0.clone(), 2);
println!("Index of node with value 2 in linked list = {}", index);
}
@@ -0,0 +1,71 @@
/*
* File: list.rs
* Created Time: 2023-01-18
* Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
/* Driver Code */
fn main() {
// Initialize list
let mut nums: Vec<i32> = vec![1, 3, 2, 5, 4];
print!("List nums = ");
print_util::print_array(&nums);
// Update element
let num = nums[1];
println!("\nAccess element at index 1, get num = {num}");
// Add elements at the end
nums[1] = 0;
print!("Update element at index 1 to 0, resulting in nums = ");
print_util::print_array(&nums);
// Remove element
nums.clear();
print!("\nAfter clearing list, nums = ");
print_util::print_array(&nums);
// Direct traversal of list elements
nums.push(1);
nums.push(3);
nums.push(2);
nums.push(5);
nums.push(4);
print!("\nAfter adding elements, nums = ");
print_util::print_array(&nums);
// Sort list
nums.insert(3, 6);
print!("\nInsert number 6 at index 3, get nums = ");
print_util::print_array(&nums);
// Remove element
nums.remove(3);
print!("\nDelete element at index 3, get nums = ");
print_util::print_array(&nums);
// Traverse list by index
let mut _count = 0;
for i in 0..nums.len() {
_count += nums[i];
}
// Directly traverse list elements
_count = 0;
for x in &nums {
_count += x;
}
// Concatenate two lists
let mut nums1 = vec![6, 8, 7, 10, 9];
nums.append(&mut nums1); // After append (move), nums1 is empty!
// nums.extend(&nums1); // extend (borrow) allows nums1 to continue being used
print!("\nAfter concatenating list nums1 to nums, get nums = ");
print_util::print_array(&nums);
// Sort list
nums.sort();
print!("\nAfter sorting list, nums = ");
print_util::print_array(&nums);
}
@@ -0,0 +1,164 @@
/*
* File: my_list.rs
* Created Time: 2023-03-11
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
/* List class */
#[allow(dead_code)]
struct MyList {
arr: Vec<i32>, // Array (stores list elements)
capacity: usize, // List capacity
size: usize, // List length (current number of elements)
extend_ratio: usize, // Multiple by which the list capacity is extended each time
}
#[allow(unused, unused_comparisons)]
impl MyList {
/* Constructor */
pub fn new(capacity: usize) -> Self {
let mut vec = vec![0; capacity];
Self {
arr: vec,
capacity,
size: 0,
extend_ratio: 2,
}
}
/* Get list length (current number of elements) */
pub fn size(&self) -> usize {
return self.size;
}
/* Get list capacity */
pub fn capacity(&self) -> usize {
return self.capacity;
}
/* Update element */
pub fn get(&self, index: usize) -> i32 {
// If the index is out of bounds, throw an exception, as below
if index >= self.size {
panic!("Index out of bounds")
};
return self.arr[index];
}
/* Add elements at the end */
pub fn set(&mut self, index: usize, num: i32) {
if index >= self.size {
panic!("Index out of bounds")
};
self.arr[index] = num;
}
/* Direct traversal of list elements */
pub fn add(&mut self, num: i32) {
// When the number of elements exceeds capacity, trigger the extension mechanism
if self.size == self.capacity() {
self.extend_capacity();
}
self.arr[self.size] = num;
// Update the number of elements
self.size += 1;
}
/* Sort list */
pub fn insert(&mut self, index: usize, num: i32) {
if index >= self.size() {
panic!("Index out of bounds")
};
// When the number of elements exceeds capacity, trigger the extension mechanism
if self.size == self.capacity() {
self.extend_capacity();
}
// Move all elements after index index forward by one position
for j in (index..self.size).rev() {
self.arr[j + 1] = self.arr[j];
}
self.arr[index] = num;
// Update the number of elements
self.size += 1;
}
/* Remove element */
pub fn remove(&mut self, index: usize) -> i32 {
if index >= self.size() {
panic!("Index out of bounds")
};
let num = self.arr[index];
// Create a new array with length _extend_ratio times the original array, and copy the original array to the new array
for j in index..self.size - 1 {
self.arr[j] = self.arr[j + 1];
}
// Update the number of elements
self.size -= 1;
// Return the removed element
return num;
}
/* Driver Code */
pub fn extend_capacity(&mut self) {
// Create new array with length extend_ratio times original, copy original array to new array
let new_capacity = self.capacity * self.extend_ratio;
self.arr.resize(new_capacity, 0);
// Add elements at the end
self.capacity = new_capacity;
}
/* Convert list to array */
pub fn to_array(&self) -> Vec<i32> {
// Elements enqueue
let mut arr = Vec::new();
for i in 0..self.size {
arr.push(self.get(i));
}
arr
}
}
/* Driver Code */
fn main() {
/* Initialize list */
let mut nums = MyList::new(10);
/* Direct traversal of list elements */
nums.add(1);
nums.add(3);
nums.add(2);
nums.add(5);
nums.add(4);
print!("List nums = ");
print_util::print_array(&nums.to_array());
print!(", capacity = {}, length = {}", nums.capacity(), nums.size());
/* Sort list */
nums.insert(3, 6);
print!("\nInsert number 6 at index 3, get nums = ");
print_util::print_array(&nums.to_array());
/* Remove element */
nums.remove(3);
print!("\nDelete element at index 3, get nums = ");
print_util::print_array(&nums.to_array());
/* Update element */
let num = nums.get(1);
println!("\nAccess element at index 1, get num = {num}");
/* Add elements at the end */
nums.set(1, 0);
print!("Update element at index 1 to 0, resulting in nums = ");
print_util::print_array(&nums.to_array());
/* Test capacity expansion mechanism */
for i in 0..10 {
// At i = 5, the list length will exceed the list capacity, triggering the expansion mechanism
nums.add(i);
}
print!("\nAfter expanding list, nums = ");
print_util::print_array(&nums.to_array());
print!(", capacity = {}, length = {}", nums.capacity(), nums.size());
}
@@ -0,0 +1,76 @@
/*
* File: n_queens.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
/* Backtracking algorithm: N queens */
fn backtrack(
row: usize,
n: usize,
state: &mut Vec<Vec<String>>,
res: &mut Vec<Vec<Vec<String>>>,
cols: &mut [bool],
diags1: &mut [bool],
diags2: &mut [bool],
) {
// When all rows are placed, record the solution
if row == n {
res.push(state.clone());
return;
}
// Traverse all columns
for col in 0..n {
// Calculate the main diagonal and anti-diagonal corresponding to this cell
let diag1 = row + n - 1 - col;
let diag2 = row + col;
// Pruning: do not allow queens to exist in the column, main diagonal, and anti-diagonal of this cell
if !cols[col] && !diags1[diag1] && !diags2[diag2] {
// Attempt: place the queen in this cell
state[row][col] = "Q".into();
(cols[col], diags1[diag1], diags2[diag2]) = (true, true, true);
// Place the next row
backtrack(row + 1, n, state, res, cols, diags1, diags2);
// Backtrack: restore this cell to an empty cell
state[row][col] = "#".into();
(cols[col], diags1[diag1], diags2[diag2]) = (false, false, false);
}
}
}
/* Solve N queens */
fn n_queens(n: usize) -> Vec<Vec<Vec<String>>> {
// Initialize an n*n chessboard, where 'Q' represents a queen and '#' represents an empty cell
let mut state: Vec<Vec<String>> = vec![vec!["#".to_string(); n]; n];
let mut cols = vec![false; n]; // Record whether there is a queen in the column
let mut diags1 = vec![false; 2 * n - 1]; // Record whether there is a queen on the main diagonal
let mut diags2 = vec![false; 2 * n - 1]; // Record whether there is a queen on the anti-diagonal
let mut res: Vec<Vec<Vec<String>>> = Vec::new();
backtrack(
0,
n,
&mut state,
&mut res,
&mut cols,
&mut diags1,
&mut diags2,
);
res
}
/* Driver Code */
pub fn main() {
let n: usize = 4;
let res = n_queens(n);
println!("Input board size is {n}");
println!("Total queen placement solutions: {}", res.len());
for state in res.iter() {
println!("--------------------");
for row in state.iter() {
println!("{:?}", row);
}
}
}
@@ -0,0 +1,46 @@
/*
* File: permutations_i.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
/* Backtracking algorithm: Permutations I */
fn backtrack(mut state: Vec<i32>, choices: &[i32], selected: &mut [bool], res: &mut Vec<Vec<i32>>) {
// When the state length equals the number of elements, record the solution
if state.len() == choices.len() {
res.push(state);
return;
}
// Traverse all choices
for i in 0..choices.len() {
let choice = choices[i];
// Pruning: do not allow repeated selection of elements
if !selected[i] {
// Attempt: make choice, update state
selected[i] = true;
state.push(choice);
// Proceed to the next round of selection
backtrack(state.clone(), choices, selected, res);
// Backtrack: undo choice, restore to previous state
selected[i] = false;
state.pop();
}
}
}
/* Permutations I */
fn permutations_i(nums: &mut [i32]) -> Vec<Vec<i32>> {
let mut res = Vec::new(); // State (subset)
backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res);
res
}
/* Driver Code */
pub fn main() {
let mut nums = [1, 2, 3];
let res = permutations_i(&mut nums);
println!("Input array nums = {:?}", &nums);
println!("All permutations res = {:?}", &res);
}
@@ -0,0 +1,50 @@
/*
* File: permutations_ii.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use std::collections::HashSet;
/* Backtracking algorithm: Permutations II */
fn backtrack(mut state: Vec<i32>, choices: &[i32], selected: &mut [bool], res: &mut Vec<Vec<i32>>) {
// When the state length equals the number of elements, record the solution
if state.len() == choices.len() {
res.push(state);
return;
}
// Traverse all choices
let mut duplicated = HashSet::<i32>::new();
for i in 0..choices.len() {
let choice = choices[i];
// Pruning: do not allow repeated selection of elements and do not allow repeated selection of equal elements
if !selected[i] && !duplicated.contains(&choice) {
// Attempt: make choice, update state
duplicated.insert(choice); // Record the selected element value
selected[i] = true;
state.push(choice);
// Proceed to the next round of selection
backtrack(state.clone(), choices, selected, res);
// Backtrack: undo choice, restore to previous state
selected[i] = false;
state.pop();
}
}
}
/* Permutations II */
fn permutations_ii(nums: &mut [i32]) -> Vec<Vec<i32>> {
let mut res = Vec::new();
backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res);
res
}
/* Driver Code */
pub fn main() {
let mut nums = [1, 2, 2];
let res = permutations_ii(&mut nums);
println!("Input array nums = {:?}", &nums);
println!("All permutations res = {:?}", &res);
}
@@ -0,0 +1,41 @@
/*
* File: preorder_traversal_i_compact.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use std::{cell::RefCell, rc::Rc};
/* Preorder traversal: Example 1 */
fn pre_order(res: &mut Vec<Rc<RefCell<TreeNode>>>, root: Option<&Rc<RefCell<TreeNode>>>) {
if root.is_none() {
return;
}
if let Some(node) = root {
if node.borrow().val == 7 {
// Record solution
res.push(node.clone());
}
pre_order(res, node.borrow().left.as_ref());
pre_order(res, node.borrow().right.as_ref());
}
}
/* Driver Code */
pub fn main() {
let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec());
println!("Initialize binary tree");
print_util::print_tree(root.as_ref().unwrap());
// Preorder traversal
let mut res = Vec::new();
pre_order(&mut res, root.as_ref());
println!("\nOutput all nodes with value 7");
let mut vals = Vec::new();
for node in res {
vals.push(node.borrow().val)
}
println!("{:?}", vals);
}
@@ -0,0 +1,52 @@
/*
* File: preorder_traversal_ii_compact.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use std::{cell::RefCell, rc::Rc};
/* Preorder traversal: Example 2 */
fn pre_order(
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
path: &mut Vec<Rc<RefCell<TreeNode>>>,
root: Option<&Rc<RefCell<TreeNode>>>,
) {
if root.is_none() {
return;
}
if let Some(node) = root {
// Attempt
path.push(node.clone());
if node.borrow().val == 7 {
// Record solution
res.push(path.clone());
}
pre_order(res, path, node.borrow().left.as_ref());
pre_order(res, path, node.borrow().right.as_ref());
// Backtrack
path.pop();
}
}
/* Driver Code */
pub fn main() {
let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec());
println!("Initialize binary tree");
print_util::print_tree(root.as_ref().unwrap());
// Preorder traversal
let mut path = Vec::new();
let mut res = Vec::new();
pre_order(&mut res, &mut path, root.as_ref());
println!("\nOutput all paths from root node to node 7");
for path in res {
let mut vals = Vec::new();
for node in path {
vals.push(node.borrow().val)
}
println!("{:?}", vals);
}
}
@@ -0,0 +1,53 @@
/*
* File: preorder_traversal_iii_compact.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use std::{cell::RefCell, rc::Rc};
/* Preorder traversal: Example 3 */
fn pre_order(
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
path: &mut Vec<Rc<RefCell<TreeNode>>>,
root: Option<&Rc<RefCell<TreeNode>>>,
) {
// Pruning
if root.is_none() || root.as_ref().unwrap().borrow().val == 3 {
return;
}
if let Some(node) = root {
// Attempt
path.push(node.clone());
if node.borrow().val == 7 {
// Record solution
res.push(path.clone());
}
pre_order(res, path, node.borrow().left.as_ref());
pre_order(res, path, node.borrow().right.as_ref());
// Backtrack
path.pop();
}
}
/* Driver Code */
pub fn main() {
let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec());
println!("Initialize binary tree");
print_util::print_tree(root.as_ref().unwrap());
// Preorder traversal
let mut path = Vec::new();
let mut res = Vec::new();
pre_order(&mut res, &mut path, root.as_ref());
println!("\nOutput all paths from root node to node 7, paths do not include nodes with value 3");
for path in res {
let mut vals = Vec::new();
for node in path {
vals.push(node.borrow().val)
}
println!("{:?}", vals);
}
}
@@ -0,0 +1,88 @@
/*
* File: preorder_traversal_iii_template.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use std::{cell::RefCell, rc::Rc};
/* Check if the current state is a solution */
fn is_solution(state: &mut Vec<Rc<RefCell<TreeNode>>>) -> bool {
return !state.is_empty() && state.last().unwrap().borrow().val == 7;
}
/* Record solution */
fn record_solution(
state: &mut Vec<Rc<RefCell<TreeNode>>>,
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
) {
res.push(state.clone());
}
/* Check if the choice is valid under the current state */
fn is_valid(_: &mut Vec<Rc<RefCell<TreeNode>>>, choice: Option<&Rc<RefCell<TreeNode>>>) -> bool {
return choice.is_some() && choice.unwrap().borrow().val != 3;
}
/* Update state */
fn make_choice(state: &mut Vec<Rc<RefCell<TreeNode>>>, choice: Rc<RefCell<TreeNode>>) {
state.push(choice);
}
/* Restore state */
fn undo_choice(state: &mut Vec<Rc<RefCell<TreeNode>>>, _: Rc<RefCell<TreeNode>>) {
state.pop();
}
/* Backtracking algorithm: Example 3 */
fn backtrack(
state: &mut Vec<Rc<RefCell<TreeNode>>>,
choices: &Vec<Option<&Rc<RefCell<TreeNode>>>>,
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
) {
// Check if it is a solution
if is_solution(state) {
// Record solution
record_solution(state, res);
}
// Traverse all choices
for &choice in choices.iter() {
// Pruning: check if the choice is valid
if is_valid(state, choice) {
// Attempt: make choice, update state
make_choice(state, choice.unwrap().clone());
// Proceed to the next round of selection
backtrack(
state,
&vec![
choice.unwrap().borrow().left.as_ref(),
choice.unwrap().borrow().right.as_ref(),
],
res,
);
// Backtrack: undo choice, restore to previous state
undo_choice(state, choice.unwrap().clone());
}
}
}
/* Driver Code */
pub fn main() {
let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec());
println!("Initialize binary tree");
print_util::print_tree(root.as_ref().unwrap());
// Backtracking algorithm
let mut res = Vec::new();
backtrack(&mut Vec::new(), &mut vec![root.as_ref()], &mut res);
println!("\nOutput all paths from root node to node 7, requiring paths do not include nodes with value 3");
for path in res {
let mut vals = Vec::new();
for node in path {
vals.push(node.borrow().val)
}
println!("{:?}", vals);
}
}
@@ -0,0 +1,56 @@
/*
* File: subset_sum_i.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Backtracking algorithm: Subset sum I */
fn backtrack(
state: &mut Vec<i32>,
target: i32,
choices: &[i32],
start: usize,
res: &mut Vec<Vec<i32>>,
) {
// When the subset sum equals target, record the solution
if target == 0 {
res.push(state.clone());
return;
}
// Traverse all choices
// Pruning 2: start traversing from start to avoid generating duplicate subsets
for i in start..choices.len() {
// Pruning 1: if the subset sum exceeds target, end the loop directly
// This is because the array is sorted, and later elements are larger, so the subset sum will definitely exceed target
if target - choices[i] < 0 {
break;
}
// Attempt: make choice, update target, start
state.push(choices[i]);
// Proceed to the next round of selection
backtrack(state, target - choices[i], choices, i, res);
// Backtrack: undo choice, restore to previous state
state.pop();
}
}
/* Solve subset sum I */
fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec<Vec<i32>> {
let mut state = Vec::new(); // State (subset)
nums.sort(); // Sort nums
let start = 0; // Start point for traversal
let mut res = Vec::new(); // Result list (subset list)
backtrack(&mut state, target, nums, start, &mut res);
res
}
/* Driver Code */
pub fn main() {
let mut nums = [3, 4, 5];
let target = 9;
let res = subset_sum_i(&mut nums, target);
println!("Input array nums = {:?}, target = {}", &nums, target);
println!("All subsets with sum equal to {} res = {:?}", target, &res);
}
@@ -0,0 +1,54 @@
/*
* File: subset_sum_i_naive.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Backtracking algorithm: Subset sum I */
fn backtrack(
state: &mut Vec<i32>,
target: i32,
total: i32,
choices: &[i32],
res: &mut Vec<Vec<i32>>,
) {
// When the subset sum equals target, record the solution
if total == target {
res.push(state.clone());
return;
}
// Traverse all choices
for i in 0..choices.len() {
// Pruning: if the subset sum exceeds target, skip this choice
if total + choices[i] > target {
continue;
}
// Attempt: make choice, update element sum total
state.push(choices[i]);
// Proceed to the next round of selection
backtrack(state, target, total + choices[i], choices, res);
// Backtrack: undo choice, restore to previous state
state.pop();
}
}
/* Solve subset sum I (including duplicate subsets) */
fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec<Vec<i32>> {
let mut state = Vec::new(); // State (subset)
let total = 0; // Subset sum
let mut res = Vec::new(); // Result list (subset list)
backtrack(&mut state, target, total, nums, &mut res);
res
}
/* Driver Code */
pub fn main() {
let nums = [3, 4, 5];
let target = 9;
let res = subset_sum_i_naive(&nums, target);
println!("Input array nums = {:?}, target = {}", &nums, target);
println!("All subsets with sum equal to {} res = {:?}", target, &res);
println!("Please note that this method outputs results containing duplicate sets");
}
@@ -0,0 +1,61 @@
/*
* File: subset_sum_ii.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Backtracking algorithm: Subset sum II */
fn backtrack(
state: &mut Vec<i32>,
target: i32,
choices: &[i32],
start: usize,
res: &mut Vec<Vec<i32>>,
) {
// When the subset sum equals target, record the solution
if target == 0 {
res.push(state.clone());
return;
}
// Traverse all choices
// Pruning 2: start traversing from start to avoid generating duplicate subsets
// Pruning 3: start traversing from start to avoid repeatedly selecting the same element
for i in start..choices.len() {
// Pruning 1: if the subset sum exceeds target, end the loop directly
// This is because the array is sorted, and later elements are larger, so the subset sum will definitely exceed target
if target - choices[i] < 0 {
break;
}
// Pruning 4: if this element equals the left element, it means this search branch is duplicate, skip it directly
if i > start && choices[i] == choices[i - 1] {
continue;
}
// Attempt: make choice, update target, start
state.push(choices[i]);
// Proceed to the next round of selection
backtrack(state, target - choices[i], choices, i + 1, res);
// Backtrack: undo choice, restore to previous state
state.pop();
}
}
/* Solve subset sum II */
fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec<Vec<i32>> {
let mut state = Vec::new(); // State (subset)
nums.sort(); // Sort nums
let start = 0; // Start point for traversal
let mut res = Vec::new(); // Result list (subset list)
backtrack(&mut state, target, nums, start, &mut res);
res
}
/* Driver Code */
pub fn main() {
let mut nums = [4, 4, 5];
let target = 9;
let res = subset_sum_ii(&mut nums, target);
println!("Input array nums = {:?}, target = {}", &nums, target);
println!("All subsets with sum equal to {} res = {:?}", target, &res);
}
@@ -0,0 +1,74 @@
/*
* File: iteration.rs
* Created Time: 2023-09-02
* Author: night-cruise (2586447362@qq.com)
*/
/* for loop */
fn for_loop(n: i32) -> i32 {
let mut res = 0;
// Sum 1, 2, ..., n-1, n
for i in 1..=n {
res += i;
}
res
}
/* while loop */
fn while_loop(n: i32) -> i32 {
let mut res = 0;
let mut i = 1; // Initialize condition variable
// Sum 1, 2, ..., n-1, n
while i <= n {
res += i;
i += 1; // Update condition variable
}
res
}
/* while loop (two updates) */
fn while_loop_ii(n: i32) -> i32 {
let mut res = 0;
let mut i = 1; // Initialize condition variable
// Sum 1, 4, 10, ...
while i <= n {
res += i;
// Update condition variable
i += 1;
i *= 2;
}
res
}
/* Nested for loop */
fn nested_for_loop(n: i32) -> String {
let mut res = vec![];
// Loop i = 1, 2, ..., n-1, n
for i in 1..=n {
// Loop j = 1, 2, ..., n-1, n
for j in 1..=n {
res.push(format!("({}, {}), ", i, j));
}
}
res.join("")
}
/* Driver Code */
fn main() {
let n = 5;
let mut res;
res = for_loop(n);
println!("\nFor loop sum result res = {res}");
res = while_loop(n);
println!("\nWhile loop sum result res = {res}");
res = while_loop_ii(n);
println!("\nWhile loop (two updates) sum result res = {}", res);
let res = nested_for_loop(n);
println!("\nNested for loop traversal result {res}");
}
@@ -0,0 +1,76 @@
/*
* File: recursion.rs
* Created Time: 2023-09-02
* Author: night-cruise (2586447362@qq.com)
*/
/* Recursion */
fn recur(n: i32) -> i32 {
// Termination condition
if n == 1 {
return 1;
}
// Recurse: recursive call
let res = recur(n - 1);
// Return: return result
n + res
}
/* Simulate recursion using iteration */
fn for_loop_recur(n: i32) -> i32 {
// Use an explicit stack to simulate the system call stack
let mut stack = Vec::new();
let mut res = 0;
// Recurse: recursive call
for i in (1..=n).rev() {
// Simulate "recurse" with "push"
stack.push(i);
}
// Return: return result
while !stack.is_empty() {
// Simulate "return" with "pop"
res += stack.pop().unwrap();
}
// res = 1+2+3+...+n
res
}
/* Tail recursion */
fn tail_recur(n: i32, res: i32) -> i32 {
// Termination condition
if n == 0 {
return res;
}
// Tail recursive call
tail_recur(n - 1, res + n)
}
/* Fibonacci sequence: recursion */
fn fib(n: i32) -> i32 {
// Termination condition f(1) = 0, f(2) = 1
if n == 1 || n == 2 {
return n - 1;
}
// Recursive call f(n) = f(n-1) + f(n-2)
let res = fib(n - 1) + fib(n - 2);
// Return result
res
}
/* Driver Code */
fn main() {
let n = 5;
let mut res;
res = recur(n);
println!("\nRecursion sum result res = {res}");
res = for_loop_recur(n);
println!("\nUsing iteration to simulate recursion sum result res = {res}");
res = tail_recur(n, 0);
println!("\nTail recursion sum result res = {res}");
res = fib(n);
println!("\nThe {n}th Fibonacci number is {res}");
}
@@ -0,0 +1,114 @@
/*
* File: space_complexity.rs
* Created Time: 2023-03-11
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, ListNode, TreeNode};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
/* Function */
fn function() -> i32 {
// Perform some operations
return 0;
}
/* Constant order */
#[allow(unused)]
fn constant(n: i32) {
// Constants, variables, objects occupy O(1) space
const A: i32 = 0;
let b = 0;
let nums = vec![0; 10000];
let node = ListNode::new(0);
// Variables in the loop occupy O(1) space
for i in 0..n {
let c = 0;
}
// Functions in the loop occupy O(1) space
for i in 0..n {
function();
}
}
/* Linear order */
#[allow(unused)]
fn linear(n: i32) {
// Array of length n uses O(n) space
let mut nums = vec![0; n as usize];
// A list of length n occupies O(n) space
let mut nodes = Vec::new();
for i in 0..n {
nodes.push(ListNode::new(i))
}
// A hash table of length n occupies O(n) space
let mut map = HashMap::new();
for i in 0..n {
map.insert(i, i.to_string());
}
}
/* Linear order (recursive implementation) */
fn linear_recur(n: i32) {
println!("Recursion n = {}", n);
if n == 1 {
return;
};
linear_recur(n - 1);
}
/* Exponential order */
#[allow(unused)]
fn quadratic(n: i32) {
// Matrix uses O(n^2) space
let num_matrix = vec![vec![0; n as usize]; n as usize];
// 2D list uses O(n^2) space
let mut num_list = Vec::new();
for i in 0..n {
let mut tmp = Vec::new();
for j in 0..n {
tmp.push(0);
}
num_list.push(tmp);
}
}
/* Quadratic order (recursive implementation) */
fn quadratic_recur(n: i32) -> i32 {
if n <= 0 {
return 0;
};
// Array nums has length n, n-1, ..., 2, 1
let nums = vec![0; n as usize];
println!("In recursion n = {}, nums length = {}", n, nums.len());
return quadratic_recur(n - 1);
}
/* Driver Code */
fn build_tree(n: i32) -> Option<Rc<RefCell<TreeNode>>> {
if n == 0 {
return None;
};
let root = TreeNode::new(0);
root.borrow_mut().left = build_tree(n - 1);
root.borrow_mut().right = build_tree(n - 1);
return Some(root);
}
/* Driver Code */
fn main() {
let n = 5;
// Constant order
constant(n);
// Linear order
linear(n);
linear_recur(n);
// Exponential order
quadratic(n);
quadratic_recur(n);
// Exponential order
let root = build_tree(n);
print_util::print_tree(&root.unwrap());
}
@@ -0,0 +1,170 @@
/*
* File: time_complexity.rs
* Created Time: 2023-01-10
* Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com)
*/
/* Constant order */
fn constant(n: i32) -> i32 {
_ = n;
let mut count = 0;
let size = 100_000;
for _ in 0..size {
count += 1;
}
count
}
/* Linear order */
fn linear(n: i32) -> i32 {
let mut count = 0;
for _ in 0..n {
count += 1;
}
count
}
/* Linear order (traversing array) */
fn array_traversal(nums: &[i32]) -> i32 {
let mut count = 0;
// Number of iterations is proportional to the array length
for _ in nums {
count += 1;
}
count
}
/* Exponential order */
fn quadratic(n: i32) -> i32 {
let mut count = 0;
// Number of iterations is quadratically related to the data size n
for _ in 0..n {
for _ in 0..n {
count += 1;
}
}
count
}
/* Quadratic order (bubble sort) */
fn bubble_sort(nums: &mut [i32]) -> i32 {
let mut count = 0; // Counter
// Outer loop: unsorted range is [0, i]
for i in (1..nums.len()).rev() {
// Inner loop: swap the largest element in the unsorted range [0, i] to the rightmost end of that range
for j in 0..i {
if nums[j] > nums[j + 1] {
// Swap nums[j] and nums[j + 1]
let tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
count += 3; // Element swap includes 3 unit operations
}
}
}
count
}
/* Exponential order (loop implementation) */
fn exponential(n: i32) -> i32 {
let mut count = 0;
let mut base = 1;
// Cells divide into two every round, forming sequence 1, 2, 4, 8, ..., 2^(n-1)
for _ in 0..n {
for _ in 0..base {
count += 1
}
base *= 2;
}
// count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1
count
}
/* Exponential order (recursive implementation) */
fn exp_recur(n: i32) -> i32 {
if n == 1 {
return 1;
}
exp_recur(n - 1) + exp_recur(n - 1) + 1
}
/* Logarithmic order (loop implementation) */
fn logarithmic(mut n: i32) -> i32 {
let mut count = 0;
while n > 1 {
n = n / 2;
count += 1;
}
count
}
/* Logarithmic order (recursive implementation) */
fn log_recur(n: i32) -> i32 {
if n <= 1 {
return 0;
}
log_recur(n / 2) + 1
}
/* Linearithmic order */
fn linear_log_recur(n: i32) -> i32 {
if n <= 1 {
return 1;
}
let mut count = linear_log_recur(n / 2) + linear_log_recur(n / 2);
for _ in 0..n {
count += 1;
}
return count;
}
/* Factorial order (recursive implementation) */
fn factorial_recur(n: i32) -> i32 {
if n == 0 {
return 1;
}
let mut count = 0;
// Split from 1 into n
for _ in 0..n {
count += factorial_recur(n - 1);
}
count
}
/* Driver Code */
fn main() {
// You can modify n to run and observe the trend of the number of operations for various complexities
let n: i32 = 8;
println!("Input data size n = {}", n);
let mut count = constant(n);
println!("Constant-time operations count = {}", count);
count = linear(n);
println!("Linear-time operations count = {}", count);
count = array_traversal(&vec![0; n as usize]);
println!("Linear-time (array traversal) operations count = {}", count);
count = quadratic(n);
println!("Quadratic-time operations count = {}", count);
let mut nums = (1..=n).rev().collect::<Vec<_>>(); // [n,n-1,...,2,1]
count = bubble_sort(&mut nums);
println!("Quadratic-time (bubble sort) operations count = {}", count);
count = exponential(n);
println!("Exponential-time (iterative) operations count = {}", count);
count = exp_recur(n);
println!("Exponential-time (recursive) operations count = {}", count);
count = logarithmic(n);
println!("Logarithmic-time (iterative) operations count = {}", count);
count = log_recur(n);
println!("Logarithmic-time (recursive) operations count = {}", count);
count = linear_log_recur(n);
println!("Linearithmic-time (recursive) operations count = {}", count);
count = factorial_recur(n);
println!("Factorial-time (recursive) operations count = {}", count);
}
@@ -0,0 +1,42 @@
/*
* File: worst_best_time_complexity.rs
* Created Time: 2023-01-13
* Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
use rand::seq::SliceRandom;
use rand::thread_rng;
/* Generate an array with elements { 1, 2, ..., n }, order shuffled */
fn random_numbers(n: i32) -> Vec<i32> {
// Generate array nums = { 1, 2, 3, ..., n }
let mut nums = (1..=n).collect::<Vec<i32>>();
// Randomly shuffle array elements
nums.shuffle(&mut thread_rng());
nums
}
/* Find the index of number 1 in array nums */
fn find_one(nums: &[i32]) -> Option<usize> {
for i in 0..nums.len() {
// When element 1 is at the head of the array, best time complexity O(1) is achieved
// When element 1 is at the tail of the array, worst time complexity O(n) is achieved
if nums[i] == 1 {
return Some(i);
}
}
None
}
/* Driver Code */
fn main() {
for _ in 0..10 {
let n = 100;
let nums = random_numbers(n);
let index = find_one(&nums).unwrap();
print!("\nArray [ 1, 2, ..., n ] after shuffling = ");
print_util::print_array(&nums);
println!("\nIndex of number 1 is {}", index);
}
}
@@ -0,0 +1,41 @@
/*
* File: binary_search_recur.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
/* Binary search: problem f(i, j) */
fn dfs(nums: &[i32], target: i32, i: i32, j: i32) -> i32 {
// If the interval is empty, it means there is no target element, return -1
if i > j {
return -1;
}
let m: i32 = i + (j - i) / 2;
if nums[m as usize] < target {
// Recursion subproblem f(m+1, j)
return dfs(nums, target, m + 1, j);
} else if nums[m as usize] > target {
// Recursion subproblem f(i, m-1)
return dfs(nums, target, i, m - 1);
} else {
// Found the target element, return its index
return m;
}
}
/* Binary search */
fn binary_search(nums: &[i32], target: i32) -> i32 {
let n = nums.len() as i32;
// Solve the problem f(0, n-1)
dfs(nums, target, 0, n - 1)
}
/* Driver Code */
pub fn main() {
let target = 6;
let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35];
// Binary search (closed interval on both sides)
let index = binary_search(&nums, target);
println!("Index of target element 6 is {index}");
}
@@ -0,0 +1,56 @@
/*
* File: build_tree.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, TreeNode};
use std::collections::HashMap;
use std::{cell::RefCell, rc::Rc};
/* Build binary tree: divide and conquer */
fn dfs(
preorder: &[i32],
inorder_map: &HashMap<i32, i32>,
i: i32,
l: i32,
r: i32,
) -> Option<Rc<RefCell<TreeNode>>> {
// Terminate when the subtree interval is empty
if r - l < 0 {
return None;
}
// Initialize the root node
let root = TreeNode::new(preorder[i as usize]);
// Query m to divide the left and right subtrees
let m = inorder_map.get(&preorder[i as usize]).unwrap();
// Subproblem: build the left subtree
root.borrow_mut().left = dfs(preorder, inorder_map, i + 1, l, m - 1);
// Subproblem: build the right subtree
root.borrow_mut().right = dfs(preorder, inorder_map, i + 1 + m - l, m + 1, r);
// Return the root node
Some(root)
}
/* Build binary tree */
fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option<Rc<RefCell<TreeNode>>> {
// Initialize hash map, storing the mapping from inorder elements to indices
let mut inorder_map: HashMap<i32, i32> = HashMap::new();
for i in 0..inorder.len() {
inorder_map.insert(inorder[i], i as i32);
}
let root = dfs(preorder, &inorder_map, 0, 0, inorder.len() as i32 - 1);
root
}
/* Driver Code */
fn main() {
let preorder = [3, 9, 2, 1, 7];
let inorder = [9, 3, 1, 2, 7];
println!("In-order traversal = {:?}", preorder);
println!("Pre-order traversal = {:?}", inorder);
let root = build_tree(&preorder, &inorder);
println!("The constructed binary tree is:");
print_util::print_tree(root.as_ref().unwrap());
}
@@ -0,0 +1,55 @@
/*
* File: hanota.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
#![allow(non_snake_case)]
/* Move a disk */
fn move_pan(src: &mut Vec<i32>, tar: &mut Vec<i32>) {
// Take out a disk from the top of src
let pan = src.pop().unwrap();
// Place the disk on top of tar
tar.push(pan);
}
/* Solve the Tower of Hanoi problem f(i) */
fn dfs(i: i32, src: &mut Vec<i32>, buf: &mut Vec<i32>, tar: &mut Vec<i32>) {
// If there is only one disk left in src, move it directly to tar
if i == 1 {
move_pan(src, tar);
return;
}
// Subproblem f(i-1): move the top i-1 disks from src to buf using tar
dfs(i - 1, src, tar, buf);
// Subproblem f(1): move the remaining disk from src to tar
move_pan(src, tar);
// Subproblem f(i-1): move the top i-1 disks from buf to tar using src
dfs(i - 1, buf, src, tar);
}
/* Solve the Tower of Hanoi problem */
fn solve_hanota(A: &mut Vec<i32>, B: &mut Vec<i32>, C: &mut Vec<i32>) {
let n = A.len() as i32;
// Move the top n disks from A to C using B
dfs(n, A, B, C);
}
/* Driver Code */
pub fn main() {
let mut A = vec![5, 4, 3, 2, 1];
let mut B = Vec::new();
let mut C = Vec::new();
println!("In initial state:");
println!("A = {:?}", A);
println!("B = {:?}", B);
println!("C = {:?}", C);
solve_hanota(&mut A, &mut B, &mut C);
println!("After disk movement is complete:");
println!("A = {:?}", A);
println!("B = {:?}", B);
println!("C = {:?}", C);
}
@@ -0,0 +1,41 @@
/*
* File: climbing_stairs_backtrack.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Backtracking */
fn backtrack(choices: &[i32], state: i32, n: i32, res: &mut [i32]) {
// When climbing to the n-th stair, add 1 to the solution count
if state == n {
res[0] = res[0] + 1;
}
// Traverse all choices
for &choice in choices {
// Pruning: not allowed to go beyond the n-th stair
if state + choice > n {
continue;
}
// Attempt: make choice, update state
backtrack(choices, state + choice, n, res);
// Backtrack
}
}
/* Climbing stairs: Backtracking */
fn climbing_stairs_backtrack(n: usize) -> i32 {
let choices = vec![1, 2]; // Can choose to climb up 1 or 2 stairs
let state = 0; // Start climbing from the 0-th stair
let mut res = Vec::new();
res.push(0); // Use res[0] to record the solution count
backtrack(&choices, state, n as i32, &mut res);
res[0]
}
/* Driver Code */
pub fn main() {
let n: usize = 9;
let res = climbing_stairs_backtrack(n);
println!("Climbing {n} stairs has {res} solutions");
}
@@ -0,0 +1,33 @@
/*
* File: climbing_stairs_constraint_dp.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Climbing stairs with constraint: Dynamic programming */
fn climbing_stairs_constraint_dp(n: usize) -> i32 {
if n == 1 || n == 2 {
return 1;
};
// Initialize dp table, used to store solutions to subproblems
let mut dp = vec![vec![-1; 3]; n + 1];
// Initial state: preset the solution to the smallest subproblem
dp[1][1] = 1;
dp[1][2] = 0;
dp[2][1] = 0;
dp[2][2] = 1;
// State transition: gradually solve larger subproblems from smaller ones
for i in 3..=n {
dp[i][1] = dp[i - 1][2];
dp[i][2] = dp[i - 2][1] + dp[i - 2][2];
}
dp[n][1] + dp[n][2]
}
/* Driver Code */
pub fn main() {
let n: usize = 9;
let res = climbing_stairs_constraint_dp(n);
println!("Climbing {n} stairs has {res} solutions");
}
@@ -0,0 +1,29 @@
/*
* File: climbing_stairs_dfs.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Search */
fn dfs(i: usize) -> i32 {
// Known dp[1] and dp[2], return them
if i == 1 || i == 2 {
return i as i32;
}
// dp[i] = dp[i-1] + dp[i-2]
let count = dfs(i - 1) + dfs(i - 2);
count
}
/* Climbing stairs: Search */
fn climbing_stairs_dfs(n: usize) -> i32 {
dfs(n)
}
/* Driver Code */
pub fn main() {
let n: usize = 9;
let res = climbing_stairs_dfs(n);
println!("Climbing {n} stairs has {res} solutions");
}
@@ -0,0 +1,37 @@
/*
* File: climbing_stairs_dfs_mem.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Memoization search */
fn dfs(i: usize, mem: &mut [i32]) -> i32 {
// Known dp[1] and dp[2], return them
if i == 1 || i == 2 {
return i as i32;
}
// If record dp[i] exists, return it directly
if mem[i] != -1 {
return mem[i];
}
// dp[i] = dp[i-1] + dp[i-2]
let count = dfs(i - 1, mem) + dfs(i - 2, mem);
// Record dp[i]
mem[i] = count;
count
}
/* Climbing stairs: Memoization search */
fn climbing_stairs_dfs_mem(n: usize) -> i32 {
// mem[i] records the total number of solutions to climb to the i-th stair, -1 means no record
let mut mem = vec![-1; n + 1];
dfs(n, &mut mem)
}
/* Driver Code */
pub fn main() {
let n: usize = 9;
let res = climbing_stairs_dfs_mem(n);
println!("Climbing {n} stairs has {res} solutions");
}
@@ -0,0 +1,48 @@
/*
* File: climbing_stairs_dp.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Climbing stairs: Dynamic programming */
fn climbing_stairs_dp(n: usize) -> i32 {
// Known dp[1] and dp[2], return them
if n == 1 || n == 2 {
return n as i32;
}
// Initialize dp table, used to store solutions to subproblems
let mut dp = vec![-1; n + 1];
// Initial state: preset the solution to the smallest subproblem
dp[1] = 1;
dp[2] = 2;
// State transition: gradually solve larger subproblems from smaller ones
for i in 3..=n {
dp[i] = dp[i - 1] + dp[i - 2];
}
dp[n]
}
/* Climbing stairs: Space-optimized dynamic programming */
fn climbing_stairs_dp_comp(n: usize) -> i32 {
if n == 1 || n == 2 {
return n as i32;
}
let (mut a, mut b) = (1, 2);
for _ in 3..=n {
let tmp = b;
b = a + b;
a = tmp;
}
b
}
/* Driver Code */
pub fn main() {
let n: usize = 9;
let res = climbing_stairs_dp(n);
println!("Climbing {n} stairs has {res} solutions");
let res = climbing_stairs_dp_comp(n);
println!("Climbing {n} stairs has {res} solutions");
}
@@ -0,0 +1,75 @@
/*
* File: coin_change.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Coin change: Dynamic programming */
fn coin_change_dp(coins: &[i32], amt: usize) -> i32 {
let n = coins.len();
let max = amt + 1;
// Initialize dp table
let mut dp = vec![vec![0; amt + 1]; n + 1];
// State transition: first row and first column
for a in 1..=amt {
dp[0][a] = max;
}
// State transition: rest of the rows and columns
for i in 1..=n {
for a in 1..=amt {
if coins[i - 1] > a as i32 {
// If exceeds target amount, don't select coin i
dp[i][a] = dp[i - 1][a];
} else {
// The smaller value between not selecting and selecting coin i
dp[i][a] = std::cmp::min(dp[i - 1][a], dp[i][a - coins[i - 1] as usize] + 1);
}
}
}
if dp[n][amt] != max {
return dp[n][amt] as i32;
} else {
-1
}
}
/* Coin change: Space-optimized dynamic programming */
fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 {
let n = coins.len();
let max = amt + 1;
// Initialize dp table
let mut dp = vec![0; amt + 1];
dp.fill(max);
dp[0] = 0;
// State transition
for i in 1..=n {
for a in 1..=amt {
if coins[i - 1] > a as i32 {
// If exceeds target amount, don't select coin i
dp[a] = dp[a];
} else {
// The smaller value between not selecting and selecting coin i
dp[a] = std::cmp::min(dp[a], dp[a - coins[i - 1] as usize] + 1);
}
}
}
if dp[amt] != max {
return dp[amt] as i32;
} else {
-1
}
}
/* Driver Code */
pub fn main() {
let coins = [1, 2, 5];
let amt: usize = 4;
// Dynamic programming
let res = coin_change_dp(&coins, amt);
println!("Minimum coins needed to make target amount is {res}");
// Space-optimized dynamic programming
let res = coin_change_dp_comp(&coins, amt);
println!("Minimum coins needed to make target amount is {res}");
}
@@ -0,0 +1,64 @@
/*
* File: coin_change_ii.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Coin change II: Dynamic programming */
fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 {
let n = coins.len();
// Initialize dp table
let mut dp = vec![vec![0; amt + 1]; n + 1];
// Initialize first column
for i in 0..=n {
dp[i][0] = 1;
}
// State transition
for i in 1..=n {
for a in 1..=amt {
if coins[i - 1] > a as i32 {
// If exceeds target amount, don't select coin i
dp[i][a] = dp[i - 1][a];
} else {
// Sum of the two options: not selecting and selecting coin i
dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1] as usize];
}
}
}
dp[n][amt]
}
/* Coin change II: Space-optimized dynamic programming */
fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 {
let n = coins.len();
// Initialize dp table
let mut dp = vec![0; amt + 1];
dp[0] = 1;
// State transition
for i in 1..=n {
for a in 1..=amt {
if coins[i - 1] > a as i32 {
// If exceeds target amount, don't select coin i
dp[a] = dp[a];
} else {
// Sum of the two options: not selecting and selecting coin i
dp[a] = dp[a] + dp[a - coins[i - 1] as usize];
}
}
}
dp[amt]
}
/* Driver Code */
pub fn main() {
let coins = [1, 2, 5];
let amt: usize = 5;
// Dynamic programming
let res = coin_change_ii_dp(&coins, amt);
println!("Number of coin combinations to make target amount is {res}");
// Space-optimized dynamic programming
let res = coin_change_ii_dp_comp(&coins, amt);
println!("Number of coin combinations to make target amount is {res}");
}
@@ -0,0 +1,145 @@
/*
* File: edit_distance.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Edit distance: Brute-force search */
fn edit_distance_dfs(s: &str, t: &str, i: usize, j: usize) -> i32 {
// If both s and t are empty, return 0
if i == 0 && j == 0 {
return 0;
}
// If s is empty, return length of t
if i == 0 {
return j as i32;
}
// If t is empty, return length of s
if j == 0 {
return i as i32;
}
// If two characters are equal, skip both characters
if s.chars().nth(i - 1) == t.chars().nth(j - 1) {
return edit_distance_dfs(s, t, i - 1, j - 1);
}
// Minimum edit steps = minimum edit steps of insert, delete, replace + 1
let insert = edit_distance_dfs(s, t, i, j - 1);
let delete = edit_distance_dfs(s, t, i - 1, j);
let replace = edit_distance_dfs(s, t, i - 1, j - 1);
// Return minimum edit steps
std::cmp::min(std::cmp::min(insert, delete), replace) + 1
}
/* Edit distance: Memoization search */
fn edit_distance_dfs_mem(s: &str, t: &str, mem: &mut Vec<Vec<i32>>, i: usize, j: usize) -> i32 {
// If both s and t are empty, return 0
if i == 0 && j == 0 {
return 0;
}
// If s is empty, return length of t
if i == 0 {
return j as i32;
}
// If t is empty, return length of s
if j == 0 {
return i as i32;
}
// If there's a record, return it directly
if mem[i][j] != -1 {
return mem[i][j];
}
// If two characters are equal, skip both characters
if s.chars().nth(i - 1) == t.chars().nth(j - 1) {
return edit_distance_dfs_mem(s, t, mem, i - 1, j - 1);
}
// Minimum edit steps = minimum edit steps of insert, delete, replace + 1
let insert = edit_distance_dfs_mem(s, t, mem, i, j - 1);
let delete = edit_distance_dfs_mem(s, t, mem, i - 1, j);
let replace = edit_distance_dfs_mem(s, t, mem, i - 1, j - 1);
// Record and return minimum edit steps
mem[i][j] = std::cmp::min(std::cmp::min(insert, delete), replace) + 1;
mem[i][j]
}
/* Edit distance: Dynamic programming */
fn edit_distance_dp(s: &str, t: &str) -> i32 {
let (n, m) = (s.len(), t.len());
let mut dp = vec![vec![0; m + 1]; n + 1];
// State transition: first row and first column
for i in 1..=n {
dp[i][0] = i as i32;
}
for j in 1..m {
dp[0][j] = j as i32;
}
// State transition: rest of the rows and columns
for i in 1..=n {
for j in 1..=m {
if s.chars().nth(i - 1) == t.chars().nth(j - 1) {
// If two characters are equal, skip both characters
dp[i][j] = dp[i - 1][j - 1];
} else {
// Minimum edit steps = minimum edit steps of insert, delete, replace + 1
dp[i][j] =
std::cmp::min(std::cmp::min(dp[i][j - 1], dp[i - 1][j]), dp[i - 1][j - 1]) + 1;
}
}
}
dp[n][m]
}
/* Edit distance: Space-optimized dynamic programming */
fn edit_distance_dp_comp(s: &str, t: &str) -> i32 {
let (n, m) = (s.len(), t.len());
let mut dp = vec![0; m + 1];
// State transition: first row
for j in 1..m {
dp[j] = j as i32;
}
// State transition: rest of the rows
for i in 1..=n {
// State transition: first column
let mut leftup = dp[0]; // Temporarily store dp[i-1, j-1]
dp[0] = i as i32;
// State transition: rest of the columns
for j in 1..=m {
let temp = dp[j];
if s.chars().nth(i - 1) == t.chars().nth(j - 1) {
// If two characters are equal, skip both characters
dp[j] = leftup;
} else {
// Minimum edit steps = minimum edit steps of insert, delete, replace + 1
dp[j] = std::cmp::min(std::cmp::min(dp[j - 1], dp[j]), leftup) + 1;
}
leftup = temp; // Update for next round's dp[i-1, j-1]
}
}
dp[m]
}
/* Driver Code */
pub fn main() {
let s = "bag";
let t = "pack";
let (n, m) = (s.len(), t.len());
// Brute-force search
let res = edit_distance_dfs(s, t, n, m);
println!("Changing {s} to {t} requires minimum {res} edits");
// Memoization search
let mut mem = vec![vec![0; m + 1]; n + 1];
for row in mem.iter_mut() {
row.fill(-1);
}
let res = edit_distance_dfs_mem(s, t, &mut mem, n, m);
println!("Changing {s} to {t} requires minimum {res} edits");
// Dynamic programming
let res = edit_distance_dp(s, t);
println!("Changing {s} to {t} requires minimum {res} edits");
// Space-optimized dynamic programming
let res = edit_distance_dp_comp(s, t);
println!("Changing {s} to {t} requires minimum {res} edits");
}
@@ -0,0 +1,113 @@
/*
* File: knapsack.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* 0-1 knapsack: Brute-force search */
fn knapsack_dfs(wgt: &[i32], val: &[i32], i: usize, c: usize) -> i32 {
// If all items have been selected or knapsack has no remaining capacity, return value 0
if i == 0 || c == 0 {
return 0;
}
// If exceeds knapsack capacity, can only choose not to put it in
if wgt[i - 1] > c as i32 {
return knapsack_dfs(wgt, val, i - 1, c);
}
// Calculate the maximum value of not putting in and putting in item i
let no = knapsack_dfs(wgt, val, i - 1, c);
let yes = knapsack_dfs(wgt, val, i - 1, c - wgt[i - 1] as usize) + val[i - 1];
// Return the larger value of the two options
std::cmp::max(no, yes)
}
/* 0-1 knapsack: Memoization search */
fn knapsack_dfs_mem(wgt: &[i32], val: &[i32], mem: &mut Vec<Vec<i32>>, i: usize, c: usize) -> i32 {
// If all items have been selected or knapsack has no remaining capacity, return value 0
if i == 0 || c == 0 {
return 0;
}
// If there's a record, return it directly
if mem[i][c] != -1 {
return mem[i][c];
}
// If exceeds knapsack capacity, can only choose not to put it in
if wgt[i - 1] > c as i32 {
return knapsack_dfs_mem(wgt, val, mem, i - 1, c);
}
// Calculate the maximum value of not putting in and putting in item i
let no = knapsack_dfs_mem(wgt, val, mem, i - 1, c);
let yes = knapsack_dfs_mem(wgt, val, mem, i - 1, c - wgt[i - 1] as usize) + val[i - 1];
// Record and return the larger value of the two options
mem[i][c] = std::cmp::max(no, yes);
mem[i][c]
}
/* 0-1 knapsack: Dynamic programming */
fn knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 {
let n = wgt.len();
// Initialize dp table
let mut dp = vec![vec![0; cap + 1]; n + 1];
// State transition
for i in 1..=n {
for c in 1..=cap {
if wgt[i - 1] > c as i32 {
// If exceeds knapsack capacity, don't select item i
dp[i][c] = dp[i - 1][c];
} else {
// The larger value between not selecting and selecting item i
dp[i][c] = std::cmp::max(
dp[i - 1][c],
dp[i - 1][c - wgt[i - 1] as usize] + val[i - 1],
);
}
}
}
dp[n][cap]
}
/* 0-1 knapsack: Space-optimized dynamic programming */
fn knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 {
let n = wgt.len();
// Initialize dp table
let mut dp = vec![0; cap + 1];
// State transition
for i in 1..=n {
// Traverse in reverse order
for c in (1..=cap).rev() {
if wgt[i - 1] <= c as i32 {
// The larger value between not selecting and selecting item i
dp[c] = std::cmp::max(dp[c], dp[c - wgt[i - 1] as usize] + val[i - 1]);
}
}
}
dp[cap]
}
/* Driver Code */
pub fn main() {
let wgt = [10, 20, 30, 40, 50];
let val = [50, 120, 150, 210, 240];
let cap: usize = 50;
let n = wgt.len();
// Brute-force search
let res = knapsack_dfs(&wgt, &val, n, cap);
println!("Maximum item value not exceeding knapsack capacity is {res}");
// Memoization search
let mut mem = vec![vec![0; cap + 1]; n + 1];
for row in mem.iter_mut() {
row.fill(-1);
}
let res = knapsack_dfs_mem(&wgt, &val, &mut mem, n, cap);
println!("Maximum item value not exceeding knapsack capacity is {res}");
// Dynamic programming
let res = knapsack_dp(&wgt, &val, cap);
println!("Maximum item value not exceeding knapsack capacity is {res}");
// Space-optimized dynamic programming
let res = knapsack_dp_comp(&wgt, &val, cap);
println!("Maximum item value not exceeding knapsack capacity is {res}");
}
@@ -0,0 +1,52 @@
/*
* File: min_cost_climbing_stairs_dp.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
use std::cmp;
/* Minimum cost climbing stairs: Dynamic programming */
fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 {
let n = cost.len() - 1;
if n == 1 || n == 2 {
return cost[n];
}
// Initialize dp table, used to store solutions to subproblems
let mut dp = vec![-1; n + 1];
// Initial state: preset the solution to the smallest subproblem
dp[1] = cost[1];
dp[2] = cost[2];
// State transition: gradually solve larger subproblems from smaller ones
for i in 3..=n {
dp[i] = cmp::min(dp[i - 1], dp[i - 2]) + cost[i];
}
dp[n]
}
/* Minimum cost climbing stairs: Space-optimized dynamic programming */
fn min_cost_climbing_stairs_dp_comp(cost: &[i32]) -> i32 {
let n = cost.len() - 1;
if n == 1 || n == 2 {
return cost[n];
};
let (mut a, mut b) = (cost[1], cost[2]);
for i in 3..=n {
let tmp = b;
b = cmp::min(a, tmp) + cost[i];
a = tmp;
}
b
}
/* Driver Code */
pub fn main() {
let cost = [0, 1, 10, 1, 1, 1, 10, 1, 1, 10, 1];
println!("Input stair cost list is {:?}", &cost);
let res = min_cost_climbing_stairs_dp(&cost);
println!("Minimum cost to climb stairs is {res}");
let res = min_cost_climbing_stairs_dp_comp(&cost);
println!("Minimum cost to climb stairs is {res}");
}
@@ -0,0 +1,120 @@
/*
* File: min_path_sum.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Minimum path sum: Brute-force search */
fn min_path_sum_dfs(grid: &Vec<Vec<i32>>, i: i32, j: i32) -> i32 {
// If it's the top-left cell, terminate the search
if i == 0 && j == 0 {
return grid[0][0];
}
// If row or column index is out of bounds, return +∞ cost
if i < 0 || j < 0 {
return i32::MAX;
}
// Calculate the minimum path cost from top-left to (i-1, j) and (i, j-1)
let up = min_path_sum_dfs(grid, i - 1, j);
let left = min_path_sum_dfs(grid, i, j - 1);
// Return the minimum path cost from top-left to (i, j)
std::cmp::min(left, up) + grid[i as usize][j as usize]
}
/* Minimum path sum: Memoization search */
fn min_path_sum_dfs_mem(grid: &Vec<Vec<i32>>, mem: &mut Vec<Vec<i32>>, i: i32, j: i32) -> i32 {
// If it's the top-left cell, terminate the search
if i == 0 && j == 0 {
return grid[0][0];
}
// If row or column index is out of bounds, return +∞ cost
if i < 0 || j < 0 {
return i32::MAX;
}
// If there's a record, return it directly
if mem[i as usize][j as usize] != -1 {
return mem[i as usize][j as usize];
}
// Minimum path cost for left and upper cells
let up = min_path_sum_dfs_mem(grid, mem, i - 1, j);
let left = min_path_sum_dfs_mem(grid, mem, i, j - 1);
// Record and return the minimum path cost from top-left to (i, j)
mem[i as usize][j as usize] = std::cmp::min(left, up) + grid[i as usize][j as usize];
mem[i as usize][j as usize]
}
/* Minimum path sum: Dynamic programming */
fn min_path_sum_dp(grid: &Vec<Vec<i32>>) -> i32 {
let (n, m) = (grid.len(), grid[0].len());
// Initialize dp table
let mut dp = vec![vec![0; m]; n];
dp[0][0] = grid[0][0];
// State transition: first row
for j in 1..m {
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
// State transition: first column
for i in 1..n {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
// State transition: rest of the rows and columns
for i in 1..n {
for j in 1..m {
dp[i][j] = std::cmp::min(dp[i][j - 1], dp[i - 1][j]) + grid[i][j];
}
}
dp[n - 1][m - 1]
}
/* Minimum path sum: Space-optimized dynamic programming */
fn min_path_sum_dp_comp(grid: &Vec<Vec<i32>>) -> i32 {
let (n, m) = (grid.len(), grid[0].len());
// Initialize dp table
let mut dp = vec![0; m];
// State transition: first row
dp[0] = grid[0][0];
for j in 1..m {
dp[j] = dp[j - 1] + grid[0][j];
}
// State transition: rest of the rows
for i in 1..n {
// State transition: first column
dp[0] = dp[0] + grid[i][0];
// State transition: rest of the columns
for j in 1..m {
dp[j] = std::cmp::min(dp[j - 1], dp[j]) + grid[i][j];
}
}
dp[m - 1]
}
/* Driver Code */
pub fn main() {
let grid = vec![
vec![1, 3, 1, 5],
vec![2, 2, 4, 2],
vec![5, 3, 2, 1],
vec![4, 3, 5, 2],
];
let (n, m) = (grid.len(), grid[0].len());
// Brute-force search
let res = min_path_sum_dfs(&grid, n as i32 - 1, m as i32 - 1);
println!("Minimum path sum from top-left to bottom-right is {res}");
// Memoization search
let mut mem = vec![vec![0; m]; n];
for row in mem.iter_mut() {
row.fill(-1);
}
let res = min_path_sum_dfs_mem(&grid, &mut mem, n as i32 - 1, m as i32 - 1);
println!("Minimum path sum from top-left to bottom-right is {res}");
// Dynamic programming
let res = min_path_sum_dp(&grid);
println!("Minimum path sum from top-left to bottom-right is {res}");
// Space-optimized dynamic programming
let res = min_path_sum_dp_comp(&grid);
println!("Minimum path sum from top-left to bottom-right is {res}");
}
@@ -0,0 +1,60 @@
/*
* File: unbounded_knapsack.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Unbounded knapsack: Dynamic programming */
fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 {
let n = wgt.len();
// Initialize dp table
let mut dp = vec![vec![0; cap + 1]; n + 1];
// State transition
for i in 1..=n {
for c in 1..=cap {
if wgt[i - 1] > c as i32 {
// If exceeds knapsack capacity, don't select item i
dp[i][c] = dp[i - 1][c];
} else {
// The larger value between not selecting and selecting item i
dp[i][c] = std::cmp::max(dp[i - 1][c], dp[i][c - wgt[i - 1] as usize] + val[i - 1]);
}
}
}
return dp[n][cap];
}
/* Unbounded knapsack: Space-optimized dynamic programming */
fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 {
let n = wgt.len();
// Initialize dp table
let mut dp = vec![0; cap + 1];
// State transition
for i in 1..=n {
for c in 1..=cap {
if wgt[i - 1] > c as i32 {
// If exceeds knapsack capacity, don't select item i
dp[c] = dp[c];
} else {
// The larger value between not selecting and selecting item i
dp[c] = std::cmp::max(dp[c], dp[c - wgt[i - 1] as usize] + val[i - 1]);
}
}
}
dp[cap]
}
/* Driver Code */
pub fn main() {
let wgt = [1, 2, 3];
let val = [5, 11, 15];
let cap: usize = 4;
// Dynamic programming
let res = unbounded_knapsack_dp(&wgt, &val, cap);
println!("Maximum item value not exceeding knapsack capacity is {res}");
// Space-optimized dynamic programming
let res = unbounded_knapsack_dp_comp(&wgt, &val, cap);
println!("Maximum item value not exceeding knapsack capacity is {res}");
}
@@ -0,0 +1,135 @@
/*
* File: graph_adjacency_list.rs
* Created Time: 2023-07-12
* Author: night-cruise (2586447362@qq.com)
*/
pub use hello_algo_rust::include::{vals_to_vets, vets_to_vals, Vertex};
use std::collections::HashMap;
/* Undirected graph type based on adjacency list */
pub struct GraphAdjList {
// Adjacency list, key: vertex, value: all adjacent vertices of that vertex
pub adj_list: HashMap<Vertex, Vec<Vertex>>, // maybe HashSet<Vertex> for value part is better?
}
impl GraphAdjList {
/* Constructor */
pub fn new(edges: Vec<[Vertex; 2]>) -> Self {
let mut graph = GraphAdjList {
adj_list: HashMap::new(),
};
// Add all vertices and edges
for edge in edges {
graph.add_vertex(edge[0]);
graph.add_vertex(edge[1]);
graph.add_edge(edge[0], edge[1]);
}
graph
}
/* Get the number of vertices */
#[allow(unused)]
pub fn size(&self) -> usize {
self.adj_list.len()
}
/* Add edge */
pub fn add_edge(&mut self, vet1: Vertex, vet2: Vertex) {
if vet1 == vet2 {
panic!("value error");
}
// Add edge vet1 - vet2
self.adj_list.entry(vet1).or_default().push(vet2);
self.adj_list.entry(vet2).or_default().push(vet1);
}
/* Remove edge */
#[allow(unused)]
pub fn remove_edge(&mut self, vet1: Vertex, vet2: Vertex) {
if vet1 == vet2 {
panic!("value error");
}
// Remove edge vet1 - vet2
self.adj_list
.entry(vet1)
.and_modify(|v| v.retain(|&e| e != vet2));
self.adj_list
.entry(vet2)
.and_modify(|v| v.retain(|&e| e != vet1));
}
/* Add vertex */
pub fn add_vertex(&mut self, vet: Vertex) {
if self.adj_list.contains_key(&vet) {
return;
}
// Add a new linked list in the adjacency list
self.adj_list.insert(vet, vec![]);
}
/* Remove vertex */
#[allow(unused)]
pub fn remove_vertex(&mut self, vet: Vertex) {
// Remove the linked list corresponding to vertex vet in the adjacency list
self.adj_list.remove(&vet);
// Traverse the linked lists of other vertices and remove all edges containing vet
for list in self.adj_list.values_mut() {
list.retain(|&v| v != vet);
}
}
/* Print adjacency list */
pub fn print(&self) {
println!("Adjacency list =");
for (vertex, list) in &self.adj_list {
let list = list.iter().map(|vertex| vertex.val).collect::<Vec<i32>>();
println!("{}: {:?},", vertex.val, list);
}
}
}
/* Driver Code */
#[allow(unused)]
fn main() {
/* Add edge */
let v = vals_to_vets(vec![1, 3, 2, 5, 4]);
let edges = vec![
[v[0], v[1]],
[v[0], v[3]],
[v[1], v[2]],
[v[2], v[3]],
[v[2], v[4]],
[v[3], v[4]],
];
let mut graph = GraphAdjList::new(edges);
println!("\nAfter initialization, graph is");
graph.print();
/* Add edge */
// Vertices 1, 3 are v[0], v[1]
graph.add_edge(v[0], v[2]);
println!("\nAfter adding edge 1-2, graph is");
graph.print();
/* Remove edge */
// Vertex 3 is v[1]
graph.remove_edge(v[0], v[1]);
println!("\nAfter removing edge 1-3, graph is");
graph.print();
/* Add vertex */
let v5 = Vertex { val: 6 };
graph.add_vertex(v5);
println!("\nAfter adding vertex 6, graph is");
graph.print();
/* Remove vertex */
// Vertex 3 is v[1]
graph.remove_vertex(v[1]);
println!("\nAfter removing vertex 3, graph is");
graph.print();
}
@@ -0,0 +1,136 @@
/*
* File: graph_adjacency_matrix.rs
* Created Time: 2023-07-12
* Author: night-cruise (2586447362@qq.com)
*/
/* Undirected graph type based on adjacency matrix */
pub struct GraphAdjMat {
// Vertex list, where the element represents the "vertex value" and the index represents the "vertex index"
pub vertices: Vec<i32>,
// Adjacency matrix, where the row and column indices correspond to the "vertex index"
pub adj_mat: Vec<Vec<i32>>,
}
impl GraphAdjMat {
/* Constructor */
pub fn new(vertices: Vec<i32>, edges: Vec<[usize; 2]>) -> Self {
let mut graph = GraphAdjMat {
vertices: vec![],
adj_mat: vec![],
};
// Add vertex
for val in vertices {
graph.add_vertex(val);
}
// Add edge
// Note that the edges elements represent vertex indices, i.e., corresponding to the vertices element indices
for edge in edges {
graph.add_edge(edge[0], edge[1])
}
graph
}
/* Get the number of vertices */
pub fn size(&self) -> usize {
self.vertices.len()
}
/* Add vertex */
pub fn add_vertex(&mut self, val: i32) {
let n = self.size();
// Add the value of the new vertex to the vertex list
self.vertices.push(val);
// Add a row to the adjacency matrix
self.adj_mat.push(vec![0; n]);
// Add a column to the adjacency matrix
for row in self.adj_mat.iter_mut() {
row.push(0);
}
}
/* Remove vertex */
pub fn remove_vertex(&mut self, index: usize) {
if index >= self.size() {
panic!("index error")
}
// Remove the vertex at index from the vertex list
self.vertices.remove(index);
// Remove the row at index from the adjacency matrix
self.adj_mat.remove(index);
// Remove the column at index from the adjacency matrix
for row in self.adj_mat.iter_mut() {
row.remove(index);
}
}
/* Add edge */
pub fn add_edge(&mut self, i: usize, j: usize) {
// Parameters i, j correspond to the vertices element indices
// Handle index out of bounds and equality
if i >= self.size() || j >= self.size() || i == j {
panic!("index error")
}
// In an undirected graph, the adjacency matrix is symmetric about the main diagonal, i.e., (i, j) == (j, i)
self.adj_mat[i][j] = 1;
self.adj_mat[j][i] = 1;
}
/* Remove edge */
// Parameters i, j correspond to the vertices element indices
pub fn remove_edge(&mut self, i: usize, j: usize) {
// Parameters i, j correspond to the vertices element indices
// Handle index out of bounds and equality
if i >= self.size() || j >= self.size() || i == j {
panic!("index error")
}
self.adj_mat[i][j] = 0;
self.adj_mat[j][i] = 0;
}
/* Print adjacency matrix */
pub fn print(&self) {
println!("Vertex list = {:?}", self.vertices);
println!("Adjacency matrix =");
println!("[");
for row in &self.adj_mat {
println!(" {:?},", row);
}
println!("]")
}
}
/* Driver Code */
fn main() {
/* Add edge */
// Note that the edges elements represent vertex indices, i.e., corresponding to the vertices element indices
let vertices = vec![1, 3, 2, 5, 4];
let edges = vec![[0, 1], [0, 3], [1, 2], [2, 3], [2, 4], [3, 4]];
let mut graph = GraphAdjMat::new(vertices, edges);
println!("\nAfter initialization, graph is");
graph.print();
/* Add edge */
// Add vertex
graph.add_edge(0, 2);
println!("\nAfter adding edge 1-2, graph is");
graph.print();
/* Remove edge */
// Vertices 1, 3 have indices 0, 1 respectively
graph.remove_edge(0, 1);
println!("\nAfter removing edge 1-3, graph is");
graph.print();
/* Add vertex */
graph.add_vertex(6);
println!("\nAfter adding vertex 6, graph is");
graph.print();
/* Remove vertex */
// Vertex 3 has index 1
graph.remove_vertex(1);
println!("\nAfter removing vertex 3, graph is");
graph.print();
}
+69
View File
@@ -0,0 +1,69 @@
/*
* File: graph_bfs.rs
* Created Time: 2023-07-12
* Author: night-cruise (2586447362@qq.com)
*/
mod graph_adjacency_list;
use graph_adjacency_list::GraphAdjList;
use graph_adjacency_list::{vals_to_vets, vets_to_vals, Vertex};
use std::collections::{HashSet, VecDeque};
/* Breadth-first traversal */
// Use adjacency list to represent the graph, in order to obtain all adjacent vertices of a specified vertex
fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
// Vertex traversal sequence
let mut res = vec![];
// Hash set for recording vertices that have been visited
let mut visited = HashSet::new();
visited.insert(start_vet);
// Queue used to implement BFS
let mut que = VecDeque::new();
que.push_back(start_vet);
// Starting from vertex vet, loop until all vertices are visited
while let Some(vet) = que.pop_front() {
res.push(vet); // Record visited vertex
// Traverse all adjacent vertices of this vertex
if let Some(adj_vets) = graph.adj_list.get(&vet) {
for &adj_vet in adj_vets {
if visited.contains(&adj_vet) {
continue; // Skip vertices that have been visited
}
que.push_back(adj_vet); // Only enqueue unvisited vertices
visited.insert(adj_vet); // Mark this vertex as visited
}
}
}
// Return vertex traversal sequence
res
}
/* Driver Code */
fn main() {
/* Add edge */
let v = vals_to_vets(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let edges = vec![
[v[0], v[1]],
[v[0], v[3]],
[v[1], v[2]],
[v[1], v[4]],
[v[2], v[5]],
[v[3], v[4]],
[v[3], v[6]],
[v[4], v[5]],
[v[4], v[7]],
[v[5], v[8]],
[v[6], v[7]],
[v[7], v[8]],
];
let graph = GraphAdjList::new(edges);
println!("\nAfter initialization, graph is");
graph.print();
/* Breadth-first traversal */
let res = graph_bfs(graph, v[0]);
println!("\nBreadth-first traversal (BFS) vertex sequence is");
println!("{:?}", vets_to_vals(res));
}
+61
View File
@@ -0,0 +1,61 @@
/*
* File: graph_dfs.rs
* Created Time: 2023-07-12
* Author: night-cruise (2586447362@qq.com)
*/
mod graph_adjacency_list;
use graph_adjacency_list::GraphAdjList;
use graph_adjacency_list::{vals_to_vets, vets_to_vals, Vertex};
use std::collections::HashSet;
/* Depth-first traversal helper function */
fn dfs(graph: &GraphAdjList, visited: &mut HashSet<Vertex>, res: &mut Vec<Vertex>, vet: Vertex) {
res.push(vet); // Record visited vertex
visited.insert(vet); // Mark this vertex as visited
// Traverse all adjacent vertices of this vertex
if let Some(adj_vets) = graph.adj_list.get(&vet) {
for &adj_vet in adj_vets {
if visited.contains(&adj_vet) {
continue; // Skip vertices that have been visited
}
// Recursively visit adjacent vertices
dfs(graph, visited, res, adj_vet);
}
}
}
/* Depth-first traversal */
// Use adjacency list to represent the graph, in order to obtain all adjacent vertices of a specified vertex
fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
// Vertex traversal sequence
let mut res = vec![];
// Hash set for recording vertices that have been visited
let mut visited = HashSet::new();
dfs(&graph, &mut visited, &mut res, start_vet);
res
}
/* Driver Code */
fn main() {
/* Add edge */
let v = vals_to_vets(vec![0, 1, 2, 3, 4, 5, 6]);
let edges = vec![
[v[0], v[1]],
[v[0], v[3]],
[v[1], v[2]],
[v[2], v[5]],
[v[4], v[5]],
[v[5], v[6]],
];
let graph = GraphAdjList::new(edges);
println!("\nAfter initialization, graph is");
graph.print();
/* Depth-first traversal */
let res = graph_dfs(graph, v[0]);
println!("\nDepth-first traversal (DFS) vertex sequence is");
println!("{:?}", vets_to_vals(res));
}
@@ -0,0 +1,54 @@
/*
* File: coin_change_greedy.rs
* Created Time: 2023-07-22
* Author: night-cruise (2586447362@qq.com)
*/
/* Coin change: Greedy algorithm */
fn coin_change_greedy(coins: &[i32], mut amt: i32) -> i32 {
// Assume coins list is sorted
let mut i = coins.len() - 1;
let mut count = 0;
// Loop to make greedy choices until no remaining amount
while amt > 0 {
// Find the coin that is less than and closest to the remaining amount
while i > 0 && coins[i] > amt {
i -= 1;
}
// Choose coins[i]
amt -= coins[i];
count += 1;
}
// If no feasible solution is found, return -1
if amt == 0 {
count
} else {
-1
}
}
/* Driver Code */
fn main() {
// Greedy algorithm: Can guarantee finding the global optimal solution
let coins = [1, 5, 10, 20, 50, 100];
let amt = 186;
let res = coin_change_greedy(&coins, amt);
println!("\ncoins = {:?}, amt = {}", coins, amt);
println!("Minimum coins needed to make {} is {}", amt, res);
// Greedy algorithm: Cannot guarantee finding the global optimal solution
let coins = [1, 20, 50];
let amt = 60;
let res = coin_change_greedy(&coins, amt);
println!("\ncoins = {:?}, amt = {}", coins, amt);
println!("Minimum coins needed to make {} is {}", amt, res);
println!("Actually the minimum number needed is 3, i.e., 20 + 20 + 20");
// Greedy algorithm: Cannot guarantee finding the global optimal solution
let coins = [1, 49, 50];
let amt = 98;
let res = coin_change_greedy(&coins, amt);
println!("\ncoins = {:?}, amt = {}", coins, amt);
println!("Minimum coins needed to make {} is {}", amt, res);
println!("Actually the minimum number needed is 2, i.e., 49 + 49");
}
@@ -0,0 +1,59 @@
/*
* File: coin_change_greedy.rs
* Created Time: 2023-07-22
* Author: night-cruise (2586447362@qq.com)
*/
/* Item */
struct Item {
w: i32, // Item weight
v: i32, // Item value
}
impl Item {
fn new(w: i32, v: i32) -> Self {
Self { w, v }
}
}
/* Fractional knapsack: Greedy algorithm */
fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 {
// Create item list with two attributes: weight, value
let mut items = wgt
.iter()
.zip(val.iter())
.map(|(&w, &v)| Item::new(w, v))
.collect::<Vec<Item>>();
// Sort by unit value item.v / item.w from high to low
items.sort_by(|a, b| {
(b.v as f64 / b.w as f64)
.partial_cmp(&(a.v as f64 / a.w as f64))
.unwrap()
});
// Loop for greedy selection
let mut res = 0.0;
for item in &items {
if item.w <= cap {
// If remaining capacity is sufficient, put the entire current item into the knapsack
res += item.v as f64;
cap -= item.w;
} else {
// If remaining capacity is insufficient, put part of the current item into the knapsack
res += item.v as f64 / item.w as f64 * cap as f64;
// No remaining capacity, so break out of the loop
break;
}
}
res
}
/* Driver Code */
fn main() {
let wgt = [10, 20, 30, 40, 50];
let val = [50, 120, 150, 210, 240];
let cap = 50;
// Greedy algorithm
let res = fractional_knapsack(&wgt, &val, cap);
println!("Maximum item value not exceeding knapsack capacity is {}", res);
}
@@ -0,0 +1,36 @@
/*
* File: coin_change_greedy.rs
* Created Time: 2023-07-22
* Author: night-cruise (2586447362@qq.com)
*/
/* Max capacity: Greedy algorithm */
fn max_capacity(ht: &[i32]) -> i32 {
// Initialize i, j to be at both ends of the array
let mut i = 0;
let mut j = ht.len() - 1;
// Initial max capacity is 0
let mut res = 0;
// Loop for greedy selection until the two boards meet
while i < j {
// Update max capacity
let cap = std::cmp::min(ht[i], ht[j]) * (j - i) as i32;
res = std::cmp::max(res, cap);
// Move the shorter board inward
if ht[i] < ht[j] {
i += 1;
} else {
j -= 1;
}
}
res
}
/* Driver Code */
fn main() {
let ht = [3, 8, 5, 2, 7, 7, 3, 4];
// Greedy algorithm
let res = max_capacity(&ht);
println!("Maximum capacity is {}", res);
}
@@ -0,0 +1,35 @@
/*
* File: coin_change_greedy.rs
* Created Time: 2023-07-22
* Author: night-cruise (2586447362@qq.com)
*/
/* Max product cutting: Greedy algorithm */
fn max_product_cutting(n: i32) -> i32 {
// When n <= 3, must cut out a 1
if n <= 3 {
return 1 * (n - 1);
}
// Greedily cut out 3, a is the number of 3s, b is the remainder
let a = n / 3;
let b = n % 3;
if b == 1 {
// When the remainder is 1, convert a pair of 1 * 3 to 2 * 2
3_i32.pow(a as u32 - 1) * 2 * 2
} else if b == 2 {
// When the remainder is 2, do nothing
3_i32.pow(a as u32) * 2
} else {
// When the remainder is 0, do nothing
3_i32.pow(a as u32)
}
}
/* Driver Code */
fn main() {
let n = 58;
// Greedy algorithm
let res = max_product_cutting(n);
println!("Maximum cutting product is {}", res);
}
@@ -0,0 +1,124 @@
/**
* File: array_hash_map.rs
* Created Time: 2023-2-18
* Author: xBLACICEx (xBLACKICEx@outlook.com)
*/
/* Key-value pair */
#[derive(Debug, Clone, PartialEq)]
pub struct Pair {
pub key: i32,
pub val: String,
}
/* Hash table based on array implementation */
pub struct ArrayHashMap {
buckets: Vec<Option<Pair>>,
}
impl ArrayHashMap {
pub fn new() -> ArrayHashMap {
// Initialize array with 100 buckets
Self {
buckets: vec![None; 100],
}
}
/* Hash function */
fn hash_func(&self, key: i32) -> usize {
key as usize % 100
}
/* Query operation */
pub fn get(&self, key: i32) -> Option<&String> {
let index = self.hash_func(key);
self.buckets[index].as_ref().map(|pair| &pair.val)
}
/* Add operation */
pub fn put(&mut self, key: i32, val: &str) {
let index = self.hash_func(key);
self.buckets[index] = Some(Pair {
key,
val: val.to_string(),
});
}
/* Remove operation */
pub fn remove(&mut self, key: i32) {
let index = self.hash_func(key);
// Set to None to represent removal
self.buckets[index] = None;
}
/* Get all key-value pairs */
pub fn entry_set(&self) -> Vec<&Pair> {
self.buckets
.iter()
.filter_map(|pair| pair.as_ref())
.collect()
}
/* Get all keys */
pub fn key_set(&self) -> Vec<&i32> {
self.buckets
.iter()
.filter_map(|pair| pair.as_ref().map(|pair| &pair.key))
.collect()
}
/* Get all values */
pub fn value_set(&self) -> Vec<&String> {
self.buckets
.iter()
.filter_map(|pair| pair.as_ref().map(|pair| &pair.val))
.collect()
}
/* Print hash table */
pub fn print(&self) {
for pair in self.entry_set() {
println!("{} -> {}", pair.key, pair.val);
}
}
}
fn main() {
/* Initialize hash table */
let mut map = ArrayHashMap::new();
/* Add operation */
// Add key-value pair (key, value) to hash table
map.put(12836, "Xiao Ha");
map.put(15937, "Xiao Luo");
map.put(16750, "Xiao Suan");
map.put(13276, "Xiao Fa");
map.put(10583, "Xiao Ya");
println!("\nAfter adding is complete, hash table is\nKey -> Value");
map.print();
/* Query operation */
// Input key into hash table to get value
let name = map.get(15937).unwrap();
println!("\nInput student ID 15937, found name {}", name);
/* Remove operation */
// Remove key-value pair (key, value) from hash table
map.remove(10583);
println!("\nAfter removing 10583, hash table is\nKey -> Value");
map.print();
/* Traverse hash table */
println!("\nTraverse key-value pairs Key->Value");
for pair in map.entry_set() {
println!("{} -> {}", pair.key, pair.val);
}
println!("\nTraverse keys only Key");
for key in map.key_set() {
println!("{}", key);
}
println!("\nTraverse values only Value");
for val in map.value_set() {
println!("{}", val);
}
}
@@ -0,0 +1,49 @@
/*
* File: build_in_hash.rs
* Created Time: 2023-7-6
* Author: WSL0809 (wslzzy@outlook.com)
*/
use hello_algo_rust::include::ListNode;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
/* Driver Code */
fn main() {
let num = 3;
let mut num_hasher = DefaultHasher::new();
num.hash(&mut num_hasher);
let hash_num = num_hasher.finish();
println!("Hash value of integer {} is {}", num, hash_num);
let bol = true;
let mut bol_hasher = DefaultHasher::new();
bol.hash(&mut bol_hasher);
let hash_bol = bol_hasher.finish();
println!("Hash value of boolean {} is {}", bol, hash_bol);
let dec: f32 = 3.14159;
let mut dec_hasher = DefaultHasher::new();
dec.to_bits().hash(&mut dec_hasher);
let hash_dec = dec_hasher.finish();
println!("Hash value of decimal {} is {}", dec, hash_dec);
let str = "Hello Algo";
let mut str_hasher = DefaultHasher::new();
str.hash(&mut str_hasher);
let hash_str = str_hasher.finish();
println!("Hash value of string {} is {}", str, hash_str);
let arr = (&12836, &"Xiao Ha");
let mut tup_hasher = DefaultHasher::new();
arr.hash(&mut tup_hasher);
let hash_tup = tup_hasher.finish();
println!("Hash value of tuple {:?} is {}", arr, hash_tup);
let node = ListNode::new(42);
let mut hasher = DefaultHasher::new();
node.borrow().val.hash(&mut hasher);
let hash = hasher.finish();
println!("Hash value of node object {:?} is {}", node, hash);
}
+48
View File
@@ -0,0 +1,48 @@
/*
* File: hash_map.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
use std::collections::HashMap;
/* Driver Code */
pub fn main() {
// Initialize hash table
let mut map = HashMap::new();
// Add operation
// Add key-value pair (key, value) to the hash table
map.insert(12836, "Xiao Ha");
map.insert(15937, "Xiao Luo");
map.insert(16750, "Xiao Suan");
map.insert(13276, "Xiao Fa");
map.insert(10583, "Xiao Ya");
println!("\nAfter adding is complete, hash table is\nKey -> Value");
print_util::print_hash_map(&map);
// Query operation
// Input key into hash table to get value
let name = map.get(&15937).copied().unwrap();
println!("\nInput student ID 15937, found name {name}");
// Remove operation
// Remove key-value pair (key, value) from hash table
_ = map.remove(&10583);
println!("\nAfter removing 10583, hash table is\nKey -> Value");
print_util::print_hash_map(&map);
// Traverse hash table
println!("\nTraverse key-value pairs Key->Value");
print_util::print_hash_map(&map);
println!("\nTraverse keys only Key");
for key in map.keys() {
println!("{key}");
}
println!("\nTraverse values separately");
for value in map.values() {
println!("{value}");
}
}
@@ -0,0 +1,160 @@
/*
* File: hash_map_chaining.rs
* Created Time: 2023-07-07
* Author: WSL0809 (wslzzy@outlook.com)
*/
#[derive(Clone)]
/* Key-value pair */
struct Pair {
key: i32,
val: String,
}
/* Hash table with separate chaining */
struct HashMapChaining {
size: usize,
capacity: usize,
load_thres: f32,
extend_ratio: usize,
buckets: Vec<Vec<Pair>>,
}
impl HashMapChaining {
/* Constructor */
fn new() -> Self {
Self {
size: 0,
capacity: 4,
load_thres: 2.0 / 3.0,
extend_ratio: 2,
buckets: vec![vec![]; 4],
}
}
/* Hash function */
fn hash_func(&self, key: i32) -> usize {
key as usize % self.capacity
}
/* Load factor */
fn load_factor(&self) -> f32 {
self.size as f32 / self.capacity as f32
}
/* Remove operation */
fn remove(&mut self, key: i32) -> Option<String> {
let index = self.hash_func(key);
// Traverse bucket and remove key-value pair from it
for (i, p) in self.buckets[index].iter_mut().enumerate() {
if p.key == key {
let pair = self.buckets[index].remove(i);
self.size -= 1;
return Some(pair.val);
}
}
// If key is not found, return None
None
}
/* Expand hash table */
fn extend(&mut self) {
// Temporarily store the original hash table
let buckets_tmp = std::mem::take(&mut self.buckets);
// Initialize expanded new hash table
self.capacity *= self.extend_ratio;
self.buckets = vec![Vec::new(); self.capacity as usize];
self.size = 0;
// Move key-value pairs from original hash table to new hash table
for bucket in buckets_tmp {
for pair in bucket {
self.put(pair.key, pair.val);
}
}
}
/* Print hash table */
fn print(&self) {
for bucket in &self.buckets {
let mut res = Vec::new();
for pair in bucket {
res.push(format!("{} -> {}", pair.key, pair.val));
}
println!("{:?}", res);
}
}
/* Add operation */
fn put(&mut self, key: i32, val: String) {
// When load factor exceeds threshold, perform expansion
if self.load_factor() > self.load_thres {
self.extend();
}
let index = self.hash_func(key);
// Traverse bucket, if specified key is encountered, update corresponding val and return
for pair in self.buckets[index].iter_mut() {
if pair.key == key {
pair.val = val;
return;
}
}
// If key does not exist, append key-value pair to the end
let pair = Pair { key, val };
self.buckets[index].push(pair);
self.size += 1;
}
/* Query operation */
fn get(&self, key: i32) -> Option<&str> {
let index = self.hash_func(key);
// Traverse bucket, if key is found, return corresponding val
for pair in self.buckets[index].iter() {
if pair.key == key {
return Some(&pair.val);
}
}
// If key is not found, return None
None
}
}
/* Driver Code */
pub fn main() {
/* Initialize hash table */
let mut map = HashMapChaining::new();
/* Add operation */
// Add key-value pair (key, value) to the hash table
map.put(12836, "Xiao Ha".to_string());
map.put(15937, "Xiao Luo".to_string());
map.put(16750, "Xiao Suan".to_string());
map.put(13276, "Xiao Fa".to_string());
map.put(10583, "Xiao Ya".to_string());
println!("\nAfter adding is complete, hash table is\nKey -> Value");
map.print();
/* Query operation */
// Input key into hash table to get value
println!(
"\nInput student ID 13276, found name {}",
match map.get(13276) {
Some(value) => value,
None => "Not a valid Key",
}
);
/* Remove operation */
// Remove key-value pair (key, value) from hash table
map.remove(12836);
println!("\nAfter removing 12836, hash table is\nKey -> Value");
map.print();
}
@@ -0,0 +1,181 @@
/*
* File: hash_map_open_addressing.rs
* Created Time: 2023-07-16
* Author: WSL0809 (wslzzy@outlook.com), night-cruise (2586447362@qq.com)
*/
#![allow(non_snake_case)]
#![allow(unused)]
mod array_hash_map;
use array_hash_map::Pair;
/* Hash table with open addressing */
struct HashMapOpenAddressing {
size: usize, // Number of key-value pairs
capacity: usize, // Hash table capacity
load_thres: f64, // Load factor threshold for triggering expansion
extend_ratio: usize, // Expansion multiplier
buckets: Vec<Option<Pair>>, // Bucket array
TOMBSTONE: Option<Pair>, // Removal marker
}
impl HashMapOpenAddressing {
/* Constructor */
fn new() -> Self {
Self {
size: 0,
capacity: 4,
load_thres: 2.0 / 3.0,
extend_ratio: 2,
buckets: vec![None; 4],
TOMBSTONE: Some(Pair {
key: -1,
val: "-1".to_string(),
}),
}
}
/* Hash function */
fn hash_func(&self, key: i32) -> usize {
(key % self.capacity as i32) as usize
}
/* Load factor */
fn load_factor(&self) -> f64 {
self.size as f64 / self.capacity as f64
}
/* Search for bucket index corresponding to key */
fn find_bucket(&mut self, key: i32) -> usize {
let mut index = self.hash_func(key);
let mut first_tombstone = -1;
// Linear probing, break when encountering an empty bucket
while self.buckets[index].is_some() {
// If key is found, return corresponding bucket index
if self.buckets[index].as_ref().unwrap().key == key {
// If deletion marker was encountered before, move key-value pair to that index
if first_tombstone != -1 {
self.buckets[first_tombstone as usize] = self.buckets[index].take();
self.buckets[index] = self.TOMBSTONE.clone();
return first_tombstone as usize; // Return the moved bucket index
}
return index; // Return bucket index
}
// Record the first removal marker encountered
if first_tombstone == -1 && self.buckets[index] == self.TOMBSTONE {
first_tombstone = index as i32;
}
// Calculate bucket index, wrap around to the head if past the tail
index = (index + 1) % self.capacity;
}
// If key does not exist, return the index for insertion
if first_tombstone == -1 {
index
} else {
first_tombstone as usize
}
}
/* Query operation */
fn get(&mut self, key: i32) -> Option<&str> {
// Search for bucket index corresponding to key
let index = self.find_bucket(key);
// If key-value pair is found, return corresponding val
if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {
return self.buckets[index].as_ref().map(|pair| &pair.val as &str);
}
// If key-value pair does not exist, return null
None
}
/* Add operation */
fn put(&mut self, key: i32, val: String) {
// When load factor exceeds threshold, perform expansion
if self.load_factor() > self.load_thres {
self.extend();
}
// Search for bucket index corresponding to key
let index = self.find_bucket(key);
// If key-value pair is found, overwrite val and return
if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {
self.buckets[index].as_mut().unwrap().val = val;
return;
}
// If key-value pair does not exist, add the key-value pair
self.buckets[index] = Some(Pair { key, val });
self.size += 1;
}
/* Remove operation */
fn remove(&mut self, key: i32) {
// Search for bucket index corresponding to key
let index = self.find_bucket(key);
// If key-value pair is found, overwrite it with removal marker
if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {
self.buckets[index] = self.TOMBSTONE.clone();
self.size -= 1;
}
}
/* Expand hash table */
fn extend(&mut self) {
// Temporarily store the original hash table
let buckets_tmp = self.buckets.clone();
// Initialize expanded new hash table
self.capacity *= self.extend_ratio;
self.buckets = vec![None; self.capacity];
self.size = 0;
// Move key-value pairs from original hash table to new hash table
for pair in buckets_tmp {
if pair.is_none() || pair == self.TOMBSTONE {
continue;
}
let pair = pair.unwrap();
self.put(pair.key, pair.val);
}
}
/* Print hash table */
fn print(&self) {
for pair in &self.buckets {
if pair.is_none() {
println!("null");
} else if pair == &self.TOMBSTONE {
println!("TOMBSTONE");
} else {
let pair = pair.as_ref().unwrap();
println!("{} -> {}", pair.key, pair.val);
}
}
}
}
/* Driver Code */
fn main() {
/* Initialize hash table */
let mut hashmap = HashMapOpenAddressing::new();
/* Add operation */
// Add key-value pair (key, value) to the hash table
hashmap.put(12836, "Xiao Ha".to_string());
hashmap.put(15937, "Xiao Luo".to_string());
hashmap.put(16750, "Xiao Suan".to_string());
hashmap.put(13276, "Xiao Fa".to_string());
hashmap.put(10583, "Xiao Ya".to_string());
println!("\nAfter adding is complete, hash table is\nKey -> Value");
hashmap.print();
/* Query operation */
// Input key into hash table to get value val
let name = hashmap.get(13276).unwrap();
println!("\nInput student ID 13276, found name {}", name);
/* Remove operation */
// Remove key-value pair (key, val) from hash table
hashmap.remove(16750);
println!("\nAfter removing 16750, hash table is\nKey -> Value");
hashmap.print();
}
@@ -0,0 +1,70 @@
/*
* File: simple_hash.rs
* Created Time: 2023-09-07
* Author: night-cruise (2586447362@qq.com)
*/
/* Additive hash */
fn add_hash(key: &str) -> i32 {
let mut hash = 0_i64;
const MODULUS: i64 = 1000000007;
for c in key.chars() {
hash = (hash + c as i64) % MODULUS;
}
hash as i32
}
/* Multiplicative hash */
fn mul_hash(key: &str) -> i32 {
let mut hash = 0_i64;
const MODULUS: i64 = 1000000007;
for c in key.chars() {
hash = (31 * hash + c as i64) % MODULUS;
}
hash as i32
}
/* XOR hash */
fn xor_hash(key: &str) -> i32 {
let mut hash = 0_i64;
const MODULUS: i64 = 1000000007;
for c in key.chars() {
hash ^= c as i64;
}
(hash & MODULUS) as i32
}
/* Rotational hash */
fn rot_hash(key: &str) -> i32 {
let mut hash = 0_i64;
const MODULUS: i64 = 1000000007;
for c in key.chars() {
hash = ((hash << 4) ^ (hash >> 28) ^ c as i64) % MODULUS;
}
hash as i32
}
/* Driver Code */
fn main() {
let key = "Hello Algo";
let hash = add_hash(key);
println!("Additive hash value is {hash}");
let hash = mul_hash(key);
println!("Multiplicative hash value is {hash}");
let hash = xor_hash(key);
println!("XOR hash value is {hash}");
let hash = rot_hash(key);
println!("Rotational hash value is {hash}");
}
+71
View File
@@ -0,0 +1,71 @@
/*
* File: heap.rs
* Created Time: 2023-07-16
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
use std::{cmp::Reverse, collections::BinaryHeap};
fn test_push_max(heap: &mut BinaryHeap<i32>, val: i32) {
heap.push(val); // Element enters heap
println!("\nAfter element {} pushes to heap", val);
print_util::print_heap(heap.iter().map(|&val| val).collect());
}
fn test_pop_max(heap: &mut BinaryHeap<i32>) {
let val = heap.pop().unwrap();
println!("\nAfter heap top element {} pops from heap", val);
print_util::print_heap(heap.iter().map(|&val| val).collect());
}
/* Driver Code */
fn main() {
/* Initialize heap */
// Python's heapq module implements min heap by default
#[allow(unused_assignments)]
let mut min_heap = BinaryHeap::new();
// Rust's BinaryHeap is a max heap, min heap typically wraps elements with Reverse
// Consider negating the elements before entering the heap, which can reverse the size relationship, thus implementing max heap
let mut max_heap = BinaryHeap::new();
println!("\nThe following test cases are for max heap");
/* Element enters heap */
test_push_max(&mut max_heap, 1);
test_push_max(&mut max_heap, 3);
test_push_max(&mut max_heap, 2);
test_push_max(&mut max_heap, 5);
test_push_max(&mut max_heap, 4);
/* Check if heap is empty */
let peek = max_heap.peek().unwrap();
println!("\nHeap top element is {}", peek);
/* Time complexity is O(n), not O(nlogn) */
test_pop_max(&mut max_heap);
test_pop_max(&mut max_heap);
test_pop_max(&mut max_heap);
test_pop_max(&mut max_heap);
test_pop_max(&mut max_heap);
/* Get heap size */
let size = max_heap.len();
println!("\nHeap size is {}", size);
/* Check if heap is empty */
let is_empty = max_heap.is_empty();
println!("\nIs heap empty {}", is_empty);
/* Input list and build heap */
// Time complexity is O(n), not O(nlogn)
min_heap = BinaryHeap::from(
vec![1, 3, 2, 5, 4]
.into_iter()
.map(|val| Reverse(val))
.collect::<Vec<Reverse<i32>>>(),
);
println!("\nAfter inputting list and building min heap");
print_util::print_heap(min_heap.iter().map(|&val| val.0).collect());
}
+165
View File
@@ -0,0 +1,165 @@
/*
* File: my_heap.rs
* Created Time: 2023-07-16
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
/* Max heap */
struct MaxHeap {
// Use vector instead of array to avoid capacity concerns
max_heap: Vec<i32>,
}
impl MaxHeap {
/* Constructor, build heap based on input list */
fn new(nums: Vec<i32>) -> Self {
// Add list elements to heap as is
let mut heap = MaxHeap { max_heap: nums };
// Heapify all nodes except leaf nodes
for i in (0..=Self::parent(heap.size() - 1)).rev() {
heap.sift_down(i);
}
heap
}
/* Get index of left child node */
fn left(i: usize) -> usize {
2 * i + 1
}
/* Get index of right child node */
fn right(i: usize) -> usize {
2 * i + 2
}
/* Get index of parent node */
fn parent(i: usize) -> usize {
(i - 1) / 2 // Floor division
}
/* Swap elements */
fn swap(&mut self, i: usize, j: usize) {
self.max_heap.swap(i, j);
}
/* Get heap size */
fn size(&self) -> usize {
self.max_heap.len()
}
/* Check if heap is empty */
fn is_empty(&self) -> bool {
self.max_heap.is_empty()
}
/* Access top element */
fn peek(&self) -> Option<i32> {
self.max_heap.first().copied()
}
/* Element enters heap */
fn push(&mut self, val: i32) {
// Add node
self.max_heap.push(val);
// Heapify from bottom to top
self.sift_up(self.size() - 1);
}
/* Starting from node i, heapify from bottom to top */
fn sift_up(&mut self, mut i: usize) {
loop {
// Node i is already the heap root, end heapification
if i == 0 {
break;
}
// Get parent node of node i
let p = Self::parent(i);
// When "node needs no repair", end heapification
if self.max_heap[i] <= self.max_heap[p] {
break;
}
// Swap two nodes
self.swap(i, p);
// Loop upward heapify
i = p;
}
}
/* Element exits heap */
fn pop(&mut self) -> i32 {
// Handle empty case
if self.is_empty() {
panic!("index out of bounds");
}
// Delete node
self.swap(0, self.size() - 1);
// Remove node
let val = self.max_heap.pop().unwrap();
// Return top element
self.sift_down(0);
// Return heap top element
val
}
/* Starting from node i, heapify from top to bottom */
fn sift_down(&mut self, mut i: usize) {
loop {
// If node i is largest or indices l, r are out of bounds, no need to continue heapify, break
let (l, r, mut ma) = (Self::left(i), Self::right(i), i);
if l < self.size() && self.max_heap[l] > self.max_heap[ma] {
ma = l;
}
if r < self.size() && self.max_heap[r] > self.max_heap[ma] {
ma = r;
}
// Swap two nodes
if ma == i {
break;
}
// Swap two nodes
self.swap(i, ma);
// Loop downwards heapification
i = ma;
}
}
/* Driver Code */
fn print(&self) {
print_util::print_heap(self.max_heap.clone());
}
}
/* Driver Code */
fn main() {
/* Consider negating the elements before entering the heap, which can reverse the size relationship, thus implementing max heap */
let mut max_heap = MaxHeap::new(vec![9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]);
println!("\nAfter inputting list and building heap");
max_heap.print();
/* Check if heap is empty */
let peek = max_heap.peek();
if let Some(peek) = peek {
println!("\nHeap top element is {}", peek);
}
/* Element enters heap */
let val = 7;
max_heap.push(val);
println!("\nAfter element {} pushes to heap", val);
max_heap.print();
/* Time complexity is O(n), not O(nlogn) */
let peek = max_heap.pop();
println!("\nAfter heap top element {} pops from heap", peek);
max_heap.print();
/* Get heap size */
let size = max_heap.size();
println!("\nHeap size is {}", size);
/* Check if heap is empty */
let is_empty = max_heap.is_empty();
println!("\nIs heap empty {}", is_empty);
}
+39
View File
@@ -0,0 +1,39 @@
/*
* File: top_k.rs
* Created Time: 2023-07-16
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
/* Find the largest k elements in array based on heap */
fn top_k_heap(nums: Vec<i32>, k: usize) -> BinaryHeap<Reverse<i32>> {
// BinaryHeap is a max heap, use Reverse to negate elements to implement min heap
let mut heap = BinaryHeap::<Reverse<i32>>::new();
// Enter the first k elements of array into heap
for &num in nums.iter().take(k) {
heap.push(Reverse(num));
}
// Starting from the (k+1)th element, maintain heap length as k
for &num in nums.iter().skip(k) {
// If current element is greater than top element, top element exits heap, current element enters heap
if num > heap.peek().unwrap().0 {
heap.pop();
heap.push(Reverse(num));
}
}
heap
}
/* Driver Code */
fn main() {
let nums = vec![1, 7, 6, 3, 2];
let k = 3;
let res = top_k_heap(nums, k);
println!("The largest {} elements are", k);
print_util::print_heap(res.into_iter().map(|item| item.0).collect());
}
@@ -0,0 +1,65 @@
/*
* File: binary_search.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com)
*/
/* Binary search (closed interval on both sides) */
fn binary_search(nums: &[i32], target: i32) -> i32 {
// Initialize closed interval [0, n-1], i.e., i, j point to the first and last elements of the array
let mut i = 0;
let mut j = nums.len() as i32 - 1;
// Loop, exit when the search interval is empty (empty when i > j)
while i <= j {
let m = i + (j - i) / 2; // Calculate the midpoint index m
if nums[m as usize] < target {
// This means target is in the interval [m+1, j]
i = m + 1;
} else if nums[m as usize] > target {
// This means target is in the interval [i, m-1]
j = m - 1;
} else {
// Found the target element, return its index
return m;
}
}
// Target element not found, return -1
return -1;
}
/* Binary search (left-closed right-open interval) */
fn binary_search_lcro(nums: &[i32], target: i32) -> i32 {
// Initialize left-closed right-open interval [0, n), i.e., i, j point to the first element and last element+1
let mut i = 0;
let mut j = nums.len() as i32;
// Loop, exit when the search interval is empty (empty when i = j)
while i < j {
let m = i + (j - i) / 2; // Calculate the midpoint index m
if nums[m as usize] < target {
// This means target is in the interval [m+1, j)
i = m + 1;
} else if nums[m as usize] > target {
// This means target is in the interval [i, m)
j = m;
} else {
// Found the target element, return its index
return m;
}
}
// Target element not found, return -1
return -1;
}
/* Driver Code */
pub fn main() {
let target = 6;
let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35];
// Binary search (closed interval on both sides)
let mut index = binary_search(&nums, target);
println!("Index of target element 6 is {index}");
// Binary search (left-closed right-open interval)
index = binary_search_lcro(&nums, target);
println!("Index of target element 6 is {index}");
}
@@ -0,0 +1,50 @@
/*
* File: binary_search_edge.rs
* Created Time: 2023-08-30
* Author: night-cruise (2586447362@qq.com)
*/
mod binary_search_insertion;
use binary_search_insertion::binary_search_insertion;
/* Binary search for the leftmost target */
fn binary_search_left_edge(nums: &[i32], target: i32) -> i32 {
// Equivalent to finding the insertion point of target
let i = binary_search_insertion(nums, target);
// Target not found, return -1
if i == nums.len() as i32 || nums[i as usize] != target {
return -1;
}
// Found target, return index i
i
}
/* Binary search for the rightmost target */
fn binary_search_right_edge(nums: &[i32], target: i32) -> i32 {
// Convert to finding the leftmost target + 1
let i = binary_search_insertion(nums, target + 1);
// j points to the rightmost target, i points to the first element greater than target
let j = i - 1;
// Target not found, return -1
if j == -1 || nums[j as usize] != target {
return -1;
}
// Found target, return index j
j
}
/* Driver Code */
fn main() {
// Array with duplicate elements
let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
println!("\nArray nums = {:?}", nums);
// Binary search left and right boundaries
for target in [6, 7] {
let index = binary_search_left_edge(&nums, target);
println!("Leftmost element {} index is {}", target, index);
let index = binary_search_right_edge(&nums, target);
println!("Rightmost element {} index is {}", target, index);
}
}
@@ -0,0 +1,61 @@
/*
* File: binary_search_insertion.rs
* Created Time: 2023-08-30
* Author: night-cruise (2586447362@qq.com)
*/
#![allow(unused)]
/* Binary search for insertion point (no duplicate elements) */
fn binary_search_insertion_simple(nums: &[i32], target: i32) -> i32 {
let (mut i, mut j) = (0, nums.len() as i32 - 1); // Initialize closed interval [0, n-1]
while i <= j {
let m = i + (j - i) / 2; // Calculate the midpoint index m
if nums[m as usize] < target {
i = m + 1; // target is in the interval [m+1, j]
} else if nums[m as usize] > target {
j = m - 1; // target is in the interval [i, m-1]
} else {
return m;
}
}
// Target not found, return insertion point i
i
}
/* Binary search for insertion point (with duplicate elements) */
pub fn binary_search_insertion(nums: &[i32], target: i32) -> i32 {
let (mut i, mut j) = (0, nums.len() as i32 - 1); // Initialize closed interval [0, n-1]
while i <= j {
let m = i + (j - i) / 2; // Calculate the midpoint index m
if nums[m as usize] < target {
i = m + 1; // target is in the interval [m+1, j]
} else if nums[m as usize] > target {
j = m - 1; // target is in the interval [i, m-1]
} else {
j = m - 1; // The first element less than target is in the interval [i, m-1]
}
}
// Return insertion point i
i
}
/* Driver Code */
fn main() {
// Array without duplicate elements
let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35];
println!("\nArray nums = {:?}", nums);
// Binary search for insertion point
for target in [6, 9] {
let index = binary_search_insertion_simple(&nums, target);
println!("Insertion point index for element {} is {}", target, index);
}
// Array with duplicate elements
let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
println!("\nArray nums = {:?}", nums);
// Binary search for insertion point
for target in [2, 6, 20] {
let index = binary_search_insertion(&nums, target);
println!("Insertion point index for element {} is {}", target, index);
}
}
@@ -0,0 +1,50 @@
/*
* File: hashing_search.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::ListNode;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
/* Hash search (array) */
fn hashing_search_array<'a>(map: &'a HashMap<i32, usize>, target: i32) -> Option<&'a usize> {
// Hash table's key: target element, value: index
// If this key does not exist in the hash table, return None
map.get(&target)
}
/* Hash search (linked list) */
fn hashing_search_linked_list(
map: &HashMap<i32, Rc<RefCell<ListNode<i32>>>>,
target: i32,
) -> Option<&Rc<RefCell<ListNode<i32>>>> {
// Hash table key: target node value, value: node object
// If this key does not exist in the hash table, return None
map.get(&target)
}
/* Driver Code */
pub fn main() {
let target = 3;
/* Hash search (array) */
let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8];
// Initialize hash table
let mut map = HashMap::new();
for (i, num) in nums.iter().enumerate() {
map.insert(*num, i); // key: element, value: index
}
let index = hashing_search_array(&map, target);
println!("Index of target element 3 = {}", index.unwrap());
/* Hash search (linked list) */
let head = ListNode::arr_to_linked_list(&nums);
// Initialize hash table
// let mut map1 = HashMap::new();
let map1 = ListNode::linked_list_to_hashmap(head);
let node = hashing_search_linked_list(&map1, target);
println!("Node object corresponding to target node value 3 is {:?}", node);
}
@@ -0,0 +1,54 @@
/*
* File: linear_search.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::ListNode;
use std::cell::RefCell;
use std::rc::Rc;
/* Linear search (array) */
fn linear_search_array(nums: &[i32], target: i32) -> i32 {
// Traverse array
for (i, num) in nums.iter().enumerate() {
// Found the target element, return its index
if num == &target {
return i as i32;
}
}
// Target element not found, return -1
return -1;
}
/* Linear search (linked list) */
fn linear_search_linked_list(
head: Rc<RefCell<ListNode<i32>>>,
target: i32,
) -> Option<Rc<RefCell<ListNode<i32>>>> {
// Found the target node, return it
if head.borrow().val == target {
return Some(head);
};
// Found the target node, return it
if let Some(node) = &head.borrow_mut().next {
return linear_search_linked_list(node.clone(), target);
}
// Target node not found, return None
return None;
}
/* Driver Code */
pub fn main() {
let target = 3;
/* Perform linear search in array */
let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8];
let index = linear_search_array(&nums, target);
println!("Index of target element 3 = {}", index);
/* Perform linear search in linked list */
let head = ListNode::arr_to_linked_list(&nums);
let node = linear_search_linked_list(head.unwrap(), target);
println!("Node object corresponding to target node value 3 is {:?}", node);
}
@@ -0,0 +1,52 @@
/*
* File: two_sum.rs
* Created Time: 2023-01-14
* Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
use std::collections::HashMap;
/* Method 1: Brute force enumeration */
pub fn two_sum_brute_force(nums: &Vec<i32>, target: i32) -> Option<Vec<i32>> {
let size = nums.len();
// Two nested loops, time complexity is O(n^2)
for i in 0..size - 1 {
for j in i + 1..size {
if nums[i] + nums[j] == target {
return Some(vec![i as i32, j as i32]);
}
}
}
None
}
/* Method 2: Auxiliary hash table */
pub fn two_sum_hash_table(nums: &Vec<i32>, target: i32) -> Option<Vec<i32>> {
// Auxiliary hash table, space complexity is O(n)
let mut dic = HashMap::new();
// Single loop, time complexity is O(n)
for (i, num) in nums.iter().enumerate() {
match dic.get(&(target - num)) {
Some(v) => return Some(vec![*v as i32, i as i32]),
None => dic.insert(num, i as i32),
};
}
None
}
fn main() {
// ======= Test Case =======
let nums = vec![2, 7, 11, 15];
let target = 13;
// ====== Driver Code ======
// Method 1
let res = two_sum_brute_force(&nums, target).unwrap();
print!("Method 1 res = ");
print_util::print_array(&res);
// Method 2
let res = two_sum_hash_table(&nums, target).unwrap();
print!("\nMethod 2 res = ");
print_util::print_array(&res);
}
@@ -0,0 +1,53 @@
/*
* File: bubble_sort.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
/* Bubble sort */
fn bubble_sort(nums: &mut [i32]) {
// Outer loop: unsorted range is [0, i]
for i in (1..nums.len()).rev() {
// Inner loop: swap the largest element in the unsorted range [0, i] to the rightmost end of that range
for j in 0..i {
if nums[j] > nums[j + 1] {
// Swap nums[j] and nums[j + 1]
nums.swap(j, j + 1);
}
}
}
}
/* Bubble sort (flag optimization) */
fn bubble_sort_with_flag(nums: &mut [i32]) {
// Outer loop: unsorted range is [0, i]
for i in (1..nums.len()).rev() {
let mut flag = false; // Initialize flag
// Inner loop: swap the largest element in the unsorted range [0, i] to the rightmost end of that range
for j in 0..i {
if nums[j] > nums[j + 1] {
// Swap nums[j] and nums[j + 1]
nums.swap(j, j + 1);
flag = true; // Record element swap
}
}
if !flag {
break; // No elements were swapped in this round of "bubbling", exit directly
};
}
}
/* Driver Code */
pub fn main() {
let mut nums = [4, 1, 3, 1, 5, 2];
bubble_sort(&mut nums);
print!("After bubble sort completes, nums = ");
print_util::print_array(&nums);
let mut nums1 = [4, 1, 3, 1, 5, 2];
bubble_sort_with_flag(&mut nums1);
print!("\nAfter bubble sort, nums1 = ");
print_util::print_array(&nums1);
}
@@ -0,0 +1,43 @@
/*
* File: bucket_sort.rs
* Created Time: 2023-07-09
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
/* Bucket sort */
fn bucket_sort(nums: &mut [f64]) {
// Initialize k = n/2 buckets, expected to allocate 2 elements per bucket
let k = nums.len() / 2;
let mut buckets = vec![vec![]; k];
// 1. Distribute array elements into various buckets
for &num in nums.iter() {
// Input data range is [0, 1), use num * k to map to index range [0, k-1]
let i = (num * k as f64) as usize;
// Add num to bucket i
buckets[i].push(num);
}
// 2. Sort each bucket
for bucket in &mut buckets {
// Use built-in sorting function, can also replace with other sorting algorithms
bucket.sort_by(|a, b| a.partial_cmp(b).unwrap());
}
// 3. Traverse buckets to merge results
let mut i = 0;
for bucket in buckets.iter() {
for &num in bucket.iter() {
nums[i] = num;
i += 1;
}
}
}
/* Driver Code */
fn main() {
// Assume input data is floating point, interval [0, 1)
let mut nums = [0.49, 0.96, 0.82, 0.09, 0.57, 0.43, 0.91, 0.75, 0.15, 0.37];
bucket_sort(&mut nums);
print!("After bucket sort completes, nums = ");
print_util::print_array(&nums);
}
@@ -0,0 +1,70 @@
/*
* File: counting_sort.rs
* Created Time: 2023-07-09
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
/* Counting sort */
// Simple implementation, cannot be used for sorting objects
fn counting_sort_naive(nums: &mut [i32]) {
// 1. Count the maximum element m in the array
let m = *nums.iter().max().unwrap();
// 2. Count the occurrence of each number
// counter[num] represents the occurrence of num
let mut counter = vec![0; m as usize + 1];
for &num in nums.iter() {
counter[num as usize] += 1;
}
// 3. Traverse counter, filling each element back into the original array nums
let mut i = 0;
for num in 0..m + 1 {
for _ in 0..counter[num as usize] {
nums[i] = num;
i += 1;
}
}
}
/* Counting sort */
// Complete implementation, can sort objects and is a stable sort
fn counting_sort(nums: &mut [i32]) {
// 1. Count the maximum element m in the array
let m = *nums.iter().max().unwrap() as usize;
// 2. Count the occurrence of each number
// counter[num] represents the occurrence of num
let mut counter = vec![0; m + 1];
for &num in nums.iter() {
counter[num as usize] += 1;
}
// 3. Calculate the prefix sum of counter, converting "occurrence count" to "tail index"
// counter[num]-1 is the last index where num appears in res
for i in 0..m {
counter[i + 1] += counter[i];
}
// 4. Traverse nums in reverse order, placing each element into the result array res
// Initialize the array res to record results
let n = nums.len();
let mut res = vec![0; n];
for i in (0..n).rev() {
let num = nums[i];
res[counter[num as usize] - 1] = num; // Place num at the corresponding index
counter[num as usize] -= 1; // Decrement the prefix sum by 1, getting the next index to place num
}
// Use result array res to overwrite the original array nums
nums.copy_from_slice(&res)
}
/* Driver Code */
fn main() {
let mut nums = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4];
counting_sort_naive(&mut nums);
print!("After counting sort (cannot sort objects) completes, nums = ");
print_util::print_array(&nums);
let mut nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4];
counting_sort(&mut nums1);
print!("\nAfter counting sort, nums1 = ");
print_util::print_array(&nums1);
}
@@ -0,0 +1,54 @@
/*
* File: heap_sort.rs
* Created Time: 2023-07-04
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
/* Heap length is n, start heapifying node i, from top to bottom */
fn sift_down(nums: &mut [i32], n: usize, mut i: usize) {
loop {
// If node i is largest or indices l, r are out of bounds, no need to continue heapify, break
let l = 2 * i + 1;
let r = 2 * i + 2;
let mut ma = i;
if l < n && nums[l] > nums[ma] {
ma = l;
}
if r < n && nums[r] > nums[ma] {
ma = r;
}
// Swap two nodes
if ma == i {
break;
}
// Swap two nodes
nums.swap(i, ma);
// Loop downwards heapification
i = ma;
}
}
/* Heap sort */
fn heap_sort(nums: &mut [i32]) {
// Build heap operation: heapify all nodes except leaves
for i in (0..nums.len() / 2).rev() {
sift_down(nums, nums.len(), i);
}
// Extract the largest element from the heap and repeat for n-1 rounds
for i in (1..nums.len()).rev() {
// Delete node
nums.swap(0, i);
// Start heapifying the root node, from top to bottom
sift_down(nums, i, 0);
}
}
/* Driver Code */
fn main() {
let mut nums = [4, 1, 3, 1, 5, 2];
heap_sort(&mut nums);
print!("After heap sort completes, nums = ");
print_util::print_array(&nums);
}
@@ -0,0 +1,29 @@
/*
* File: insertion_sort.rs
* Created Time: 2023-02-13
* Author: xBLACKICEx (xBLACKICEx@outlook.com)
*/
use hello_algo_rust::include::print_util;
/* Insertion sort */
fn insertion_sort(nums: &mut [i32]) {
// Outer loop: sorted interval is [0, i-1]
for i in 1..nums.len() {
let (base, mut j) = (nums[i], (i - 1) as i32);
// Inner loop: insert base into the correct position within the sorted interval [0, i-1]
while j >= 0 && nums[j as usize] > base {
nums[(j + 1) as usize] = nums[j as usize]; // Move nums[j] to the right by one position
j -= 1;
}
nums[(j + 1) as usize] = base; // Assign base to the correct position
}
}
/* Driver Code */
fn main() {
let mut nums = [4, 1, 3, 1, 5, 2];
insertion_sort(&mut nums);
print!("After insertion sort completes, nums = ");
print_util::print_array(&nums);
}
@@ -0,0 +1,66 @@
/**
* File: merge_sort.rs
* Created Time: 2023-02-14
* Author: xBLACKICEx (xBLACKICEx@outlook.com)
*/
/* Merge left subarray and right subarray */
fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) {
// Left subarray interval is [left, mid], right subarray interval is [mid+1, right]
// Create a temporary array tmp to store the merged results
let tmp_size = right - left + 1;
let mut tmp = vec![0; tmp_size];
// Initialize the start indices of the left and right subarrays
let (mut i, mut j, mut k) = (left, mid + 1, 0);
// While both subarrays still have elements, compare and copy the smaller element into the temporary array
while i <= mid && j <= right {
if nums[i] <= nums[j] {
tmp[k] = nums[i];
i += 1;
} else {
tmp[k] = nums[j];
j += 1;
}
k += 1;
}
// Copy the remaining elements of the left and right subarrays into the temporary array
while i <= mid {
tmp[k] = nums[i];
k += 1;
i += 1;
}
while j <= right {
tmp[k] = nums[j];
k += 1;
j += 1;
}
// Copy the elements from the temporary array tmp back to the original array nums at the corresponding interval
for k in 0..tmp_size {
nums[left + k] = tmp[k];
}
}
/* Merge sort */
fn merge_sort(nums: &mut [i32], left: usize, right: usize) {
// Termination condition
if left >= right {
return; // Terminate recursion when subarray length is 1
}
// Divide and conquer stage
let mid = left + (right - left) / 2; // Calculate midpoint
merge_sort(nums, left, mid); // Recursively process the left subarray
merge_sort(nums, mid + 1, right); // Recursively process the right subarray
// Merge stage
merge(nums, left, mid, right);
}
/* Driver Code */
fn main() {
/* Merge sort */
let mut nums = [7, 3, 2, 6, 0, 1, 5, 4];
let right = nums.len() - 1;
merge_sort(&mut nums, 0, right);
println!("After merge sort, nums = {:?}", nums);
}
+148
View File
@@ -0,0 +1,148 @@
/**
* File: quick_sort.rs
* Created Time: 2023-02-16
* Author: xBLACKICEx (xBLACKICE@outlook.com)
*/
/* Quick sort */
struct QuickSort;
impl QuickSort {
/* Sentinel partition */
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
// Use nums[left] as the pivot
let (mut i, mut j) = (left, right);
while i < j {
while i < j && nums[j] >= nums[left] {
j -= 1; // Search from right to left for the first element smaller than the pivot
}
while i < j && nums[i] <= nums[left] {
i += 1; // Search from left to right for the first element greater than the pivot
}
nums.swap(i, j); // Swap these two elements
}
nums.swap(i, left); // Swap the pivot to the boundary between the two subarrays
i // Return the index of the pivot
}
/* Quick sort */
pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) {
// Terminate recursion when subarray length is 1
if left >= right {
return;
}
// Sentinel partition
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
// Recursively process the left subarray and right subarray
Self::quick_sort(left, pivot - 1, nums);
Self::quick_sort(pivot + 1, right, nums);
}
}
/* Quick sort (recursion depth optimization) */
struct QuickSortMedian;
impl QuickSortMedian {
/* Select the median of three candidate elements */
fn median_three(nums: &mut [i32], left: usize, mid: usize, right: usize) -> usize {
let (l, m, r) = (nums[left], nums[mid], nums[right]);
if (l <= m && m <= r) || (r <= m && m <= l) {
return mid; // m is between l and r
}
if (m <= l && l <= r) || (r <= l && l <= m) {
return left; // l is between m and r
}
right
}
/* Sentinel partition (median of three) */
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
// Select the median of three candidate elements
let med = Self::median_three(nums, left, (left + right) / 2, right);
// Swap the median to the array's leftmost position
nums.swap(left, med);
// Use nums[left] as the pivot
let (mut i, mut j) = (left, right);
while i < j {
while i < j && nums[j] >= nums[left] {
j -= 1; // Search from right to left for the first element smaller than the pivot
}
while i < j && nums[i] <= nums[left] {
i += 1; // Search from left to right for the first element greater than the pivot
}
nums.swap(i, j); // Swap these two elements
}
nums.swap(i, left); // Swap the pivot to the boundary between the two subarrays
i // Return the index of the pivot
}
/* Quick sort */
pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) {
// Terminate recursion when subarray length is 1
if left >= right {
return;
}
// Sentinel partition
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
// Recursively process the left subarray and right subarray
Self::quick_sort(left, pivot - 1, nums);
Self::quick_sort(pivot + 1, right, nums);
}
}
/* Quick sort (recursion depth optimization) */
struct QuickSortTailCall;
impl QuickSortTailCall {
/* Sentinel partition */
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
// Use nums[left] as the pivot
let (mut i, mut j) = (left, right);
while i < j {
while i < j && nums[j] >= nums[left] {
j -= 1; // Search from right to left for the first element smaller than the pivot
}
while i < j && nums[i] <= nums[left] {
i += 1; // Search from left to right for the first element greater than the pivot
}
nums.swap(i, j); // Swap these two elements
}
nums.swap(i, left); // Swap the pivot to the boundary between the two subarrays
i // Return the index of the pivot
}
/* Quick sort (recursion depth optimization) */
pub fn quick_sort(mut left: i32, mut right: i32, nums: &mut [i32]) {
// Terminate when subarray length is 1
while left < right {
// Sentinel partition operation
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
// Perform quick sort on the shorter of the two subarrays
if pivot - left < right - pivot {
Self::quick_sort(left, pivot - 1, nums); // Recursively sort the left subarray
left = pivot + 1; // Remaining unsorted interval is [pivot + 1, right]
} else {
Self::quick_sort(pivot + 1, right, nums); // Recursively sort the right subarray
right = pivot - 1; // Remaining unsorted interval is [left, pivot - 1]
}
}
}
}
/* Driver Code */
fn main() {
/* Quick sort */
let mut nums = [2, 4, 1, 0, 3, 5];
QuickSort::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
println!("After quick sort, nums = {:?}", nums);
/* Quick sort (recursion depth optimization) */
let mut nums = [2, 4, 1, 0, 3, 5];
QuickSortMedian::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
println!("After quick sort (median pivot optimization), nums = {:?}", nums);
/* Quick sort (recursion depth optimization) */
let mut nums = [2, 4, 1, 0, 3, 5];
QuickSortTailCall::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
println!("After quick sort (recursion depth optimization), nums = {:?}", nums);
}
@@ -0,0 +1,63 @@
/*
* File: radix_sort.rs
* Created Time: 2023-07-09
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
/* Get the k-th digit of element num, where exp = 10^(k-1) */
fn digit(num: i32, exp: i32) -> usize {
// Passing exp instead of k can avoid repeated expensive exponentiation here
return ((num / exp) % 10) as usize;
}
/* Counting sort (based on nums k-th digit) */
fn counting_sort_digit(nums: &mut [i32], exp: i32) {
// Decimal digit range is 0~9, therefore need a bucket array of length 10
let mut counter = [0; 10];
let n = nums.len();
// Count the occurrence of digits 0~9
for i in 0..n {
let d = digit(nums[i], exp); // Get the k-th digit of nums[i], noted as d
counter[d] += 1; // Count the occurrence of digit d
}
// Calculate prefix sum, converting "occurrence count" into "array index"
for i in 1..10 {
counter[i] += counter[i - 1];
}
// Traverse in reverse, based on bucket statistics, place each element into res
let mut res = vec![0; n];
for i in (0..n).rev() {
let d = digit(nums[i], exp);
let j = counter[d] - 1; // Get the index j for d in the array
res[j] = nums[i]; // Place the current element at index j
counter[d] -= 1; // Decrease the count of d by 1
}
// Use result to overwrite the original array nums
nums.copy_from_slice(&res);
}
/* Radix sort */
fn radix_sort(nums: &mut [i32]) {
// Get the maximum element of the array, used to determine the maximum number of digits
let m = *nums.into_iter().max().unwrap();
// Traverse from the lowest to the highest digit
let mut exp = 1;
while exp <= m {
counting_sort_digit(nums, exp);
exp *= 10;
}
}
/* Driver Code */
fn main() {
// Radix sort
let mut nums = [
10546151, 35663510, 42865989, 34862445, 81883077, 88906420, 72429244, 30524779, 82060337,
63832996,
];
radix_sort(&mut nums);
print!("After radix sort completes, nums = ");
print_util::print_array(&nums);
}
@@ -0,0 +1,35 @@
/*
* File: selection_sort.rs
* Created Time: 2023-05-30
* Author: WSL0809 (wslzzy@outlook.com)
*/
use hello_algo_rust::include::print_util;
/* Selection sort */
fn selection_sort(nums: &mut [i32]) {
if nums.is_empty() {
return;
}
let n = nums.len();
// Outer loop: unsorted interval is [i, n-1]
for i in 0..n - 1 {
// Inner loop: find the smallest element within the unsorted interval
let mut k = i;
for j in i + 1..n {
if nums[j] < nums[k] {
k = j; // Record the index of the smallest element
}
}
// Swap the smallest element with the first element of the unsorted interval
nums.swap(i, k);
}
}
/* Driver Code */
pub fn main() {
let mut nums = [4, 1, 3, 1, 5, 2];
selection_sort(&mut nums);
print!("\nAfter selection sort, nums = ");
print_util::print_array(&nums);
}
@@ -0,0 +1,160 @@
/*
* File: array_deque.rs
* Created Time: 2023-03-11
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
/* Double-ended queue based on circular array implementation */
struct ArrayDeque<T> {
nums: Vec<T>, // Array for storing double-ended queue elements
front: usize, // Front pointer, points to the front of the queue element
que_size: usize, // Double-ended queue length
}
impl<T: Copy + Default> ArrayDeque<T> {
/* Constructor */
pub fn new(capacity: usize) -> Self {
Self {
nums: vec![T::default(); capacity],
front: 0,
que_size: 0,
}
}
/* Get the capacity of the double-ended queue */
pub fn capacity(&self) -> usize {
self.nums.len()
}
/* Get the length of the double-ended queue */
pub fn size(&self) -> usize {
self.que_size
}
/* Check if the double-ended queue is empty */
pub fn is_empty(&self) -> bool {
self.que_size == 0
}
/* Calculate circular array index */
fn index(&self, i: i32) -> usize {
// Use modulo operation to wrap the array head and tail together
// When i passes the tail of the array, return to the head
// When i passes the head of the array, return to the tail
((i + self.capacity() as i32) % self.capacity() as i32) as usize
}
/* Front of the queue enqueue */
pub fn push_first(&mut self, num: T) {
if self.que_size == self.capacity() {
println!("Double-ended queue is full");
return;
}
// Use modulo operation to wrap front around to the tail after passing the head of the array
// Add num to the front of the queue
self.front = self.index(self.front as i32 - 1);
// Add num to front of queue
self.nums[self.front] = num;
self.que_size += 1;
}
/* Rear of the queue enqueue */
pub fn push_last(&mut self, num: T) {
if self.que_size == self.capacity() {
println!("Double-ended queue is full");
return;
}
// Use modulo operation to wrap rear around to the head after passing the tail of the array
let rear = self.index(self.front as i32 + self.que_size as i32);
// Front pointer moves one position backward
self.nums[rear] = num;
self.que_size += 1;
}
/* Rear of the queue dequeue */
fn pop_first(&mut self) -> T {
let num = self.peek_first();
// Move front pointer backward by one position
self.front = self.index(self.front as i32 + 1);
self.que_size -= 1;
num
}
/* Access rear of the queue element */
fn pop_last(&mut self) -> T {
let num = self.peek_last();
self.que_size -= 1;
num
}
/* Return list for printing */
fn peek_first(&self) -> T {
if self.is_empty() {
panic!("Deque is empty")
};
self.nums[self.front]
}
/* Driver Code */
fn peek_last(&self) -> T {
if self.is_empty() {
panic!("Deque is empty")
};
// Initialize double-ended queue
let last = self.index(self.front as i32 + self.que_size as i32 - 1);
self.nums[last]
}
/* Return array for printing */
fn to_array(&self) -> Vec<T> {
// Elements enqueue
let mut res = vec![T::default(); self.que_size];
let mut j = self.front;
for i in 0..self.que_size {
res[i] = self.nums[self.index(j as i32)];
j += 1;
}
res
}
}
/* Driver Code */
fn main() {
/* Get the length of the double-ended queue */
let mut deque = ArrayDeque::new(10);
deque.push_last(3);
deque.push_last(2);
deque.push_last(5);
print!("Double-ended queue deque = ");
print_util::print_array(&deque.to_array());
/* Update element */
let peek_first = deque.peek_first();
print!("\nFront element peek_first = {}", peek_first);
let peek_last = deque.peek_last();
print!("\nRear element peek_last = {}", peek_last);
/* Elements enqueue */
deque.push_last(4);
print!("\nAfter element 4 enqueues at rear, deque = ");
print_util::print_array(&deque.to_array());
deque.push_first(1);
print!("\nAfter element 1 enqueues at front, deque = ");
print_util::print_array(&deque.to_array());
/* Element dequeue */
let pop_last = deque.pop_last();
print!("\nDequeue rear element = {}, after dequeue deque = ", pop_last);
print_util::print_array(&deque.to_array());
let pop_first = deque.pop_first();
print!("\nDequeue front element = {}, after dequeue deque = ", pop_first);
print_util::print_array(&deque.to_array());
/* Get the length of the double-ended queue */
let size = deque.size();
print!("\nDeque length size = {}", size);
/* Check if the double-ended queue is empty */
let is_empty = deque.is_empty();
print!("\nIs deque empty = {}", is_empty);
}
@@ -0,0 +1,125 @@
/*
* File: array_queue.rs
* Created Time: 2023-02-06
* Author: WSL0809 (wslzzy@outlook.com)
*/
/* Queue based on circular array implementation */
struct ArrayQueue<T> {
nums: Vec<T>, // Array for storing queue elements
front: i32, // Front pointer, points to the front of the queue element
que_size: i32, // Queue length
que_capacity: i32, // Queue capacity
}
impl<T: Copy + Default> ArrayQueue<T> {
/* Constructor */
fn new(capacity: i32) -> ArrayQueue<T> {
ArrayQueue {
nums: vec![T::default(); capacity as usize],
front: 0,
que_size: 0,
que_capacity: capacity,
}
}
/* Get the capacity of the queue */
fn capacity(&self) -> i32 {
self.que_capacity
}
/* Get the length of the queue */
fn size(&self) -> i32 {
self.que_size
}
/* Check if the queue is empty */
fn is_empty(&self) -> bool {
self.que_size == 0
}
/* Enqueue */
fn push(&mut self, num: T) {
if self.que_size == self.capacity() {
println!("Queue is full");
return;
}
// Use modulo operation to wrap rear around to the head after passing the tail of the array
// Add num to the rear of the queue
let rear = (self.front + self.que_size) % self.que_capacity;
// Front pointer moves one position backward
self.nums[rear as usize] = num;
self.que_size += 1;
}
/* Dequeue */
fn pop(&mut self) -> T {
let num = self.peek();
// Move front pointer backward by one position, if it passes the tail, return to array head
self.front = (self.front + 1) % self.que_capacity;
self.que_size -= 1;
num
}
/* Return list for printing */
fn peek(&self) -> T {
if self.is_empty() {
panic!("index out of bounds");
}
self.nums[self.front as usize]
}
/* Return array */
fn to_vector(&self) -> Vec<T> {
let cap = self.que_capacity;
let mut j = self.front;
let mut arr = vec![T::default(); cap as usize];
for i in 0..self.que_size {
arr[i as usize] = self.nums[(j % cap) as usize];
j += 1;
}
arr
}
}
/* Driver Code */
fn main() {
/* Access front of the queue element */
let capacity = 10;
let mut queue = ArrayQueue::new(capacity);
/* Elements enqueue */
queue.push(1);
queue.push(3);
queue.push(2);
queue.push(5);
queue.push(4);
println!("Queue queue = {:?}", queue.to_vector());
/* Return list for printing */
let peek = queue.peek();
println!("Front element peek = {}", peek);
/* Element dequeue */
let pop = queue.pop();
println!(
"Dequeue element pop = {:?}, after dequeue queue = {:?}",
pop,
queue.to_vector()
);
/* Get the length of the queue */
let size = queue.size();
println!("Queue length size = {}", size);
/* Check if the queue is empty */
let is_empty = queue.is_empty();
println!("Is queue empty = {}", is_empty);
/* Test circular array */
for i in 0..10 {
queue.push(i);
queue.pop();
println!("After round {:?} of enqueue + dequeue, queue = {:?}", i, queue.to_vector());
}
}
@@ -0,0 +1,86 @@
/*
* File: array_stack.rs
* Created Time: 2023-02-05
* Author: WSL0809 (wslzzy@outlook.com), codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
/* Stack based on array implementation */
struct ArrayStack<T> {
stack: Vec<T>,
}
impl<T> ArrayStack<T> {
/* Access top of the stack element */
fn new() -> ArrayStack<T> {
ArrayStack::<T> {
stack: Vec::<T>::new(),
}
}
/* Get the length of the stack */
fn size(&self) -> usize {
self.stack.len()
}
/* Check if the stack is empty */
fn is_empty(&self) -> bool {
self.size() == 0
}
/* Push */
fn push(&mut self, num: T) {
self.stack.push(num);
}
/* Pop */
fn pop(&mut self) -> Option<T> {
self.stack.pop()
}
/* Return list for printing */
fn peek(&self) -> Option<&T> {
if self.is_empty() {
panic!("Stack is empty")
};
self.stack.last()
}
/* Return &Vec */
fn to_array(&self) -> &Vec<T> {
&self.stack
}
}
/* Driver Code */
fn main() {
// Access top of the stack element
let mut stack = ArrayStack::<i32>::new();
// Elements push onto stack
stack.push(1);
stack.push(3);
stack.push(2);
stack.push(5);
stack.push(4);
print!("Stack stack = ");
print_util::print_array(stack.to_array());
// Return list for printing
let peek = stack.peek().unwrap();
print!("\nTop element peek = {}", peek);
// Element pop from stack
let pop = stack.pop().unwrap();
print!("\nPop element pop = {pop}, after pop stack = ");
print_util::print_array(stack.to_array());
// Get the length of the stack
let size = stack.size();
print!("\nStack length size = {size}");
// Check if empty
let is_empty = stack.is_empty();
print!("\nIs stack empty = {is_empty}");
}
@@ -0,0 +1,49 @@
/*
* File: deque.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICEx@outlook.com)
*/
use hello_algo_rust::include::print_util;
use std::collections::VecDeque;
/* Driver Code */
pub fn main() {
// Get the length of the double-ended queue
let mut deque: VecDeque<i32> = VecDeque::new();
deque.push_back(3);
deque.push_back(2);
deque.push_back(5);
print!("Double-ended queue deque = ");
print_util::print_queue(&deque);
// Update element
let peek_first = deque.front().unwrap();
print!("\nFront element peekFirst = {peek_first}");
let peek_last = deque.back().unwrap();
print!("\nRear element peekLast = {peek_last}");
/* Elements enqueue */
deque.push_back(4);
print!("\nAfter element 4 enqueues at rear, deque = ");
print_util::print_queue(&deque);
deque.push_front(1);
print!("\nAfter element 1 enqueues at front, deque = ");
print_util::print_queue(&deque);
// Element dequeue
let pop_last = deque.pop_back().unwrap();
print!("\nDequeue rear element = {pop_last}, after dequeue deque = ");
print_util::print_queue(&deque);
let pop_first = deque.pop_front().unwrap();
print!("\nDequeue front element = {pop_first}, after dequeue deque = ");
print_util::print_queue(&deque);
// Get the length of the double-ended queue
let size = deque.len();
print!("\nDeque length size = {size}");
// Check if the double-ended queue is empty
let is_empty = deque.is_empty();
print!("\nIs deque empty = {is_empty}");
}
@@ -0,0 +1,218 @@
/*
* File: linkedlist_deque.rs
* Created Time: 2023-03-11
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
use std::cell::RefCell;
use std::rc::Rc;
/* Doubly linked list node */
pub struct ListNode<T> {
pub val: T, // Node value
pub next: Option<Rc<RefCell<ListNode<T>>>>, // Successor node pointer
pub prev: Option<Rc<RefCell<ListNode<T>>>>, // Predecessor node pointer
}
impl<T> ListNode<T> {
pub fn new(val: T) -> Rc<RefCell<ListNode<T>>> {
Rc::new(RefCell::new(ListNode {
val,
next: None,
prev: None,
}))
}
}
/* Double-ended queue based on doubly linked list implementation */
#[allow(dead_code)]
pub struct LinkedListDeque<T> {
front: Option<Rc<RefCell<ListNode<T>>>>, // Head node front
rear: Option<Rc<RefCell<ListNode<T>>>>, // Tail node rear
que_size: usize, // Length of the double-ended queue
}
impl<T: Copy> LinkedListDeque<T> {
pub fn new() -> Self {
Self {
front: None,
rear: None,
que_size: 0,
}
}
/* Get the length of the double-ended queue */
pub fn size(&self) -> usize {
return self.que_size;
}
/* Check if the double-ended queue is empty */
pub fn is_empty(&self) -> bool {
return self.que_size == 0;
}
/* Enqueue operation */
fn push(&mut self, num: T, is_front: bool) {
let node = ListNode::new(num);
// Front of the queue enqueue operation
if is_front {
match self.front.take() {
// If the linked list is empty, make both front and rear point to node
None => {
self.rear = Some(node.clone());
self.front = Some(node);
}
// Add node to the head of the linked list
Some(old_front) => {
old_front.borrow_mut().prev = Some(node.clone());
node.borrow_mut().next = Some(old_front);
self.front = Some(node); // Update head node
}
}
}
// Rear of the queue enqueue operation
else {
match self.rear.take() {
// If the linked list is empty, make both front and rear point to node
None => {
self.front = Some(node.clone());
self.rear = Some(node);
}
// Add node to the tail of the linked list
Some(old_rear) => {
old_rear.borrow_mut().next = Some(node.clone());
node.borrow_mut().prev = Some(old_rear);
self.rear = Some(node); // Update tail node
}
}
}
self.que_size += 1; // Update queue length
}
/* Front of the queue enqueue */
pub fn push_first(&mut self, num: T) {
self.push(num, true);
}
/* Rear of the queue enqueue */
pub fn push_last(&mut self, num: T) {
self.push(num, false);
}
/* Dequeue operation */
fn pop(&mut self, is_front: bool) -> Option<T> {
// If queue is empty, return None directly
if self.is_empty() {
return None;
};
// Temporarily store head node value
if is_front {
self.front.take().map(|old_front| {
match old_front.borrow_mut().next.take() {
Some(new_front) => {
new_front.borrow_mut().prev.take();
self.front = Some(new_front); // Update head node
}
None => {
self.rear.take();
}
}
self.que_size -= 1; // Update queue length
old_front.borrow().val
})
}
// Temporarily store tail node value
else {
self.rear.take().map(|old_rear| {
match old_rear.borrow_mut().prev.take() {
Some(new_rear) => {
new_rear.borrow_mut().next.take();
self.rear = Some(new_rear); // Update tail node
}
None => {
self.front.take();
}
}
self.que_size -= 1; // Update queue length
old_rear.borrow().val
})
}
}
/* Rear of the queue dequeue */
pub fn pop_first(&mut self) -> Option<T> {
return self.pop(true);
}
/* Access rear of the queue element */
pub fn pop_last(&mut self) -> Option<T> {
return self.pop(false);
}
/* Return list for printing */
pub fn peek_first(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
self.front.as_ref()
}
/* Driver Code */
pub fn peek_last(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
self.rear.as_ref()
}
/* Return array for printing */
pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {
let mut res: Vec<T> = Vec::new();
fn recur<T: Copy>(cur: Option<&Rc<RefCell<ListNode<T>>>>, res: &mut Vec<T>) {
if let Some(cur) = cur {
res.push(cur.borrow().val);
recur(cur.borrow().next.as_ref(), res);
}
}
recur(head, &mut res);
res
}
}
/* Driver Code */
fn main() {
/* Get the length of the double-ended queue */
let mut deque = LinkedListDeque::new();
deque.push_last(3);
deque.push_last(2);
deque.push_last(5);
print!("Double-ended queue deque = ");
print_util::print_array(&deque.to_array(deque.peek_first()));
/* Update element */
let peek_first = deque.peek_first().unwrap().borrow().val;
print!("\nFront element peek_first = {}", peek_first);
let peek_last = deque.peek_last().unwrap().borrow().val;
print!("\nRear element peek_last = {}", peek_last);
/* Elements enqueue */
deque.push_last(4);
print!("\nAfter element 4 enqueues at rear, deque = ");
print_util::print_array(&deque.to_array(deque.peek_first()));
deque.push_first(1);
print!("\nAfter element 1 enqueues at front, deque = ");
print_util::print_array(&deque.to_array(deque.peek_first()));
/* Element dequeue */
let pop_last = deque.pop_last().unwrap();
print!("\nDequeue rear element = {}, after dequeue deque = ", pop_last);
print_util::print_array(&deque.to_array(deque.peek_first()));
let pop_first = deque.pop_first().unwrap();
print!("\nDequeue front element = {}, after dequeue deque = ", pop_first);
print_util::print_array(&deque.to_array(deque.peek_first()));
/* Get the length of the double-ended queue */
let size = deque.size();
print!("\nDeque length size = {}", size);
/* Check if the double-ended queue is empty */
let is_empty = deque.is_empty();
print!("\nIs deque empty = {}", is_empty);
}
@@ -0,0 +1,126 @@
/*
* File: linkedlist_queue.rs
* Created Time: 2023-03-11
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, ListNode};
use std::cell::RefCell;
use std::rc::Rc;
/* Queue based on linked list implementation */
#[allow(dead_code)]
pub struct LinkedListQueue<T> {
front: Option<Rc<RefCell<ListNode<T>>>>, // Head node front
rear: Option<Rc<RefCell<ListNode<T>>>>, // Tail node rear
que_size: usize, // Queue length
}
impl<T: Copy> LinkedListQueue<T> {
pub fn new() -> Self {
Self {
front: None,
rear: None,
que_size: 0,
}
}
/* Get the length of the queue */
pub fn size(&self) -> usize {
return self.que_size;
}
/* Check if the queue is empty */
pub fn is_empty(&self) -> bool {
return self.que_size == 0;
}
/* Enqueue */
pub fn push(&mut self, num: T) {
// Add num after the tail node
let new_rear = ListNode::new(num);
match self.rear.take() {
// If the queue is not empty, add the node after the tail node
Some(old_rear) => {
old_rear.borrow_mut().next = Some(new_rear.clone());
self.rear = Some(new_rear);
}
// If the queue is empty, make both front and rear point to the node
None => {
self.front = Some(new_rear.clone());
self.rear = Some(new_rear);
}
}
self.que_size += 1;
}
/* Dequeue */
pub fn pop(&mut self) -> Option<T> {
self.front.take().map(|old_front| {
match old_front.borrow_mut().next.take() {
Some(new_front) => {
self.front = Some(new_front);
}
None => {
self.rear.take();
}
}
self.que_size -= 1;
old_front.borrow().val
})
}
/* Return list for printing */
pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
self.front.as_ref()
}
/* Convert linked list to Array and return */
pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {
let mut res: Vec<T> = Vec::new();
fn recur<T: Copy>(cur: Option<&Rc<RefCell<ListNode<T>>>>, res: &mut Vec<T>) {
if let Some(cur) = cur {
res.push(cur.borrow().val);
recur(cur.borrow().next.as_ref(), res);
}
}
recur(head, &mut res);
res
}
}
/* Driver Code */
fn main() {
/* Access front of the queue element */
let mut queue = LinkedListQueue::new();
/* Elements enqueue */
queue.push(1);
queue.push(3);
queue.push(2);
queue.push(5);
queue.push(4);
print!("Queue queue = ");
print_util::print_array(&queue.to_array(queue.peek()));
/* Return list for printing */
let peek = queue.peek().unwrap().borrow().val;
print!("\nFront element peek = {}", peek);
/* Element dequeue */
let pop = queue.pop().unwrap();
print!("\nDequeue element pop = {}, after dequeue queue = ", pop);
print_util::print_array(&queue.to_array(queue.peek()));
/* Get the length of the queue */
let size = queue.size();
print!("\nQueue length size = {}", size);
/* Check if the queue is empty */
let is_empty = queue.is_empty();
print!("\nIs queue empty = {}", is_empty);
}
@@ -0,0 +1,105 @@
/*
* File: linkedlist_stack.rs
* Created Time: 2023-03-11
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, ListNode};
use std::cell::RefCell;
use std::rc::Rc;
/* Stack based on linked list implementation */
#[allow(dead_code)]
pub struct LinkedListStack<T> {
stack_peek: Option<Rc<RefCell<ListNode<T>>>>, // Use head node as stack top
stk_size: usize, // Stack length
}
impl<T: Copy> LinkedListStack<T> {
pub fn new() -> Self {
Self {
stack_peek: None,
stk_size: 0,
}
}
/* Get the length of the stack */
pub fn size(&self) -> usize {
return self.stk_size;
}
/* Check if the stack is empty */
pub fn is_empty(&self) -> bool {
return self.size() == 0;
}
/* Push */
pub fn push(&mut self, num: T) {
let node = ListNode::new(num);
node.borrow_mut().next = self.stack_peek.take();
self.stack_peek = Some(node);
self.stk_size += 1;
}
/* Pop */
pub fn pop(&mut self) -> Option<T> {
self.stack_peek.take().map(|old_head| {
self.stack_peek = old_head.borrow_mut().next.take();
self.stk_size -= 1;
old_head.borrow().val
})
}
/* Return list for printing */
pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
self.stack_peek.as_ref()
}
/* Convert List to Array and return */
pub fn to_array(&self) -> Vec<T> {
fn _to_array<T: Sized + Copy>(head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {
if let Some(node) = head {
let mut nums = _to_array(node.borrow().next.as_ref());
nums.push(node.borrow().val);
return nums;
}
return Vec::new();
}
_to_array(self.peek())
}
}
/* Driver Code */
fn main() {
/* Access top of the stack element */
let mut stack = LinkedListStack::new();
/* Elements push onto stack */
stack.push(1);
stack.push(3);
stack.push(2);
stack.push(5);
stack.push(4);
print!("Stack stack = ");
print_util::print_array(&stack.to_array());
/* Return list for printing */
let peek = stack.peek().unwrap().borrow().val;
print!("\nTop element peek = {}", peek);
/* Element pop from stack */
let pop = stack.pop().unwrap();
print!("\nPop element pop = {}, after pop stack = ", pop);
print_util::print_array(&stack.to_array());
/* Get the length of the stack */
let size = stack.size();
print!("\nStack length size = {}", size);
/* Check if empty */
let is_empty = stack.is_empty();
print!("\nIs stack empty = {}", is_empty);
}
@@ -0,0 +1,41 @@
/*
* File: queue.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICEx@outlook.com)
*/
use hello_algo_rust::include::print_util;
use std::collections::VecDeque;
/* Driver Code */
pub fn main() {
// Access front of the queue element
let mut queue: VecDeque<i32> = VecDeque::new();
// Elements enqueue
queue.push_back(1);
queue.push_back(3);
queue.push_back(2);
queue.push_back(5);
queue.push_back(4);
print!("Queue queue = ");
print_util::print_queue(&queue);
// Return list for printing
let peek = queue.front().unwrap();
println!("\nFront element peek = {peek}");
// Element dequeue
let pop = queue.pop_front().unwrap();
print!("Dequeue element pop = {pop}, after dequeue queue = ");
print_util::print_queue(&queue);
// Get the length of the queue
let size = queue.len();
print!("\nQueue length size = {size}");
// Check if the queue is empty
let is_empty = queue.is_empty();
print!("\nIs queue empty = {is_empty}");
}
@@ -0,0 +1,40 @@
/*
* File: stack.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
/* Driver Code */
pub fn main() {
// Access top of the stack element
// In Rust, it's recommended to use Vec as a stack
let mut stack: Vec<i32> = Vec::new();
// Elements push onto stack
stack.push(1);
stack.push(3);
stack.push(2);
stack.push(5);
stack.push(4);
print!("Stack stack = ");
print_util::print_array(&stack);
// Return list for printing
let peek = stack.last().unwrap();
print!("\nTop element peek = {peek}");
// Element pop from stack
let pop = stack.pop().unwrap();
print!("\nPop element pop = {pop}, after pop stack = ");
print_util::print_array(&stack);
// Get the length of the stack
let size = stack.len();
print!("\nStack length size = {size}");
// Check if the stack is empty
let is_empty = stack.is_empty();
print!("\nIs stack empty = {is_empty}");
}
@@ -0,0 +1,192 @@
/*
* File: array_binary_tree.rs
* Created Time: 2023-07-25
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::{print_util, tree_node};
/* Binary tree class represented by array */
struct ArrayBinaryTree {
tree: Vec<Option<i32>>,
}
impl ArrayBinaryTree {
/* Constructor */
fn new(arr: Vec<Option<i32>>) -> Self {
Self { tree: arr }
}
/* List capacity */
fn size(&self) -> i32 {
self.tree.len() as i32
}
/* Get value of node at index i */
fn val(&self, i: i32) -> Option<i32> {
// If index is out of bounds, return None, representing empty position
if i < 0 || i >= self.size() {
None
} else {
self.tree[i as usize]
}
}
/* Get index of left child node of node at index i */
fn left(&self, i: i32) -> i32 {
2 * i + 1
}
/* Get index of right child node of node at index i */
fn right(&self, i: i32) -> i32 {
2 * i + 2
}
/* Get index of parent node of node at index i */
fn parent(&self, i: i32) -> i32 {
(i - 1) / 2
}
/* Level-order traversal */
fn level_order(&self) -> Vec<i32> {
self.tree.iter().filter_map(|&x| x).collect()
}
/* Depth-first traversal */
fn dfs(&self, i: i32, order: &'static str, res: &mut Vec<i32>) {
if self.val(i).is_none() {
return;
}
let val = self.val(i).unwrap();
// Preorder traversal
if order == "pre" {
res.push(val);
}
self.dfs(self.left(i), order, res);
// Inorder traversal
if order == "in" {
res.push(val);
}
self.dfs(self.right(i), order, res);
// Postorder traversal
if order == "post" {
res.push(val);
}
}
/* Preorder traversal */
fn pre_order(&self) -> Vec<i32> {
let mut res = vec![];
self.dfs(0, "pre", &mut res);
res
}
/* Inorder traversal */
fn in_order(&self) -> Vec<i32> {
let mut res = vec![];
self.dfs(0, "in", &mut res);
res
}
/* Postorder traversal */
fn post_order(&self) -> Vec<i32> {
let mut res = vec![];
self.dfs(0, "post", &mut res);
res
}
}
/* Driver Code */
fn main() {
// Initialize binary tree
// Here we use a function to generate a binary tree directly from an array
let arr = vec![
Some(1),
Some(2),
Some(3),
Some(4),
None,
Some(6),
Some(7),
Some(8),
Some(9),
None,
None,
Some(12),
None,
None,
Some(15),
];
let root = tree_node::vec_to_tree(arr.clone()).unwrap();
println!("\nInitialize binary tree\n");
println!("Array representation of binary tree:");
println!(
"[{}]",
arr.iter()
.map(|&val| if let Some(val) = val {
format!("{val}")
} else {
"null".to_string()
})
.collect::<Vec<String>>()
.join(", ")
);
println!("Linked list representation of binary tree:");
print_util::print_tree(&root);
// Binary tree class represented by array
let abt = ArrayBinaryTree::new(arr);
// Access node
let i = 1;
let l = abt.left(i);
let r = abt.right(i);
let p = abt.parent(i);
println!(
"\nCurrent node index is {}, value is {}",
i,
if let Some(val) = abt.val(i) {
format!("{val}")
} else {
"null".to_string()
}
);
println!(
"Left child index is {}, value is {}",
l,
if let Some(val) = abt.val(l) {
format!("{val}")
} else {
"null".to_string()
}
);
println!(
"Right child index is {}, value is {}",
r,
if let Some(val) = abt.val(r) {
format!("{val}")
} else {
"null".to_string()
}
);
println!(
"Parent node index is {}, value is {}",
p,
if let Some(val) = abt.val(p) {
format!("{val}")
} else {
"null".to_string()
}
);
// Traverse tree
let mut res = abt.level_order();
println!("\nLevel-order traversal is: {:?}", res);
res = abt.pre_order();
println!("Pre-order traversal is: {:?}", res);
res = abt.in_order();
println!("In-order traversal is: {:?}", res);
res = abt.post_order();
println!("Post-order traversal is: {:?}", res);
}
+297
View File
@@ -0,0 +1,297 @@
/*
* File: avl_tree.rs
* Created Time: 2023-07-14
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::{print_util, TreeNode};
use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
type OptionTreeNodeRc = Option<Rc<RefCell<TreeNode>>>;
/* AVL tree */
struct AVLTree {
root: OptionTreeNodeRc, // Root node
}
impl AVLTree {
/* Constructor */
fn new() -> Self {
Self { root: None }
}
/* Get node height */
fn height(node: OptionTreeNodeRc) -> i32 {
// Empty node height is -1, leaf node height is 0
match node {
Some(node) => node.borrow().height,
None => -1,
}
}
/* Update node height */
fn update_height(node: OptionTreeNodeRc) {
if let Some(node) = node {
let left = node.borrow().left.clone();
let right = node.borrow().right.clone();
// Node height equals the height of the tallest subtree + 1
node.borrow_mut().height = std::cmp::max(Self::height(left), Self::height(right)) + 1;
}
}
/* Get balance factor */
fn balance_factor(node: OptionTreeNodeRc) -> i32 {
match node {
// Empty node balance factor is 0
None => 0,
// Node balance factor = left subtree height - right subtree height
Some(node) => {
Self::height(node.borrow().left.clone()) - Self::height(node.borrow().right.clone())
}
}
}
/* Right rotation operation */
fn right_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
match node {
Some(node) => {
let child = node.borrow().left.clone().unwrap();
let grand_child = child.borrow().right.clone();
// Using child as pivot, rotate node to the right
child.borrow_mut().right = Some(node.clone());
node.borrow_mut().left = grand_child;
// Update node height
Self::update_height(Some(node));
Self::update_height(Some(child.clone()));
// Return root node of subtree after rotation
Some(child)
}
None => None,
}
}
/* Left rotation operation */
fn left_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
match node {
Some(node) => {
let child = node.borrow().right.clone().unwrap();
let grand_child = child.borrow().left.clone();
// Using child as pivot, rotate node to the left
child.borrow_mut().left = Some(node.clone());
node.borrow_mut().right = grand_child;
// Update node height
Self::update_height(Some(node));
Self::update_height(Some(child.clone()));
// Return root node of subtree after rotation
Some(child)
}
None => None,
}
}
/* Perform rotation operation to restore balance to this subtree */
fn rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
// Get balance factor of node
let balance_factor = Self::balance_factor(node.clone());
// Left-leaning tree
if balance_factor > 1 {
let node = node.unwrap();
if Self::balance_factor(node.borrow().left.clone()) >= 0 {
// Right rotation
Self::right_rotate(Some(node))
} else {
// First left rotation then right rotation
let left = node.borrow().left.clone();
node.borrow_mut().left = Self::left_rotate(left);
Self::right_rotate(Some(node))
}
}
// Right-leaning tree
else if balance_factor < -1 {
let node = node.unwrap();
if Self::balance_factor(node.borrow().right.clone()) <= 0 {
// Left rotation
Self::left_rotate(Some(node))
} else {
// First right rotation then left rotation
let right = node.borrow().right.clone();
node.borrow_mut().right = Self::right_rotate(right);
Self::left_rotate(Some(node))
}
} else {
// Balanced tree, no rotation needed, return directly
node
}
}
/* Insert node */
fn insert(&mut self, val: i32) {
self.root = Self::insert_helper(self.root.clone(), val);
}
/* Recursively insert node (helper method) */
fn insert_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc {
match node {
Some(mut node) => {
/* 1. Find insertion position and insert node */
match {
let node_val = node.borrow().val;
node_val
}
.cmp(&val)
{
Ordering::Greater => {
let left = node.borrow().left.clone();
node.borrow_mut().left = Self::insert_helper(left, val);
}
Ordering::Less => {
let right = node.borrow().right.clone();
node.borrow_mut().right = Self::insert_helper(right, val);
}
Ordering::Equal => {
return Some(node); // Duplicate node not inserted, return directly
}
}
Self::update_height(Some(node.clone())); // Update node height
/* 2. Perform rotation operation to restore balance to this subtree */
node = Self::rotate(Some(node)).unwrap();
// Return root node of subtree
Some(node)
}
None => Some(TreeNode::new(val)),
}
}
/* Remove node */
fn remove(&self, val: i32) {
Self::remove_helper(self.root.clone(), val);
}
/* Recursively delete node (helper method) */
fn remove_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc {
match node {
Some(mut node) => {
/* 1. Find node and delete */
if val < node.borrow().val {
let left = node.borrow().left.clone();
node.borrow_mut().left = Self::remove_helper(left, val);
} else if val > node.borrow().val {
let right = node.borrow().right.clone();
node.borrow_mut().right = Self::remove_helper(right, val);
} else if node.borrow().left.is_none() || node.borrow().right.is_none() {
let child = if node.borrow().left.is_some() {
node.borrow().left.clone()
} else {
node.borrow().right.clone()
};
match child {
// Number of child nodes = 0, delete node directly and return
None => {
return None;
}
// Number of child nodes = 1, delete node directly
Some(child) => node = child,
}
} else {
// Number of child nodes = 2, delete the next node in inorder traversal and replace current node with it
let mut temp = node.borrow().right.clone().unwrap();
loop {
let temp_left = temp.borrow().left.clone();
if temp_left.is_none() {
break;
}
temp = temp_left.unwrap();
}
let right = node.borrow().right.clone();
node.borrow_mut().right = Self::remove_helper(right, temp.borrow().val);
node.borrow_mut().val = temp.borrow().val;
}
Self::update_height(Some(node.clone())); // Update node height
/* 2. Perform rotation operation to restore balance to this subtree */
node = Self::rotate(Some(node)).unwrap();
// Return root node of subtree
Some(node)
}
None => None,
}
}
/* Search node */
fn search(&self, val: i32) -> OptionTreeNodeRc {
let mut cur = self.root.clone();
// Loop search, exit after passing leaf node
while let Some(current) = cur.clone() {
match current.borrow().val.cmp(&val) {
// Target node is in cur's right subtree
Ordering::Less => {
cur = current.borrow().right.clone();
}
// Target node is in cur's left subtree
Ordering::Greater => {
cur = current.borrow().left.clone();
}
// Found target node, exit loop
Ordering::Equal => {
break;
}
}
}
// Return target node
cur
}
}
/* Driver Code */
fn main() {
fn test_insert(tree: &mut AVLTree, val: i32) {
tree.insert(val);
println!("\nAfter inserting node {}, AVL tree is", val);
print_util::print_tree(&tree.root.clone().unwrap());
}
fn test_remove(tree: &mut AVLTree, val: i32) {
tree.remove(val);
println!("\nAfter deleting node {}, AVL tree is", val);
print_util::print_tree(&tree.root.clone().unwrap());
}
/* Please pay attention to how the AVL tree maintains balance after inserting nodes */
let mut avl_tree = AVLTree::new();
/* Insert node */
// Delete nodes
test_insert(&mut avl_tree, 1);
test_insert(&mut avl_tree, 2);
test_insert(&mut avl_tree, 3);
test_insert(&mut avl_tree, 4);
test_insert(&mut avl_tree, 5);
test_insert(&mut avl_tree, 8);
test_insert(&mut avl_tree, 7);
test_insert(&mut avl_tree, 9);
test_insert(&mut avl_tree, 10);
test_insert(&mut avl_tree, 6);
/* Please pay attention to how the AVL tree maintains balance after deleting nodes */
test_insert(&mut avl_tree, 7);
/* Remove node */
// Delete node with degree 1
test_remove(&mut avl_tree, 8); // Delete node with degree 2
test_remove(&mut avl_tree, 5); // Remove node with degree 1
test_remove(&mut avl_tree, 4); // Remove node with degree 2
/* Search node */
let node = avl_tree.search(7);
if let Some(node) = node {
println!(
"\nFound node object is {:?}, node value = {}",
&*node.borrow(),
node.borrow().val
);
}
}
@@ -0,0 +1,195 @@
/*
* File: binary_search_tree.rs
* Created Time: 2023-04-20
* Author: xBLACKICEx (xBLACKICE@outlook.com)、night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::rc::Rc;
use hello_algo_rust::include::TreeNode;
type OptionTreeNodeRc = Option<Rc<RefCell<TreeNode>>>;
/* Binary search tree */
pub struct BinarySearchTree {
root: OptionTreeNodeRc,
}
impl BinarySearchTree {
/* Constructor */
pub fn new() -> Self {
// Initialize empty tree
Self { root: None }
}
/* Get binary tree root node */
pub fn get_root(&self) -> OptionTreeNodeRc {
self.root.clone()
}
/* Search node */
pub fn search(&self, num: i32) -> OptionTreeNodeRc {
let mut cur = self.root.clone();
// Loop search, exit after passing leaf node
while let Some(node) = cur.clone() {
match num.cmp(&node.borrow().val) {
// Target node is in cur's right subtree
Ordering::Greater => cur = node.borrow().right.clone(),
// Target node is in cur's left subtree
Ordering::Less => cur = node.borrow().left.clone(),
// Found target node, exit loop
Ordering::Equal => break,
}
}
// Return target node
cur
}
/* Insert node */
pub fn insert(&mut self, num: i32) {
// If tree is empty, initialize root node
if self.root.is_none() {
self.root = Some(TreeNode::new(num));
return;
}
let mut cur = self.root.clone();
let mut pre = None;
// Loop search, exit after passing leaf node
while let Some(node) = cur.clone() {
match num.cmp(&node.borrow().val) {
// Found duplicate node, return directly
Ordering::Equal => return,
// Insertion position is in cur's right subtree
Ordering::Greater => {
pre = cur.clone();
cur = node.borrow().right.clone();
}
// Insertion position is in cur's left subtree
Ordering::Less => {
pre = cur.clone();
cur = node.borrow().left.clone();
}
}
}
// Insert node
let pre = pre.unwrap();
let node = Some(TreeNode::new(num));
if num > pre.borrow().val {
pre.borrow_mut().right = node;
} else {
pre.borrow_mut().left = node;
}
}
/* Remove node */
pub fn remove(&mut self, num: i32) {
// If tree is empty, return directly
if self.root.is_none() {
return;
}
let mut cur = self.root.clone();
let mut pre = None;
// Loop search, exit after passing leaf node
while let Some(node) = cur.clone() {
match num.cmp(&node.borrow().val) {
// Found node to delete, exit loop
Ordering::Equal => break,
// Node to delete is in cur's right subtree
Ordering::Greater => {
pre = cur.clone();
cur = node.borrow().right.clone();
}
// Node to delete is in cur's left subtree
Ordering::Less => {
pre = cur.clone();
cur = node.borrow().left.clone();
}
}
}
// If no node to delete, return directly
if cur.is_none() {
return;
}
let cur = cur.unwrap();
let (left_child, right_child) = (cur.borrow().left.clone(), cur.borrow().right.clone());
match (left_child.clone(), right_child.clone()) {
// Number of child nodes = 0 or 1
(None, None) | (Some(_), None) | (None, Some(_)) => {
// When number of child nodes = 0 / 1, child = nullptr / that child node
let child = left_child.or(right_child);
let pre = pre.unwrap();
// Delete node cur
if !Rc::ptr_eq(&cur, self.root.as_ref().unwrap()) {
let left = pre.borrow().left.clone();
if left.is_some() && Rc::ptr_eq(left.as_ref().unwrap(), &cur) {
pre.borrow_mut().left = child;
} else {
pre.borrow_mut().right = child;
}
} else {
// If deleted node is root node, reassign root node
self.root = child;
}
}
// Number of child nodes = 2
(Some(_), Some(_)) => {
// Get next node of cur in inorder traversal
let mut tmp = cur.borrow().right.clone();
while let Some(node) = tmp.clone() {
if node.borrow().left.is_some() {
tmp = node.borrow().left.clone();
} else {
break;
}
}
let tmp_val = tmp.unwrap().borrow().val;
// Recursively delete node tmp
self.remove(tmp_val);
// Replace cur with tmp
cur.borrow_mut().val = tmp_val;
}
}
}
}
/* Driver Code */
fn main() {
/* Initialize binary search tree */
let mut bst = BinarySearchTree::new();
// Please note that different insertion orders will generate different binary trees, this sequence can generate a perfect binary tree
let nums = [8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15];
for &num in &nums {
bst.insert(num);
}
println!("\nInitialized binary tree is\n");
print_util::print_tree(bst.get_root().as_ref().unwrap());
/* Search node */
let node = bst.search(7);
println!(
"\nFound node object is {:?}, node value = {}",
node.clone().unwrap(),
node.clone().unwrap().borrow().val
);
/* Insert node */
bst.insert(16);
println!("\nAfter inserting node 16, binary tree is\n");
print_util::print_tree(bst.get_root().as_ref().unwrap());
/* Remove node */
bst.remove(1);
println!("\nAfter removing node 1, binary tree is\n");
print_util::print_tree(bst.get_root().as_ref().unwrap());
bst.remove(2);
println!("\nAfter removing node 2, binary tree is\n");
print_util::print_tree(bst.get_root().as_ref().unwrap());
bst.remove(4);
println!("\nAfter removing node 4, binary tree is\n");
print_util::print_tree(bst.get_root().as_ref().unwrap());
}
+38
View File
@@ -0,0 +1,38 @@
/**
* File: binary_tree.rs
* Created Time: 2023-02-27
* Author: xBLACKICEx (xBLACKICE@outlook.com)
*/
use std::rc::Rc;
use hello_algo_rust::include::{print_util, TreeNode};
/* Driver Code */
fn main() {
/* Initialize binary tree */
// Initialize nodes
let n1 = TreeNode::new(1);
let n2 = TreeNode::new(2);
let n3 = TreeNode::new(3);
let n4 = TreeNode::new(4);
let n5 = TreeNode::new(5);
// Build references (pointers) between nodes
n1.borrow_mut().left = Some(Rc::clone(&n2));
n1.borrow_mut().right = Some(Rc::clone(&n3));
n2.borrow_mut().left = Some(Rc::clone(&n4));
n2.borrow_mut().right = Some(Rc::clone(&n5));
println!("\nInitialize binary tree\n");
print_util::print_tree(&n1);
// Insert node and delete node
let p = TreeNode::new(0);
// Delete node
p.borrow_mut().left = Some(Rc::clone(&n2));
n1.borrow_mut().left = Some(Rc::clone(&p));
println!("\nAfter inserting node P\n");
print_util::print_tree(&n1);
// Remove node P
drop(p);
n1.borrow_mut().left = Some(Rc::clone(&n2));
println!("\nAfter removing node P\n");
print_util::print_tree(&n1);
}
@@ -0,0 +1,45 @@
/*
* File: binary_tree_bfs.rs
* Created Time: 2023-04-07
* Author: xBLACKICEx (xBLACKICE@outlook.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use hello_algo_rust::op_vec;
use std::collections::VecDeque;
use std::{cell::RefCell, rc::Rc};
/* Level-order traversal */
fn level_order(root: &Rc<RefCell<TreeNode>>) -> Vec<i32> {
// Initialize queue, add root node
let mut que = VecDeque::new();
que.push_back(root.clone());
// Initialize a list to save the traversal sequence
let mut vec = Vec::new();
while let Some(node) = que.pop_front() {
// Dequeue
vec.push(node.borrow().val); // Save node value
if let Some(left) = node.borrow().left.as_ref() {
que.push_back(left.clone()); // Left child node enqueue
}
if let Some(right) = node.borrow().right.as_ref() {
que.push_back(right.clone()); // Right child node enqueue
};
}
vec
}
/* Driver Code */
fn main() {
/* Initialize binary tree */
// Here we use a function to generate a binary tree directly from an array
let root = vec_to_tree(op_vec![1, 2, 3, 4, 5, 6, 7]).unwrap();
println!("Initialize binary tree\n");
print_util::print_tree(&root);
/* Level-order traversal */
let vec = level_order(&root);
print!("\nLevel-order traversal node sequence = {:?}", vec);
}
@@ -0,0 +1,87 @@
/*
* File: binary_tree_dfs.rs
* Created Time: 2023-04-06
* Author: xBLACKICEx (xBLACKICE@outlook.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use hello_algo_rust::op_vec;
use std::cell::RefCell;
use std::rc::Rc;
/* Preorder traversal */
fn pre_order(root: Option<&Rc<RefCell<TreeNode>>>) -> Vec<i32> {
let mut result = vec![];
fn dfs(root: Option<&Rc<RefCell<TreeNode>>>, res: &mut Vec<i32>) {
if let Some(node) = root {
// Visit priority: root node -> left subtree -> right subtree
let node = node.borrow();
res.push(node.val);
dfs(node.left.as_ref(), res);
dfs(node.right.as_ref(), res);
}
}
dfs(root, &mut result);
result
}
/* Inorder traversal */
fn in_order(root: Option<&Rc<RefCell<TreeNode>>>) -> Vec<i32> {
let mut result = vec![];
fn dfs(root: Option<&Rc<RefCell<TreeNode>>>, res: &mut Vec<i32>) {
if let Some(node) = root {
// Visit priority: left subtree -> root node -> right subtree
let node = node.borrow();
dfs(node.left.as_ref(), res);
res.push(node.val);
dfs(node.right.as_ref(), res);
}
}
dfs(root, &mut result);
result
}
/* Postorder traversal */
fn post_order(root: Option<&Rc<RefCell<TreeNode>>>) -> Vec<i32> {
let mut result = vec![];
fn dfs(root: Option<&Rc<RefCell<TreeNode>>>, res: &mut Vec<i32>) {
if let Some(node) = root {
// Visit priority: left subtree -> right subtree -> root node
let node = node.borrow();
dfs(node.left.as_ref(), res);
dfs(node.right.as_ref(), res);
res.push(node.val);
}
}
dfs(root, &mut result);
result
}
/* Driver Code */
fn main() {
/* Initialize binary tree */
// Here we use a function to generate a binary tree directly from an array
let root = vec_to_tree(op_vec![1, 2, 3, 4, 5, 6, 7]);
println!("Initialize binary tree\n");
print_util::print_tree(root.as_ref().unwrap());
/* Preorder traversal */
let vec = pre_order(root.as_ref());
println!("\nPre-order traversal node sequence = {:?}", vec);
/* Inorder traversal */
let vec = in_order(root.as_ref());
println!("\nIn-order traversal node sequence = {:?}", vec);
/* Postorder traversal */
let vec = post_order(root.as_ref());
print!("\nPost-order traversal node sequence = {:?}", vec);
}
+57
View File
@@ -0,0 +1,57 @@
/*
* File: list_node.rs
* Created Time: 2023-03-05
* Author: codingonion (coderonion@gmail.com), rongyi (hiarongyi@gmail.com)
*/
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Debug)]
pub struct ListNode<T> {
pub val: T,
pub next: Option<Rc<RefCell<ListNode<T>>>>,
}
impl<T> ListNode<T> {
pub fn new(val: T) -> Rc<RefCell<ListNode<T>>> {
Rc::new(RefCell::new(ListNode { val, next: None }))
}
/* Deserialize array to linked list */
pub fn arr_to_linked_list(array: &[T]) -> Option<Rc<RefCell<ListNode<T>>>>
where
T: Copy + Clone,
{
let mut head = None;
// insert in reverse order
for item in array.iter().rev() {
let node = Rc::new(RefCell::new(ListNode {
val: *item,
next: head.take(),
}));
head = Some(node);
}
head
}
/* Convert linked list to hash table */
pub fn linked_list_to_hashmap(
linked_list: Option<Rc<RefCell<ListNode<T>>>>,
) -> HashMap<T, Rc<RefCell<ListNode<T>>>>
where
T: std::hash::Hash + Eq + Copy + Clone,
{
let mut hashmap = HashMap::new();
let mut node = linked_list;
while let Some(cur) = node {
let borrow = cur.borrow();
hashmap.insert(borrow.val.clone(), cur.clone());
node = borrow.next.clone();
}
hashmap
}
}
+16
View File
@@ -0,0 +1,16 @@
/*
* File: include.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICE@outlook.com)
*/
pub mod list_node;
pub mod print_util;
pub mod tree_node;
pub mod vertex;
// rexport to include
pub use list_node::*;
pub use print_util::*;
pub use tree_node::*;
pub use vertex::*;
+103
View File
@@ -0,0 +1,103 @@
/*
* File: print_util.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICEx@outlook.com)
*/
use std::cell::{Cell, RefCell};
use std::fmt::Display;
use std::collections::{HashMap, VecDeque};
use std::rc::Rc;
use super::list_node::ListNode;
use super::tree_node::{TreeNode, vec_to_tree};
struct Trunk<'a, 'b> {
prev: Option<&'a Trunk<'a, 'b>>,
str: Cell<&'b str>,
}
/* Print array */
pub fn print_array<T: Display>(nums: &[T]) {
print!("[");
if nums.len() > 0 {
for (i, num) in nums.iter().enumerate() {
print!("{}{}", num, if i == nums.len() - 1 {"]"} else {", "} );
}
} else {
print!("]");
}
}
/* Print hash table */
pub fn print_hash_map<TKey: Display, TValue: Display>(map: &HashMap<TKey, TValue>) {
for (key, value) in map {
println!("{key} -> {value}");
}
}
/* Print queue (deque) */
pub fn print_queue<T: Display>(queue: &VecDeque<T>) {
print!("[");
let iter = queue.iter();
for (i, data) in iter.enumerate() {
print!("{}{}", data, if i == queue.len() - 1 {"]"} else {", "} );
}
}
/* Print linked list */
pub fn print_linked_list<T: Display>(head: &Rc<RefCell<ListNode<T>>>) {
print!("{}{}", head.borrow().val, if head.borrow().next.is_none() {"\n"} else {" -> "});
if let Some(node) = &head.borrow().next {
return print_linked_list(node);
}
}
/* Print binary tree */
pub fn print_tree(root: &Rc<RefCell<TreeNode>>) {
_print_tree(Some(root), None, false);
}
/* Print binary tree */
fn _print_tree(root: Option<&Rc<RefCell<TreeNode>>>, prev: Option<&Trunk>, is_right: bool) {
if let Some(node) = root {
let mut prev_str = " ";
let trunk = Trunk { prev, str: Cell::new(prev_str) };
_print_tree(node.borrow().right.as_ref(), Some(&trunk), true);
if prev.is_none() {
trunk.str.set("———");
} else if is_right {
trunk.str.set("/———");
prev_str = " |";
} else {
trunk.str.set("\\———");
prev.as_ref().unwrap().str.set(prev_str);
}
show_trunks(Some(&trunk));
println!(" {}", node.borrow().val);
if let Some(prev) = prev {
prev.str.set(prev_str);
}
trunk.str.set(" |");
_print_tree(node.borrow().left.as_ref(), Some(&trunk), false);
}
}
fn show_trunks(trunk: Option<&Trunk>) {
if let Some(trunk) = trunk {
show_trunks(trunk.prev);
print!("{}", trunk.str.get());
}
}
/* Print heap */
pub fn print_heap(heap: Vec<i32>) {
println!("Array representation of heap: {:?}", heap);
println!("Heap tree representation:");
if let Some(root) = vec_to_tree(heap.into_iter().map(|val| Some(val)).collect()) {
print_tree(&root);
}
}
+92
View File
@@ -0,0 +1,92 @@
/*
* File: tree_node.rs
* Created Time: 2023-02-27
* Author: xBLACKICEx (xBLACKICE@outlook.com), night-cruise (2586447362@qq.com)
*/
use std::cell::RefCell;
use std::rc::Rc;
/* Binary tree node type */
#[derive(Debug)]
pub struct TreeNode {
pub val: i32,
pub height: i32,
pub parent: Option<Rc<RefCell<TreeNode>>>,
pub left: Option<Rc<RefCell<TreeNode>>>,
pub right: Option<Rc<RefCell<TreeNode>>>,
}
impl TreeNode {
/* Constructor */
pub fn new(val: i32) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self {
val,
height: 0,
parent: None,
left: None,
right: None,
}))
}
}
#[macro_export]
macro_rules! op_vec {
( $( $x:expr ),* ) => {
vec![
$(Option::from($x)),*
]
};
}
// For the serialization encoding rules, please refer to:
// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/
// Array representation of binary tree:
// [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15]
// Linked list representation of binary tree:
// /——— 15
// /——— 7
// /——— 3
// | \——— 6
// | \——— 12
// ——— 1
// \——— 2
// | /——— 9
// \——— 4
// \——— 8
/* Deserialize a list into a binary tree: recursion */
fn vec_to_tree_dfs(arr: &[Option<i32>], i: usize) -> Option<Rc<RefCell<TreeNode>>> {
if i >= arr.len() || arr[i].is_none() {
return None;
}
let root = TreeNode::new(arr[i].unwrap());
root.borrow_mut().left = vec_to_tree_dfs(arr, 2 * i + 1);
root.borrow_mut().right = vec_to_tree_dfs(arr, 2 * i + 2);
Some(root)
}
/* Deserialize a list into a binary tree */
pub fn vec_to_tree(arr: Vec<Option<i32>>) -> Option<Rc<RefCell<TreeNode>>> {
vec_to_tree_dfs(&arr, 0)
}
/* Serialize a binary tree into a list: recursion */
fn tree_to_vec_dfs(root: Option<&Rc<RefCell<TreeNode>>>, i: usize, res: &mut Vec<Option<i32>>) {
if let Some(root) = root {
// i + 1 is the minimum valid size to access index i
while res.len() < i + 1 {
res.push(None);
}
res[i] = Some(root.borrow().val);
tree_to_vec_dfs(root.borrow().left.as_ref(), 2 * i + 1, res);
tree_to_vec_dfs(root.borrow().right.as_ref(), 2 * i + 2, res);
}
}
/* Serialize a binary tree into a list */
pub fn tree_to_vec(root: Option<Rc<RefCell<TreeNode>>>) -> Vec<Option<i32>> {
let mut res = vec![];
tree_to_vec_dfs(root.as_ref(), 0, &mut res);
res
}
+27
View File
@@ -0,0 +1,27 @@
/*
* File: vertex.rs
* Created Time: 2023-07-13
* Author: night-cruise (2586447362@qq.com)
*/
/* Vertex type */
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub struct Vertex {
pub val: i32,
}
impl From<i32> for Vertex {
fn from(value: i32) -> Self {
Self { val: value }
}
}
/* Input value list vals, return vertex list vets */
pub fn vals_to_vets(vals: Vec<i32>) -> Vec<Vertex> {
vals.into_iter().map(|val| val.into()).collect()
}
/* Input vertex list vets, return value list vals */
pub fn vets_to_vals(vets: Vec<Vertex>) -> Vec<i32> {
vets.into_iter().map(|vet| vet.val).collect()
}
+1
View File
@@ -0,0 +1 @@
pub mod include;