mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-24 17:17:14 +00:00
Add ru version (#1865)
* Add Russian docs site baseline * Add Russian localized codebase * Polish Russian code wording * Update ru code translation. * Update code translation and chapter covers. * Fix pythontutor extraction. * Add README and landing page. * placeholder of profiles * Use figures of English version * Remove chapter paperbook
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
target/
|
||||
Cargo.lock
|
||||
@@ -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;
|
||||
|
||||
/* Случайный доступ к элементу */
|
||||
fn random_access(nums: &[i32]) -> i32 {
|
||||
// Случайным образом выбрать число из интервала [0, nums.len())
|
||||
let random_index = rand::thread_rng().gen_range(0..nums.len());
|
||||
// Получить и вернуть случайный элемент
|
||||
let random_num = nums[random_index];
|
||||
random_num
|
||||
}
|
||||
|
||||
/* Увеличить длину массива */
|
||||
fn extend(nums: &[i32], enlarge: usize) -> Vec<i32> {
|
||||
// Инициализировать массив увеличенной длины
|
||||
let mut res: Vec<i32> = vec![0; nums.len() + enlarge];
|
||||
// Скопировать все элементы исходного массива в новый
|
||||
res[0..nums.len()].copy_from_slice(nums);
|
||||
|
||||
// Вернуть новый массив после расширения
|
||||
res
|
||||
}
|
||||
|
||||
/* Вставить элемент num по индексу index в массив */
|
||||
fn insert(nums: &mut [i32], num: i32, index: usize) {
|
||||
// Сдвинуть элемент с индексом index и все последующие элементы на одну позицию назад
|
||||
for i in (index + 1..nums.len()).rev() {
|
||||
nums[i] = nums[i - 1];
|
||||
}
|
||||
// Присвоить num элементу по индексу index
|
||||
nums[index] = num;
|
||||
}
|
||||
|
||||
/* Удалить элемент по индексу index */
|
||||
fn remove(nums: &mut [i32], index: usize) {
|
||||
// Сдвинуть все элементы после индекса index на одну позицию вперед
|
||||
for i in index..nums.len() - 1 {
|
||||
nums[i] = nums[i + 1];
|
||||
}
|
||||
}
|
||||
|
||||
/* Обход массива */
|
||||
fn traverse(nums: &[i32]) {
|
||||
let mut _count = 0;
|
||||
// Обход массива по индексам
|
||||
for i in 0..nums.len() {
|
||||
_count += nums[i];
|
||||
}
|
||||
// Непосредственно обходить элементы массива
|
||||
_count = 0;
|
||||
for &num in nums {
|
||||
_count += num;
|
||||
}
|
||||
}
|
||||
|
||||
/* Найти заданный элемент в массиве */
|
||||
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() {
|
||||
/* Инициализация массива */
|
||||
let arr: [i32; 5] = [0; 5];
|
||||
print!("Массив arr = ");
|
||||
print_util::print_array(&arr);
|
||||
// В Rust при указании длины ([i32; 5]) получается массив, а без указания длины (&[i32]) — срез
|
||||
// Так как массивы в Rust имеют длину, определяемую на этапе компиляции, для задания длины можно использовать только константы
|
||||
// Vector обычно используется в Rust как тип динамического массива
|
||||
// Для удобства реализации метода расширения extend() ниже vector рассматривается как массив (array)
|
||||
let nums: Vec<i32> = vec![1, 3, 2, 5, 4];
|
||||
print!("\nМассив nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Случайный доступ
|
||||
let random_num = random_access(&nums);
|
||||
println!("\nСлучайный элемент из nums = {}", random_num);
|
||||
|
||||
// Расширение длины
|
||||
let mut nums: Vec<i32> = extend(&nums, 3);
|
||||
print!("После увеличения длины массива до 8 nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Вставка элемента
|
||||
insert(&mut nums, 6, 3);
|
||||
print!("\nПосле вставки числа 6 по индексу 3 nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Удаление элемента
|
||||
remove(&mut nums, 2);
|
||||
print!("\nПосле удаления элемента по индексу 2 nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Обход массива
|
||||
traverse(&nums);
|
||||
|
||||
// Поиск элемента
|
||||
let index = find(&nums, 3).unwrap();
|
||||
println!("\nПоиск элемента 3 в nums: индекс = {}", 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;
|
||||
|
||||
/* Вставить узел P после узла n0 в связном списке */
|
||||
#[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);
|
||||
}
|
||||
|
||||
/* Удалить первый узел после узла n0 в связном списке */
|
||||
#[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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Доступ к узлу связного списка по индексу index */
|
||||
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)
|
||||
}
|
||||
|
||||
/* Найти в связном списке первый узел со значением target */
|
||||
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() {
|
||||
/* Инициализация связного списка */
|
||||
// Инициализация всех узлов
|
||||
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);
|
||||
// Построить ссылки между узлами
|
||||
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!("Исходный связный список ");
|
||||
print_util::print_linked_list(&n0);
|
||||
|
||||
/* Вставка узла */
|
||||
insert(&n0, ListNode::new(0));
|
||||
print!("Связный список после вставки узла ");
|
||||
print_util::print_linked_list(&n0);
|
||||
|
||||
/* Удаление узла */
|
||||
remove(&n0);
|
||||
print!("Связный список после удаления узла ");
|
||||
print_util::print_linked_list(&n0);
|
||||
|
||||
/* Доступ к узлу */
|
||||
let node = access(n0.clone(), 3);
|
||||
println!("Значение узла по индексу 3 в связном списке = {}", node.unwrap().borrow().val);
|
||||
|
||||
/* Поиск узла */
|
||||
let index = find(n0.clone(), 2);
|
||||
println!("Индекс узла со значением 2 в связном списке = {}", 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() {
|
||||
// Инициализация списка
|
||||
let mut nums: Vec<i32> = vec![1, 3, 2, 5, 4];
|
||||
print!("Список nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Доступ к элементу
|
||||
let num = nums[1];
|
||||
println!("\nЭлемент по индексу 1: num = {num}");
|
||||
|
||||
// Обновление элемента
|
||||
nums[1] = 0;
|
||||
print!("После обновления элемента по индексу 1 до 0 nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Очистить список
|
||||
nums.clear();
|
||||
print!("\nПосле очистки списка nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Добавление элемента в конец
|
||||
nums.push(1);
|
||||
nums.push(3);
|
||||
nums.push(2);
|
||||
nums.push(5);
|
||||
nums.push(4);
|
||||
print!("\nПосле добавления элементов nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Вставка элемента в середину
|
||||
nums.insert(3, 6);
|
||||
print!("\nПосле вставки числа 6 по индексу 3 nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Удаление элемента
|
||||
nums.remove(3);
|
||||
print!("\nПосле удаления элемента по индексу 3 nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Обходить список по индексам
|
||||
let mut _count = 0;
|
||||
for i in 0..nums.len() {
|
||||
_count += nums[i];
|
||||
}
|
||||
// Непосредственно обходить элементы списка
|
||||
_count = 0;
|
||||
for x in &nums {
|
||||
_count += x;
|
||||
}
|
||||
|
||||
// Объединить два списка
|
||||
let mut nums1 = vec![6, 8, 7, 10, 9];
|
||||
nums.append(&mut nums1); // После append (перемещение) nums1 становится пустым!
|
||||
|
||||
// nums.extend(&nums1); // extend (заимствование), nums1 можно продолжать использовать
|
||||
print!("\nПосле конкатенации списка nums1 к nums nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
// Отсортировать список
|
||||
nums.sort();
|
||||
print!("\nПосле сортировки списка 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;
|
||||
|
||||
/* Класс списка */
|
||||
#[allow(dead_code)]
|
||||
struct MyList {
|
||||
arr: Vec<i32>, // Массив (для хранения элементов списка)
|
||||
capacity: usize, // Вместимость списка
|
||||
size: usize, // Длина списка (текущее число элементов)
|
||||
extend_ratio: usize, // Коэффициент увеличения списка при каждом расширении
|
||||
}
|
||||
|
||||
#[allow(unused, unused_comparisons)]
|
||||
impl MyList {
|
||||
/* Конструктор */
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
let mut vec = vec![0; capacity];
|
||||
Self {
|
||||
arr: vec,
|
||||
capacity,
|
||||
size: 0,
|
||||
extend_ratio: 2,
|
||||
}
|
||||
}
|
||||
|
||||
/* Получить длину списка (текущее число элементов) */
|
||||
pub fn size(&self) -> usize {
|
||||
return self.size;
|
||||
}
|
||||
|
||||
/* Получить вместимость списка */
|
||||
pub fn capacity(&self) -> usize {
|
||||
return self.capacity;
|
||||
}
|
||||
|
||||
/* Доступ к элементу */
|
||||
pub fn get(&self, index: usize) -> i32 {
|
||||
// Если индекс выходит за границы, выбрасывается исключение; далее аналогично
|
||||
if index >= self.size {
|
||||
panic!("индекс выходит за границы")
|
||||
};
|
||||
return self.arr[index];
|
||||
}
|
||||
|
||||
/* Обновление элемента */
|
||||
pub fn set(&mut self, index: usize, num: i32) {
|
||||
if index >= self.size {
|
||||
panic!("индекс выходит за границы")
|
||||
};
|
||||
self.arr[index] = num;
|
||||
}
|
||||
|
||||
/* Добавление элемента в конец */
|
||||
pub fn add(&mut self, num: i32) {
|
||||
// При превышении вместимости по числу элементов запускается расширение
|
||||
if self.size == self.capacity() {
|
||||
self.extend_capacity();
|
||||
}
|
||||
self.arr[self.size] = num;
|
||||
// Обновить число элементов
|
||||
self.size += 1;
|
||||
}
|
||||
|
||||
/* Вставка элемента в середину */
|
||||
pub fn insert(&mut self, index: usize, num: i32) {
|
||||
if index >= self.size() {
|
||||
panic!("индекс выходит за границы")
|
||||
};
|
||||
// При превышении вместимости по числу элементов запускается расширение
|
||||
if self.size == self.capacity() {
|
||||
self.extend_capacity();
|
||||
}
|
||||
// Сдвинуть элемент с индексом index и все следующие элементы на одну позицию назад
|
||||
for j in (index..self.size).rev() {
|
||||
self.arr[j + 1] = self.arr[j];
|
||||
}
|
||||
self.arr[index] = num;
|
||||
// Обновить число элементов
|
||||
self.size += 1;
|
||||
}
|
||||
|
||||
/* Удаление элемента */
|
||||
pub fn remove(&mut self, index: usize) -> i32 {
|
||||
if index >= self.size() {
|
||||
panic!("индекс выходит за границы")
|
||||
};
|
||||
let num = self.arr[index];
|
||||
// Сдвинуть все элементы после индекса index на одну позицию вперед
|
||||
for j in index..self.size - 1 {
|
||||
self.arr[j] = self.arr[j + 1];
|
||||
}
|
||||
// Обновить число элементов
|
||||
self.size -= 1;
|
||||
// Вернуть удаленный элемент
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Расширение списка */
|
||||
pub fn extend_capacity(&mut self) {
|
||||
// Создать новый массив длиной в extend_ratio раз больше исходного и скопировать в него исходный массив
|
||||
let new_capacity = self.capacity * self.extend_ratio;
|
||||
self.arr.resize(new_capacity, 0);
|
||||
// Обновить вместимость списка
|
||||
self.capacity = new_capacity;
|
||||
}
|
||||
|
||||
/* Преобразовать список в массив */
|
||||
pub fn to_array(&self) -> Vec<i32> {
|
||||
// Преобразовывать только элементы списка в пределах фактической длины
|
||||
let mut arr = Vec::new();
|
||||
for i in 0..self.size {
|
||||
arr.push(self.get(i));
|
||||
}
|
||||
arr
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Инициализация списка */
|
||||
let mut nums = MyList::new(10);
|
||||
/* Добавление элемента в конец */
|
||||
nums.add(1);
|
||||
nums.add(3);
|
||||
nums.add(2);
|
||||
nums.add(5);
|
||||
nums.add(4);
|
||||
print!("Список nums = ");
|
||||
print_util::print_array(&nums.to_array());
|
||||
print!(" , вместимость = {} , длина = {}", nums.capacity(), nums.size());
|
||||
|
||||
/* Вставка элемента в середину */
|
||||
nums.insert(3, 6);
|
||||
print!("\nПосле вставки числа 6 по индексу 3 nums = ");
|
||||
print_util::print_array(&nums.to_array());
|
||||
|
||||
/* Удаление элемента */
|
||||
nums.remove(3);
|
||||
print!("\nПосле удаления элемента по индексу 3 nums = ");
|
||||
print_util::print_array(&nums.to_array());
|
||||
|
||||
/* Доступ к элементу */
|
||||
let num = nums.get(1);
|
||||
println!("\nЭлемент по индексу 1: num = {num}");
|
||||
|
||||
/* Обновление элемента */
|
||||
nums.set(1, 0);
|
||||
print!("После обновления элемента по индексу 1 до 0 nums = ");
|
||||
print_util::print_array(&nums.to_array());
|
||||
|
||||
/* Проверка механизма расширения */
|
||||
for i in 0..10 {
|
||||
// При i = 5 длина списка превысит его вместимость, и в этот момент сработает механизм расширения
|
||||
nums.add(i);
|
||||
}
|
||||
print!("\nСписок nums после увеличения вместимости = ");
|
||||
print_util::print_array(&nums.to_array());
|
||||
print!(" , вместимость = {} , длина = {}", nums.capacity(), nums.size());
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* File: n_queens.rs
|
||||
* Created Time: 2023-07-15
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Алгоритм бэктрекинга: n ферзей */
|
||||
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],
|
||||
) {
|
||||
// Когда все строки уже обработаны, записать решение
|
||||
if row == n {
|
||||
res.push(state.clone());
|
||||
return;
|
||||
}
|
||||
// Обойти все столбцы
|
||||
for col in 0..n {
|
||||
// Вычислить главную и побочную диагонали, соответствующие этой клетке
|
||||
let diag1 = row + n - 1 - col;
|
||||
let diag2 = row + col;
|
||||
// Отсечение: в столбце, главной диагонали и побочной диагонали этой клетки не должно быть ферзей
|
||||
if !cols[col] && !diags1[diag1] && !diags2[diag2] {
|
||||
// Попытка: поставить ферзя в эту клетку
|
||||
state[row][col] = "Q".into();
|
||||
(cols[col], diags1[diag1], diags2[diag2]) = (true, true, true);
|
||||
// Перейти к размещению следующей строки
|
||||
backtrack(row + 1, n, state, res, cols, diags1, diags2);
|
||||
// Откат: восстановить эту клетку как пустую
|
||||
state[row][col] = "#".into();
|
||||
(cols[col], diags1[diag1], diags2[diag2]) = (false, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Решить задачу о n ферзях */
|
||||
fn n_queens(n: usize) -> Vec<Vec<Vec<String>>> {
|
||||
// Инициализировать доску размера n*n, где 'Q' обозначает ферзя, а '#' — пустую клетку
|
||||
let mut state: Vec<Vec<String>> = vec![vec!["#".to_string(); n]; n];
|
||||
let mut cols = vec![false; n]; // Отмечать, есть ли ферзь в столбце
|
||||
let mut diags1 = vec![false; 2 * n - 1]; // Отмечать наличие ферзя на главной диагонали
|
||||
let mut diags2 = vec![false; 2 * n - 1]; // Отмечать наличие ферзя на побочной диагонали
|
||||
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!("Размер входной доски = {n}");
|
||||
println!("Количество способов расстановки ферзей: {}", 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)
|
||||
*/
|
||||
|
||||
/* Алгоритм бэктрекинга: все перестановки I */
|
||||
fn backtrack(mut state: Vec<i32>, choices: &[i32], selected: &mut [bool], res: &mut Vec<Vec<i32>>) {
|
||||
// Когда длина состояния равна числу элементов, записать решение
|
||||
if state.len() == choices.len() {
|
||||
res.push(state);
|
||||
return;
|
||||
}
|
||||
// Перебор всех вариантов выбора
|
||||
for i in 0..choices.len() {
|
||||
let choice = choices[i];
|
||||
// Отсечение: нельзя выбирать один и тот же элемент повторно
|
||||
if !selected[i] {
|
||||
// Попытка: сделать выбор и обновить состояние
|
||||
selected[i] = true;
|
||||
state.push(choice);
|
||||
// Перейти к следующему выбору
|
||||
backtrack(state.clone(), choices, selected, res);
|
||||
// Откат: отменить выбор и восстановить предыдущее состояние
|
||||
selected[i] = false;
|
||||
state.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Все перестановки I */
|
||||
fn permutations_i(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, 3];
|
||||
|
||||
let res = permutations_i(&mut nums);
|
||||
|
||||
println!("Входной массив nums = {:?}", &nums);
|
||||
println!("Все перестановки res = {:?}", &res);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* File: permutations_ii.rs
|
||||
* Created Time: 2023-07-15
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
/* Алгоритм бэктрекинга: все перестановки II */
|
||||
fn backtrack(mut state: Vec<i32>, choices: &[i32], selected: &mut [bool], res: &mut Vec<Vec<i32>>) {
|
||||
// Когда длина состояния равна числу элементов, записать решение
|
||||
if state.len() == choices.len() {
|
||||
res.push(state);
|
||||
return;
|
||||
}
|
||||
// Перебор всех вариантов выбора
|
||||
let mut duplicated = HashSet::<i32>::new();
|
||||
for i in 0..choices.len() {
|
||||
let choice = choices[i];
|
||||
// Отсечение: нельзя выбирать один и тот же элемент повторно и нельзя повторно выбирать равные элементы
|
||||
if !selected[i] && !duplicated.contains(&choice) {
|
||||
// Попытка: сделать выбор и обновить состояние
|
||||
duplicated.insert(choice); // Записать значения уже выбранных элементов
|
||||
selected[i] = true;
|
||||
state.push(choice);
|
||||
// Перейти к следующему выбору
|
||||
backtrack(state.clone(), choices, selected, res);
|
||||
// Откат: отменить выбор и восстановить предыдущее состояние
|
||||
selected[i] = false;
|
||||
state.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Все перестановки 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!("Входной массив nums = {:?}", &nums);
|
||||
println!("Все перестановки 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};
|
||||
|
||||
/* Предварительный обход: пример 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 {
|
||||
// Записать решение
|
||||
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!("Инициализация двоичного дерева");
|
||||
print_util::print_tree(root.as_ref().unwrap());
|
||||
|
||||
// Предварительный обход
|
||||
let mut res = Vec::new();
|
||||
pre_order(&mut res, root.as_ref());
|
||||
|
||||
println!("\nВсе узлы со значением 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};
|
||||
|
||||
/* Предварительный обход: пример 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 {
|
||||
// Попытка
|
||||
path.push(node.clone());
|
||||
if node.borrow().val == 7 {
|
||||
// Записать решение
|
||||
res.push(path.clone());
|
||||
}
|
||||
pre_order(res, path, node.borrow().left.as_ref());
|
||||
pre_order(res, path, node.borrow().right.as_ref());
|
||||
// Откат
|
||||
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!("Инициализация двоичного дерева");
|
||||
print_util::print_tree(root.as_ref().unwrap());
|
||||
|
||||
// Предварительный обход
|
||||
let mut path = Vec::new();
|
||||
let mut res = Vec::new();
|
||||
pre_order(&mut res, &mut path, root.as_ref());
|
||||
|
||||
println!("\nВсе пути от корня к узлу 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};
|
||||
|
||||
/* Предварительный обход: пример 3 */
|
||||
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() || root.as_ref().unwrap().borrow().val == 3 {
|
||||
return;
|
||||
}
|
||||
if let Some(node) = root {
|
||||
// Попытка
|
||||
path.push(node.clone());
|
||||
if node.borrow().val == 7 {
|
||||
// Записать решение
|
||||
res.push(path.clone());
|
||||
}
|
||||
pre_order(res, path, node.borrow().left.as_ref());
|
||||
pre_order(res, path, node.borrow().right.as_ref());
|
||||
// Откат
|
||||
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!("Инициализация двоичного дерева");
|
||||
print_util::print_tree(root.as_ref().unwrap());
|
||||
|
||||
// Предварительный обход
|
||||
let mut path = Vec::new();
|
||||
let mut res = Vec::new();
|
||||
pre_order(&mut res, &mut path, root.as_ref());
|
||||
|
||||
println!("\nВсе пути от корня к узлу 7, не содержащие узлов со значением 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};
|
||||
|
||||
/* Проверить, является ли текущее состояние решением */
|
||||
fn is_solution(state: &mut Vec<Rc<RefCell<TreeNode>>>) -> bool {
|
||||
return !state.is_empty() && state.last().unwrap().borrow().val == 7;
|
||||
}
|
||||
|
||||
/* Записать решение */
|
||||
fn record_solution(
|
||||
state: &mut Vec<Rc<RefCell<TreeNode>>>,
|
||||
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
|
||||
) {
|
||||
res.push(state.clone());
|
||||
}
|
||||
|
||||
/* Проверить, допустим ли этот выбор в текущем состоянии */
|
||||
fn is_valid(_: &mut Vec<Rc<RefCell<TreeNode>>>, choice: Option<&Rc<RefCell<TreeNode>>>) -> bool {
|
||||
return choice.is_some() && choice.unwrap().borrow().val != 3;
|
||||
}
|
||||
|
||||
/* Обновить состояние */
|
||||
fn make_choice(state: &mut Vec<Rc<RefCell<TreeNode>>>, choice: Rc<RefCell<TreeNode>>) {
|
||||
state.push(choice);
|
||||
}
|
||||
|
||||
/* Восстановить состояние */
|
||||
fn undo_choice(state: &mut Vec<Rc<RefCell<TreeNode>>>, _: Rc<RefCell<TreeNode>>) {
|
||||
state.pop();
|
||||
}
|
||||
|
||||
/* Алгоритм бэктрекинга: пример 3 */
|
||||
fn backtrack(
|
||||
state: &mut Vec<Rc<RefCell<TreeNode>>>,
|
||||
choices: &Vec<Option<&Rc<RefCell<TreeNode>>>>,
|
||||
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
|
||||
) {
|
||||
// Проверить, является ли текущее состояние решением
|
||||
if is_solution(state) {
|
||||
// Записать решение
|
||||
record_solution(state, res);
|
||||
}
|
||||
// Перебор всех вариантов выбора
|
||||
for &choice in choices.iter() {
|
||||
// Отсечение: проверить допустимость выбора
|
||||
if is_valid(state, choice) {
|
||||
// Попытка: сделать выбор и обновить состояние
|
||||
make_choice(state, choice.unwrap().clone());
|
||||
// Перейти к следующему выбору
|
||||
backtrack(
|
||||
state,
|
||||
&vec![
|
||||
choice.unwrap().borrow().left.as_ref(),
|
||||
choice.unwrap().borrow().right.as_ref(),
|
||||
],
|
||||
res,
|
||||
);
|
||||
// Откат: отменить выбор и восстановить предыдущее состояние
|
||||
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!("Инициализация двоичного дерева");
|
||||
print_util::print_tree(root.as_ref().unwrap());
|
||||
|
||||
// Алгоритм бэктрекинга
|
||||
let mut res = Vec::new();
|
||||
backtrack(&mut Vec::new(), &mut vec![root.as_ref()], &mut res);
|
||||
|
||||
println!("\nВсе пути от корня к узлу 7, в которых путь не содержит узлов со значением 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)
|
||||
*/
|
||||
|
||||
/* Алгоритм бэктрекинга: сумма подмножеств I */
|
||||
fn backtrack(
|
||||
state: &mut Vec<i32>,
|
||||
target: i32,
|
||||
choices: &[i32],
|
||||
start: usize,
|
||||
res: &mut Vec<Vec<i32>>,
|
||||
) {
|
||||
// Если сумма подмножества равна target, записать решение
|
||||
if target == 0 {
|
||||
res.push(state.clone());
|
||||
return;
|
||||
}
|
||||
// Обойти все варианты выбора
|
||||
// Отсечение 2: начинать обход с start, чтобы избежать генерации повторяющихся подмножеств
|
||||
for i in start..choices.len() {
|
||||
// Отсечение 1: если сумма подмножества превышает target, немедленно завершить цикл
|
||||
// Это связано с тем, что массив уже отсортирован, следующие элементы больше, и сумма подмножества точно превысит target
|
||||
if target - choices[i] < 0 {
|
||||
break;
|
||||
}
|
||||
// Попытка: сделать выбор и обновить target и start
|
||||
state.push(choices[i]);
|
||||
// Перейти к следующему выбору
|
||||
backtrack(state, target - choices[i], choices, i, res);
|
||||
// Откат: отменить выбор и восстановить предыдущее состояние
|
||||
state.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/* Решить задачу суммы подмножеств I */
|
||||
fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec<Vec<i32>> {
|
||||
let mut state = Vec::new(); // Состояние (подмножество)
|
||||
nums.sort(); // Отсортировать nums
|
||||
let start = 0; // Стартовая вершина обхода
|
||||
let mut res = Vec::new(); // Список результатов (список подмножеств)
|
||||
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!("Входной массив nums = {:?}, target = {}", &nums, target);
|
||||
println!("Все подмножества с суммой {}: res = {:?}", target, &res);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* File: subset_sum_i_naive.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Алгоритм бэктрекинга: сумма подмножеств I */
|
||||
fn backtrack(
|
||||
state: &mut Vec<i32>,
|
||||
target: i32,
|
||||
total: i32,
|
||||
choices: &[i32],
|
||||
res: &mut Vec<Vec<i32>>,
|
||||
) {
|
||||
// Если сумма подмножества равна target, записать решение
|
||||
if total == target {
|
||||
res.push(state.clone());
|
||||
return;
|
||||
}
|
||||
// Перебор всех вариантов выбора
|
||||
for i in 0..choices.len() {
|
||||
// Отсечение: если сумма подмножества превышает target, пропустить этот выбор
|
||||
if total + choices[i] > target {
|
||||
continue;
|
||||
}
|
||||
// Попытка: сделать выбор и обновить элемент и total
|
||||
state.push(choices[i]);
|
||||
// Перейти к следующему выбору
|
||||
backtrack(state, target, total + choices[i], choices, res);
|
||||
// Откат: отменить выбор и восстановить предыдущее состояние
|
||||
state.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/* Решить задачу суммы подмножеств I (с повторяющимися подмножествами) */
|
||||
fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec<Vec<i32>> {
|
||||
let mut state = Vec::new(); // Состояние (подмножество)
|
||||
let total = 0; // Сумма подмножеств
|
||||
let mut res = Vec::new(); // Список результатов (список подмножеств)
|
||||
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!("Входной массив nums = {:?}, target = {}", &nums, target);
|
||||
println!("Все подмножества с суммой {}: res = {:?}", target, &res);
|
||||
println!("Обратите внимание: результат этого метода содержит повторяющиеся множества");
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* File: subset_sum_ii.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Алгоритм бэктрекинга: сумма подмножеств II */
|
||||
fn backtrack(
|
||||
state: &mut Vec<i32>,
|
||||
target: i32,
|
||||
choices: &[i32],
|
||||
start: usize,
|
||||
res: &mut Vec<Vec<i32>>,
|
||||
) {
|
||||
// Если сумма подмножества равна target, записать решение
|
||||
if target == 0 {
|
||||
res.push(state.clone());
|
||||
return;
|
||||
}
|
||||
// Обойти все варианты выбора
|
||||
// Отсечение 2: начинать обход с start, чтобы избежать генерации повторяющихся подмножеств
|
||||
// Отсечение 3: начинать обход с start, чтобы избежать повторного выбора одного и того же элемента
|
||||
for i in start..choices.len() {
|
||||
// Отсечение 1: если сумма подмножества превышает target, немедленно завершить цикл
|
||||
// Это связано с тем, что массив уже отсортирован, следующие элементы больше, и сумма подмножества точно превысит target
|
||||
if target - choices[i] < 0 {
|
||||
break;
|
||||
}
|
||||
// Отсечение 4: если этот элемент равен элементу слева, значит ветвь поиска повторяется, ее нужно сразу пропустить
|
||||
if i > start && choices[i] == choices[i - 1] {
|
||||
continue;
|
||||
}
|
||||
// Попытка: сделать выбор и обновить target и start
|
||||
state.push(choices[i]);
|
||||
// Перейти к следующему выбору
|
||||
backtrack(state, target - choices[i], choices, i + 1, res);
|
||||
// Откат: отменить выбор и восстановить предыдущее состояние
|
||||
state.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/* Решить задачу суммы подмножеств II */
|
||||
fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec<Vec<i32>> {
|
||||
let mut state = Vec::new(); // Состояние (подмножество)
|
||||
nums.sort(); // Отсортировать nums
|
||||
let start = 0; // Стартовая вершина обхода
|
||||
let mut res = Vec::new(); // Список результатов (список подмножеств)
|
||||
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!("Входной массив nums = {:?}, target = {}", &nums, target);
|
||||
println!("Все подмножества с суммой {}: res = {:?}", target, &res);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* File: iteration.rs
|
||||
* Created Time: 2023-09-02
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
|
||||
/* Цикл for */
|
||||
fn for_loop(n: i32) -> i32 {
|
||||
let mut res = 0;
|
||||
// Циклическое суммирование 1, 2, ..., n-1, n
|
||||
for i in 1..=n {
|
||||
res += i;
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/* Цикл while */
|
||||
fn while_loop(n: i32) -> i32 {
|
||||
let mut res = 0;
|
||||
let mut i = 1; // Инициализация условной переменной
|
||||
|
||||
// Циклическое суммирование 1, 2, ..., n-1, n
|
||||
while i <= n {
|
||||
res += i;
|
||||
i += 1; // Обновить условную переменную
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/* Цикл while (двойное обновление) */
|
||||
fn while_loop_ii(n: i32) -> i32 {
|
||||
let mut res = 0;
|
||||
let mut i = 1; // Инициализация условной переменной
|
||||
|
||||
// Циклическое суммирование 1, 4, 10, ...
|
||||
while i <= n {
|
||||
res += i;
|
||||
// Обновить условную переменную
|
||||
i += 1;
|
||||
i *= 2;
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/* Двойной цикл for */
|
||||
fn nested_for_loop(n: i32) -> String {
|
||||
let mut res = vec![];
|
||||
// Цикл по i = 1, 2, ..., n-1, n
|
||||
for i in 1..=n {
|
||||
// Цикл по 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!("\nРезультат суммирования в цикле for res = {res}");
|
||||
|
||||
res = while_loop(n);
|
||||
println!("\nРезультат суммирования в цикле while res = {res}");
|
||||
|
||||
res = while_loop_ii(n);
|
||||
println!("\nРезультат суммирования в цикле while (двойное обновление) res = {}", res);
|
||||
|
||||
let res = nested_for_loop(n);
|
||||
println!("\nРезультат обхода в двойном цикле for {res}");
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* File: recursion.rs
|
||||
* Created Time: 2023-09-02
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
|
||||
/* Рекурсия */
|
||||
fn recur(n: i32) -> i32 {
|
||||
// Условие завершения
|
||||
if n == 1 {
|
||||
return 1;
|
||||
}
|
||||
// Рекурсия: рекурсивный вызов
|
||||
let res = recur(n - 1);
|
||||
// Возврат: вернуть результат
|
||||
n + res
|
||||
}
|
||||
|
||||
/* Имитация рекурсии итерацией */
|
||||
fn for_loop_recur(n: i32) -> i32 {
|
||||
// Использовать явный стек для имитации системного стека вызовов
|
||||
let mut stack = Vec::new();
|
||||
let mut res = 0;
|
||||
// Рекурсия: рекурсивный вызов
|
||||
for i in (1..=n).rev() {
|
||||
// Имитировать «рекурсию» с помощью операции помещения в стек
|
||||
stack.push(i);
|
||||
}
|
||||
// Возврат: вернуть результат
|
||||
while !stack.is_empty() {
|
||||
// Имитировать «возврат» с помощью операции извлечения из стека
|
||||
res += stack.pop().unwrap();
|
||||
}
|
||||
// res = 1+2+3+...+n
|
||||
res
|
||||
}
|
||||
|
||||
/* Хвостовая рекурсия */
|
||||
fn tail_recur(n: i32, res: i32) -> i32 {
|
||||
// Условие завершения
|
||||
if n == 0 {
|
||||
return res;
|
||||
}
|
||||
// Хвостовой рекурсивный вызов
|
||||
tail_recur(n - 1, res + n)
|
||||
}
|
||||
|
||||
/* Последовательность Фибоначчи: рекурсия */
|
||||
fn fib(n: i32) -> i32 {
|
||||
// Условие завершения: f(1) = 0, f(2) = 1
|
||||
if n == 1 || n == 2 {
|
||||
return n - 1;
|
||||
}
|
||||
// Рекурсивный вызов f(n) = f(n-1) + f(n-2)
|
||||
let res = fib(n - 1) + fib(n - 2);
|
||||
// Вернуть результат
|
||||
res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
let n = 5;
|
||||
let mut res;
|
||||
|
||||
res = recur(n);
|
||||
println!("\nРезультат суммирования в рекурсивной функции res = {res}");
|
||||
|
||||
res = for_loop_recur(n);
|
||||
println!("\nРезультат суммирования при имитации рекурсии res = {res}");
|
||||
|
||||
res = tail_recur(n, 0);
|
||||
println!("\nРезультат суммирования в хвостовой рекурсии res = {res}");
|
||||
|
||||
res = fib(n);
|
||||
println!("\nЧлен последовательности Фибоначчи с номером {n} = {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;
|
||||
|
||||
/* Функция */
|
||||
fn function() -> i32 {
|
||||
// Выполнить некоторые операции
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Постоянная сложность */
|
||||
#[allow(unused)]
|
||||
fn constant(n: i32) {
|
||||
// Константы, переменные и объекты занимают O(1) памяти
|
||||
const A: i32 = 0;
|
||||
let b = 0;
|
||||
let nums = vec![0; 10000];
|
||||
let node = ListNode::new(0);
|
||||
// Переменные в цикле занимают O(1) памяти
|
||||
for i in 0..n {
|
||||
let c = 0;
|
||||
}
|
||||
// Функции в цикле занимают O(1) памяти
|
||||
for i in 0..n {
|
||||
function();
|
||||
}
|
||||
}
|
||||
|
||||
/* Линейная сложность */
|
||||
#[allow(unused)]
|
||||
fn linear(n: i32) {
|
||||
// Массив длины n занимает O(n) памяти
|
||||
let mut nums = vec![0; n as usize];
|
||||
// Список длины n занимает O(n) памяти
|
||||
let mut nodes = Vec::new();
|
||||
for i in 0..n {
|
||||
nodes.push(ListNode::new(i))
|
||||
}
|
||||
// Хеш-таблица длины n занимает O(n) памяти
|
||||
let mut map = HashMap::new();
|
||||
for i in 0..n {
|
||||
map.insert(i, i.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
/* Линейная сложность (рекурсивная реализация) */
|
||||
fn linear_recur(n: i32) {
|
||||
println!("Рекурсия n = {}", n);
|
||||
if n == 1 {
|
||||
return;
|
||||
};
|
||||
linear_recur(n - 1);
|
||||
}
|
||||
|
||||
/* Квадратичная сложность */
|
||||
#[allow(unused)]
|
||||
fn quadratic(n: i32) {
|
||||
// Матрица занимает O(n^2) памяти
|
||||
let num_matrix = vec![vec![0; n as usize]; n as usize];
|
||||
// Двумерный список занимает O(n^2) памяти
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Квадратичная сложность (рекурсивная реализация) */
|
||||
fn quadratic_recur(n: i32) -> i32 {
|
||||
if n <= 0 {
|
||||
return 0;
|
||||
};
|
||||
// Длина массива nums равна n, n-1, ..., 2, 1
|
||||
let nums = vec![0; n as usize];
|
||||
println!("В рекурсии n = {} , длина nums = {}", n, nums.len());
|
||||
return quadratic_recur(n - 1);
|
||||
}
|
||||
|
||||
/* Экспоненциальная сложность (построение полного двоичного дерева) */
|
||||
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(n);
|
||||
// Линейная сложность
|
||||
linear(n);
|
||||
linear_recur(n);
|
||||
// Квадратичная сложность
|
||||
quadratic(n);
|
||||
quadratic_recur(n);
|
||||
// Экспоненциальная сложность
|
||||
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)
|
||||
*/
|
||||
|
||||
/* Постоянная сложность */
|
||||
fn constant(n: i32) -> i32 {
|
||||
_ = n;
|
||||
let mut count = 0;
|
||||
let size = 100_000;
|
||||
for _ in 0..size {
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/* Линейная сложность */
|
||||
fn linear(n: i32) -> i32 {
|
||||
let mut count = 0;
|
||||
for _ in 0..n {
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/* Линейная сложность (обход массива) */
|
||||
fn array_traversal(nums: &[i32]) -> i32 {
|
||||
let mut count = 0;
|
||||
// Число итераций пропорционально длине массива
|
||||
for _ in nums {
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/* Квадратичная сложность */
|
||||
fn quadratic(n: i32) -> i32 {
|
||||
let mut count = 0;
|
||||
// Число итераций квадратично зависит от размера данных n
|
||||
for _ in 0..n {
|
||||
for _ in 0..n {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/* Квадратичная сложность (пузырьковая сортировка) */
|
||||
fn bubble_sort(nums: &mut [i32]) -> i32 {
|
||||
let mut count = 0; // Счетчик
|
||||
|
||||
// Внешний цикл: неотсортированный диапазон [0, i]
|
||||
for i in (1..nums.len()).rev() {
|
||||
// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конец
|
||||
for j in 0..i {
|
||||
if nums[j] > nums[j + 1] {
|
||||
// Поменять местами nums[j] и nums[j + 1]
|
||||
let tmp = nums[j];
|
||||
nums[j] = nums[j + 1];
|
||||
nums[j + 1] = tmp;
|
||||
count += 3; // Обмен элементов включает 3 элементарные операции
|
||||
}
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/* Экспоненциальная сложность (итеративная реализация) */
|
||||
fn exponential(n: i32) -> i32 {
|
||||
let mut count = 0;
|
||||
let mut base = 1;
|
||||
// На каждом шаге клетка делится надвое, образуя последовательность 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
|
||||
}
|
||||
|
||||
/* Экспоненциальная сложность (рекурсивная реализация) */
|
||||
fn exp_recur(n: i32) -> i32 {
|
||||
if n == 1 {
|
||||
return 1;
|
||||
}
|
||||
exp_recur(n - 1) + exp_recur(n - 1) + 1
|
||||
}
|
||||
|
||||
/* Логарифмическая сложность (итеративная реализация) */
|
||||
fn logarithmic(mut n: i32) -> i32 {
|
||||
let mut count = 0;
|
||||
while n > 1 {
|
||||
n = n / 2;
|
||||
count += 1;
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/* Логарифмическая сложность (рекурсивная реализация) */
|
||||
fn log_recur(n: i32) -> i32 {
|
||||
if n <= 1 {
|
||||
return 0;
|
||||
}
|
||||
log_recur(n / 2) + 1
|
||||
}
|
||||
|
||||
/* Линейно-логарифмическая сложность */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Факториальная сложность (рекурсивная реализация) */
|
||||
fn factorial_recur(n: i32) -> i32 {
|
||||
if n == 0 {
|
||||
return 1;
|
||||
}
|
||||
let mut count = 0;
|
||||
// Из одного получается n
|
||||
for _ in 0..n {
|
||||
count += factorial_recur(n - 1);
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
// Можно изменить n и запустить программу, чтобы увидеть, как меняется число операций при разных сложностях
|
||||
let n: i32 = 8;
|
||||
println!("Размер входных данных n = {}", n);
|
||||
|
||||
let mut count = constant(n);
|
||||
println!("Число операций константной сложности = {}", count);
|
||||
|
||||
count = linear(n);
|
||||
println!("Число операций линейной сложности = {}", count);
|
||||
count = array_traversal(&vec![0; n as usize]);
|
||||
println!("Число операций линейной сложности (обход массива) = {}", count);
|
||||
|
||||
count = quadratic(n);
|
||||
println!("Число операций квадратичной сложности = {}", count);
|
||||
let mut nums = (1..=n).rev().collect::<Vec<_>>(); // [n,n-1,...,2,1]
|
||||
count = bubble_sort(&mut nums);
|
||||
println!("Число операций квадратичной сложности (пузырьковая сортировка) = {}", count);
|
||||
|
||||
count = exponential(n);
|
||||
println!("Число операций экспоненциальной сложности (итеративная реализация) = {}", count);
|
||||
count = exp_recur(n);
|
||||
println!("Число операций экспоненциальной сложности (рекурсивная реализация) = {}", count);
|
||||
|
||||
count = logarithmic(n);
|
||||
println!("Число операций логарифмической сложности (итеративная реализация) = {}", count);
|
||||
count = log_recur(n);
|
||||
println!("Число операций логарифмической сложности (рекурсивная реализация) = {}", count);
|
||||
|
||||
count = linear_log_recur(n);
|
||||
println!("Число операций линейно-логарифмической сложности (рекурсивная реализация) = {}", count);
|
||||
|
||||
count = factorial_recur(n);
|
||||
println!("Число операций факториальной сложности (рекурсивная реализация) = {}", 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;
|
||||
|
||||
/* Создать массив с элементами { 1, 2, ..., n } в случайном порядке */
|
||||
fn random_numbers(n: i32) -> Vec<i32> {
|
||||
// Создать массив nums = { 1, 2, 3, ..., n }
|
||||
let mut nums = (1..=n).collect::<Vec<i32>>();
|
||||
// Случайно перемешать элементы массива
|
||||
nums.shuffle(&mut thread_rng());
|
||||
nums
|
||||
}
|
||||
|
||||
/* Найти индекс числа 1 в массиве nums */
|
||||
fn find_one(nums: &[i32]) -> Option<usize> {
|
||||
for i in 0..nums.len() {
|
||||
// Когда элемент 1 находится в начале массива, достигается лучшая временная сложность O(1)
|
||||
// Когда элемент 1 находится в конце массива, достигается худшая временная сложность O(n)
|
||||
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!("\nМассив [1, 2, ..., n] после перемешивания = ");
|
||||
print_util::print_array(&nums);
|
||||
println!("\nИндекс числа 1 = {}", index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* File: binary_search_recur.rs
|
||||
* Created Time: 2023-07-15
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Бинарный поиск: задача f(i, j) */
|
||||
fn dfs(nums: &[i32], target: i32, i: i32, j: i32) -> i32 {
|
||||
// Если интервал пуст, целевой элемент отсутствует, вернуть -1
|
||||
if i > j {
|
||||
return -1;
|
||||
}
|
||||
let m: i32 = i + (j - i) / 2;
|
||||
if nums[m as usize] < target {
|
||||
// Рекурсивная подзадача f(m+1, j)
|
||||
return dfs(nums, target, m + 1, j);
|
||||
} else if nums[m as usize] > target {
|
||||
// Рекурсивная подзадача f(i, m-1)
|
||||
return dfs(nums, target, i, m - 1);
|
||||
} else {
|
||||
// Целевой элемент найден, вернуть его индекс
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
/* Бинарный поиск */
|
||||
fn binary_search(nums: &[i32], target: i32) -> i32 {
|
||||
let n = nums.len() as i32;
|
||||
// Решить задачу 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];
|
||||
|
||||
// Бинарный поиск (двусторонне замкнутый интервал)
|
||||
let index = binary_search(&nums, target);
|
||||
println!("Индекс целевого элемента 6 = {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};
|
||||
|
||||
/* Построить двоичное дерево: разделяй и властвуй */
|
||||
fn dfs(
|
||||
preorder: &[i32],
|
||||
inorder_map: &HashMap<i32, i32>,
|
||||
i: i32,
|
||||
l: i32,
|
||||
r: i32,
|
||||
) -> Option<Rc<RefCell<TreeNode>>> {
|
||||
// Завершить при пустом диапазоне поддерева
|
||||
if r - l < 0 {
|
||||
return None;
|
||||
}
|
||||
// Инициализировать корневой узел
|
||||
let root = TreeNode::new(preorder[i as usize]);
|
||||
// Найти m, чтобы разделить левое и правое поддеревья
|
||||
let m = inorder_map.get(&preorder[i as usize]).unwrap();
|
||||
// Подзадача: построить левое поддерево
|
||||
root.borrow_mut().left = dfs(preorder, inorder_map, i + 1, l, m - 1);
|
||||
// Подзадача: построить правое поддерево
|
||||
root.borrow_mut().right = dfs(preorder, inorder_map, i + 1 + m - l, m + 1, r);
|
||||
// Вернуть корневой узел
|
||||
Some(root)
|
||||
}
|
||||
|
||||
/* Построить двоичное дерево */
|
||||
fn build_tree(preorder: &[i32], inorder: &[i32]) -> Option<Rc<RefCell<TreeNode>>> {
|
||||
// Инициализировать хеш-таблицу для хранения соответствия элементов inorder их индексам
|
||||
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!("Предварительный обход = {:?}", preorder);
|
||||
println!("Симметричный обход = {:?}", inorder);
|
||||
|
||||
let root = build_tree(&preorder, &inorder);
|
||||
println!("Построенное двоичное дерево:");
|
||||
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)]
|
||||
|
||||
/* Переместить один диск */
|
||||
fn move_pan(src: &mut Vec<i32>, tar: &mut Vec<i32>) {
|
||||
// Снять диск с вершины src
|
||||
let pan = src.pop().unwrap();
|
||||
// Положить диск на вершину tar
|
||||
tar.push(pan);
|
||||
}
|
||||
|
||||
/* Решить задачу Ханойской башни f(i) */
|
||||
fn dfs(i: i32, src: &mut Vec<i32>, buf: &mut Vec<i32>, tar: &mut Vec<i32>) {
|
||||
// Если в src остался только один диск, сразу переместить его в tar
|
||||
if i == 1 {
|
||||
move_pan(src, tar);
|
||||
return;
|
||||
}
|
||||
// Подзадача f(i-1): переместить верхние i-1 дисков из src в buf с помощью tar
|
||||
dfs(i - 1, src, tar, buf);
|
||||
// Подзадача f(1): переместить оставшийся один диск из src в tar
|
||||
move_pan(src, tar);
|
||||
// Подзадача f(i-1): переместить верхние i-1 дисков из buf в tar с помощью src
|
||||
dfs(i - 1, buf, src, tar);
|
||||
}
|
||||
|
||||
/* Решить задачу Ханойской башни */
|
||||
fn solve_hanota(A: &mut Vec<i32>, B: &mut Vec<i32>, C: &mut Vec<i32>) {
|
||||
let n = A.len() as i32;
|
||||
// Переместить верхние n дисков из A в C с помощью 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!("Исходное состояние:");
|
||||
println!("A = {:?}", A);
|
||||
println!("B = {:?}", B);
|
||||
println!("C = {:?}", C);
|
||||
|
||||
solve_hanota(&mut A, &mut B, &mut C);
|
||||
|
||||
println!("После завершения перемещения дисков:");
|
||||
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)
|
||||
*/
|
||||
|
||||
/* Бэктрекинг */
|
||||
fn backtrack(choices: &[i32], state: i32, n: i32, res: &mut [i32]) {
|
||||
// Когда подъем достигает n-й ступени, число вариантов увеличивается на 1
|
||||
if state == n {
|
||||
res[0] = res[0] + 1;
|
||||
}
|
||||
// Перебор всех вариантов выбора
|
||||
for &choice in choices {
|
||||
// Отсечение: нельзя выходить за n-ю ступень
|
||||
if state + choice > n {
|
||||
continue;
|
||||
}
|
||||
// Попытка: сделать выбор и обновить состояние
|
||||
backtrack(choices, state + choice, n, res);
|
||||
// Откат
|
||||
}
|
||||
}
|
||||
|
||||
/* Подъем по лестнице: бэктрекинг */
|
||||
fn climbing_stairs_backtrack(n: usize) -> i32 {
|
||||
let choices = vec![1, 2]; // Можно подняться на 1 или 2 ступени
|
||||
let state = 0; // Начать подъем с 0-й ступени
|
||||
let mut res = Vec::new();
|
||||
res.push(0); // Использовать res[0] для хранения числа решений
|
||||
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!("Количество способов подняться по лестнице из {n} ступеней = {res}");
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* File: climbing_stairs_constraint_dp.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Подъем по лестнице с ограничениями: динамическое программирование */
|
||||
fn climbing_stairs_constraint_dp(n: usize) -> i32 {
|
||||
if n == 1 || n == 2 {
|
||||
return 1;
|
||||
};
|
||||
// Инициализация таблицы dp для хранения решений подзадач
|
||||
let mut dp = vec![vec![-1; 3]; n + 1];
|
||||
// Начальное состояние: заранее задать решения наименьших подзадач
|
||||
dp[1][1] = 1;
|
||||
dp[1][2] = 0;
|
||||
dp[2][1] = 0;
|
||||
dp[2][2] = 1;
|
||||
// Переход состояний: постепенное решение больших подзадач через меньшие
|
||||
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!("Количество способов подняться по лестнице из {n} ступеней = {res}");
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* File: climbing_stairs_dfs.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Поиск */
|
||||
fn dfs(i: usize) -> i32 {
|
||||
// dp[1] и dp[2] уже известны, вернуть их
|
||||
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
|
||||
}
|
||||
|
||||
/* Подъем по лестнице: поиск */
|
||||
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!("Количество способов подняться по лестнице из {n} ступеней = {res}");
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* File: climbing_stairs_dfs_mem.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Поиск с мемоизацией */
|
||||
fn dfs(i: usize, mem: &mut [i32]) -> i32 {
|
||||
// dp[1] и dp[2] уже известны, вернуть их
|
||||
if i == 1 || i == 2 {
|
||||
return i as i32;
|
||||
}
|
||||
// Если запись dp[i] существует, сразу вернуть ее
|
||||
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);
|
||||
// Сохранить dp[i]
|
||||
mem[i] = count;
|
||||
count
|
||||
}
|
||||
|
||||
/* Подъем по лестнице: поиск с мемоизацией */
|
||||
fn climbing_stairs_dfs_mem(n: usize) -> i32 {
|
||||
// mem[i] хранит число способов подняться на i-ю ступень, -1 означает отсутствие записи
|
||||
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!("Количество способов подняться по лестнице из {n} ступеней = {res}");
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* File: climbing_stairs_dp.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Подъем по лестнице: динамическое программирование */
|
||||
fn climbing_stairs_dp(n: usize) -> i32 {
|
||||
// dp[1] и dp[2] уже известны, вернуть их
|
||||
if n == 1 || n == 2 {
|
||||
return n as i32;
|
||||
}
|
||||
// Инициализация таблицы dp для хранения решений подзадач
|
||||
let mut dp = vec![-1; n + 1];
|
||||
// Начальное состояние: заранее задать решения наименьших подзадач
|
||||
dp[1] = 1;
|
||||
dp[2] = 2;
|
||||
// Переход состояний: постепенное решение больших подзадач через меньшие
|
||||
for i in 3..=n {
|
||||
dp[i] = dp[i - 1] + dp[i - 2];
|
||||
}
|
||||
dp[n]
|
||||
}
|
||||
|
||||
/* Подъем по лестнице: динамическое программирование с оптимизацией памяти */
|
||||
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!("Количество способов подняться по лестнице из {n} ступеней = {res}");
|
||||
|
||||
let res = climbing_stairs_dp_comp(n);
|
||||
println!("Количество способов подняться по лестнице из {n} ступеней = {res}");
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* File: coin_change.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Размен монет: динамическое программирование */
|
||||
fn coin_change_dp(coins: &[i32], amt: usize) -> i32 {
|
||||
let n = coins.len();
|
||||
let max = amt + 1;
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![vec![0; amt + 1]; n + 1];
|
||||
// Переход состояний: первая строка и первый столбец
|
||||
for a in 1..=amt {
|
||||
dp[0][a] = max;
|
||||
}
|
||||
// Переход состояний: остальные строки и столбцы
|
||||
for i in 1..=n {
|
||||
for a in 1..=amt {
|
||||
if coins[i - 1] > a as i32 {
|
||||
// Если целевая сумма превышена, монету i не выбирать
|
||||
dp[i][a] = dp[i - 1][a];
|
||||
} else {
|
||||
// Меньшее из двух решений: не брать или взять монету 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
|
||||
}
|
||||
}
|
||||
|
||||
/* Размен монет: динамическое программирование с оптимизацией памяти */
|
||||
fn coin_change_dp_comp(coins: &[i32], amt: usize) -> i32 {
|
||||
let n = coins.len();
|
||||
let max = amt + 1;
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![0; amt + 1];
|
||||
dp.fill(max);
|
||||
dp[0] = 0;
|
||||
// Переход состояний
|
||||
for i in 1..=n {
|
||||
for a in 1..=amt {
|
||||
if coins[i - 1] > a as i32 {
|
||||
// Если целевая сумма превышена, монету i не выбирать
|
||||
dp[a] = dp[a];
|
||||
} else {
|
||||
// Меньшее из двух решений: не брать или взять монету 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;
|
||||
|
||||
// Динамическое программирование
|
||||
let res = coin_change_dp(&coins, amt);
|
||||
println!("Минимальное число монет для набора целевой суммы = {res}");
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
let res = coin_change_dp_comp(&coins, amt);
|
||||
println!("Минимальное число монет для набора целевой суммы = {res}");
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* File: coin_change_ii.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Размен монет II: динамическое программирование */
|
||||
fn coin_change_ii_dp(coins: &[i32], amt: usize) -> i32 {
|
||||
let n = coins.len();
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![vec![0; amt + 1]; n + 1];
|
||||
// Инициализация первого столбца
|
||||
for i in 0..=n {
|
||||
dp[i][0] = 1;
|
||||
}
|
||||
// Переход состояний
|
||||
for i in 1..=n {
|
||||
for a in 1..=amt {
|
||||
if coins[i - 1] > a as i32 {
|
||||
// Если целевая сумма превышена, монету i не выбирать
|
||||
dp[i][a] = dp[i - 1][a];
|
||||
} else {
|
||||
// Сумма двух решений: не брать или взять монету i
|
||||
dp[i][a] = dp[i - 1][a] + dp[i][a - coins[i - 1] as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
dp[n][amt]
|
||||
}
|
||||
|
||||
/* Размен монет II: динамическое программирование с оптимизацией памяти */
|
||||
fn coin_change_ii_dp_comp(coins: &[i32], amt: usize) -> i32 {
|
||||
let n = coins.len();
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![0; amt + 1];
|
||||
dp[0] = 1;
|
||||
// Переход состояний
|
||||
for i in 1..=n {
|
||||
for a in 1..=amt {
|
||||
if coins[i - 1] > a as i32 {
|
||||
// Если целевая сумма превышена, монету i не выбирать
|
||||
dp[a] = dp[a];
|
||||
} else {
|
||||
// Сумма двух решений: не брать или взять монету 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;
|
||||
|
||||
// Динамическое программирование
|
||||
let res = coin_change_ii_dp(&coins, amt);
|
||||
println!("Количество комбинаций монет для набора целевой суммы = {res}");
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
let res = coin_change_ii_dp_comp(&coins, amt);
|
||||
println!("Количество комбинаций монет для набора целевой суммы = {res}");
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* File: edit_distance.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Редакционное расстояние: полный перебор */
|
||||
fn edit_distance_dfs(s: &str, t: &str, i: usize, j: usize) -> i32 {
|
||||
// Если s и t пусты, вернуть 0
|
||||
if i == 0 && j == 0 {
|
||||
return 0;
|
||||
}
|
||||
// Если s пусто, вернуть длину t
|
||||
if i == 0 {
|
||||
return j as i32;
|
||||
}
|
||||
// Если t пусто, вернуть длину s
|
||||
if j == 0 {
|
||||
return i as i32;
|
||||
}
|
||||
// Если два символа равны, сразу пропустить их
|
||||
if s.chars().nth(i - 1) == t.chars().nth(j - 1) {
|
||||
return edit_distance_dfs(s, t, i - 1, j - 1);
|
||||
}
|
||||
// Минимальное число шагов редактирования = минимальное число шагов для вставки, удаления и замены + 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);
|
||||
// Вернуть минимальное число шагов редактирования
|
||||
std::cmp::min(std::cmp::min(insert, delete), replace) + 1
|
||||
}
|
||||
|
||||
/* Редакционное расстояние: поиск с мемоизацией */
|
||||
fn edit_distance_dfs_mem(s: &str, t: &str, mem: &mut Vec<Vec<i32>>, i: usize, j: usize) -> i32 {
|
||||
// Если s и t пусты, вернуть 0
|
||||
if i == 0 && j == 0 {
|
||||
return 0;
|
||||
}
|
||||
// Если s пусто, вернуть длину t
|
||||
if i == 0 {
|
||||
return j as i32;
|
||||
}
|
||||
// Если t пусто, вернуть длину s
|
||||
if j == 0 {
|
||||
return i as i32;
|
||||
}
|
||||
// Если запись уже есть, сразу вернуть ее
|
||||
if mem[i][j] != -1 {
|
||||
return mem[i][j];
|
||||
}
|
||||
// Если два символа равны, сразу пропустить их
|
||||
if s.chars().nth(i - 1) == t.chars().nth(j - 1) {
|
||||
return edit_distance_dfs_mem(s, t, mem, i - 1, j - 1);
|
||||
}
|
||||
// Минимальное число шагов редактирования = минимальное число шагов для вставки, удаления и замены + 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);
|
||||
// Сохранить и вернуть минимальное число шагов редактирования
|
||||
mem[i][j] = std::cmp::min(std::cmp::min(insert, delete), replace) + 1;
|
||||
mem[i][j]
|
||||
}
|
||||
|
||||
/* Редакционное расстояние: динамическое программирование */
|
||||
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];
|
||||
// Переход состояний: первая строка и первый столбец
|
||||
for i in 1..=n {
|
||||
dp[i][0] = i as i32;
|
||||
}
|
||||
for j in 1..m {
|
||||
dp[0][j] = j as i32;
|
||||
}
|
||||
// Переход состояний: остальные строки и столбцы
|
||||
for i in 1..=n {
|
||||
for j in 1..=m {
|
||||
if s.chars().nth(i - 1) == t.chars().nth(j - 1) {
|
||||
// Если два символа равны, сразу пропустить их
|
||||
dp[i][j] = dp[i - 1][j - 1];
|
||||
} else {
|
||||
// Минимальное число шагов редактирования = минимальное число шагов для вставки, удаления и замены + 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]
|
||||
}
|
||||
|
||||
/* Редакционное расстояние: динамическое программирование с оптимизацией памяти */
|
||||
fn edit_distance_dp_comp(s: &str, t: &str) -> i32 {
|
||||
let (n, m) = (s.len(), t.len());
|
||||
let mut dp = vec![0; m + 1];
|
||||
// Переход состояний: первая строка
|
||||
for j in 1..m {
|
||||
dp[j] = j as i32;
|
||||
}
|
||||
// Переход состояний: остальные строки
|
||||
for i in 1..=n {
|
||||
// Переход состояний: первый столбец
|
||||
let mut leftup = dp[0]; // Временно сохранить dp[i-1, j-1]
|
||||
dp[0] = i as i32;
|
||||
// Переход состояний: остальные столбцы
|
||||
for j in 1..=m {
|
||||
let temp = dp[j];
|
||||
if s.chars().nth(i - 1) == t.chars().nth(j - 1) {
|
||||
// Если два символа равны, сразу пропустить их
|
||||
dp[j] = leftup;
|
||||
} else {
|
||||
// Минимальное число шагов редактирования = минимальное число шагов для вставки, удаления и замены + 1
|
||||
dp[j] = std::cmp::min(std::cmp::min(dp[j - 1], dp[j]), leftup) + 1;
|
||||
}
|
||||
leftup = temp; // Обновить до значения 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());
|
||||
|
||||
// Полный перебор
|
||||
let res = edit_distance_dfs(s, t, n, m);
|
||||
println!("Чтобы преобразовать {s} в {t}, нужно минимум {res} шагов");
|
||||
|
||||
// Поиск с запоминанием
|
||||
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!("Чтобы преобразовать {s} в {t}, нужно минимум {res} шагов");
|
||||
|
||||
// Динамическое программирование
|
||||
let res = edit_distance_dp(s, t);
|
||||
println!("Чтобы преобразовать {s} в {t}, нужно минимум {res} шагов");
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
let res = edit_distance_dp_comp(s, t);
|
||||
println!("Чтобы преобразовать {s} в {t}, нужно минимум {res} шагов");
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* File: knapsack.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Рюкзак 0-1: полный перебор */
|
||||
fn knapsack_dfs(wgt: &[i32], val: &[i32], i: usize, c: usize) -> i32 {
|
||||
// Если все предметы уже рассмотрены или в рюкзаке не осталось места, вернуть стоимость 0
|
||||
if i == 0 || c == 0 {
|
||||
return 0;
|
||||
}
|
||||
// Если вместимость рюкзака превышена, можно только не класть предмет в рюкзак
|
||||
if wgt[i - 1] > c as i32 {
|
||||
return knapsack_dfs(wgt, val, i - 1, c);
|
||||
}
|
||||
// Вычислить максимальную стоимость для случаев, когда предмет 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];
|
||||
// Вернуть вариант с большей стоимостью из двух возможных
|
||||
std::cmp::max(no, yes)
|
||||
}
|
||||
|
||||
/* Рюкзак 0-1: поиск с мемоизацией */
|
||||
fn knapsack_dfs_mem(wgt: &[i32], val: &[i32], mem: &mut Vec<Vec<i32>>, i: usize, c: usize) -> i32 {
|
||||
// Если все предметы уже рассмотрены или в рюкзаке не осталось места, вернуть стоимость 0
|
||||
if i == 0 || c == 0 {
|
||||
return 0;
|
||||
}
|
||||
// Если запись уже есть, вернуть сразу
|
||||
if mem[i][c] != -1 {
|
||||
return mem[i][c];
|
||||
}
|
||||
// Если вместимость рюкзака превышена, можно только не класть предмет в рюкзак
|
||||
if wgt[i - 1] > c as i32 {
|
||||
return knapsack_dfs_mem(wgt, val, mem, i - 1, c);
|
||||
}
|
||||
// Вычислить максимальную стоимость для случаев, когда предмет 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];
|
||||
// Сохранить и вернуть вариант с большей стоимостью из двух решений
|
||||
mem[i][c] = std::cmp::max(no, yes);
|
||||
mem[i][c]
|
||||
}
|
||||
|
||||
/* Рюкзак 0-1: динамическое программирование */
|
||||
fn knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 {
|
||||
let n = wgt.len();
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![vec![0; cap + 1]; n + 1];
|
||||
// Переход состояний
|
||||
for i in 1..=n {
|
||||
for c in 1..=cap {
|
||||
if wgt[i - 1] > c as i32 {
|
||||
// Если вместимость рюкзака превышена, предмет i не выбирать
|
||||
dp[i][c] = dp[i - 1][c];
|
||||
} else {
|
||||
// Большее из двух решений: не брать или взять предмет 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: динамическое программирование с оптимизацией памяти */
|
||||
fn knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 {
|
||||
let n = wgt.len();
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![0; cap + 1];
|
||||
// Переход состояний
|
||||
for i in 1..=n {
|
||||
// Обход в обратном порядке
|
||||
for c in (1..=cap).rev() {
|
||||
if wgt[i - 1] <= c as i32 {
|
||||
// Большее из двух решений: не брать или взять предмет 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();
|
||||
|
||||
// Полный перебор
|
||||
let res = knapsack_dfs(&wgt, &val, n, cap);
|
||||
println!("Максимальная стоимость предметов без превышения вместимости рюкзака = {res}");
|
||||
|
||||
// Поиск с запоминанием
|
||||
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!("Максимальная стоимость предметов без превышения вместимости рюкзака = {res}");
|
||||
|
||||
// Динамическое программирование
|
||||
let res = knapsack_dp(&wgt, &val, cap);
|
||||
println!("Максимальная стоимость предметов без превышения вместимости рюкзака = {res}");
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
let res = knapsack_dp_comp(&wgt, &val, cap);
|
||||
println!("Максимальная стоимость предметов без превышения вместимости рюкзака = {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;
|
||||
|
||||
/* Минимальная стоимость подъема по лестнице: динамическое программирование */
|
||||
fn min_cost_climbing_stairs_dp(cost: &[i32]) -> i32 {
|
||||
let n = cost.len() - 1;
|
||||
if n == 1 || n == 2 {
|
||||
return cost[n];
|
||||
}
|
||||
// Инициализация таблицы dp для хранения решений подзадач
|
||||
let mut dp = vec![-1; n + 1];
|
||||
// Начальное состояние: заранее задать решения наименьших подзадач
|
||||
dp[1] = cost[1];
|
||||
dp[2] = cost[2];
|
||||
// Переход состояний: постепенное решение больших подзадач через меньшие
|
||||
for i in 3..=n {
|
||||
dp[i] = cmp::min(dp[i - 1], dp[i - 2]) + cost[i];
|
||||
}
|
||||
dp[n]
|
||||
}
|
||||
|
||||
/* Минимальная стоимость подъема по лестнице: динамическое программирование с оптимизацией памяти */
|
||||
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!("Список стоимостей ступеней = {:?}", &cost);
|
||||
|
||||
let res = min_cost_climbing_stairs_dp(&cost);
|
||||
println!("Минимальная стоимость подъема по лестнице = {res}");
|
||||
|
||||
let res = min_cost_climbing_stairs_dp_comp(&cost);
|
||||
println!("Минимальная стоимость подъема по лестнице = {res}");
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* File: min_path_sum.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Минимальная сумма пути: полный перебор */
|
||||
fn min_path_sum_dfs(grid: &Vec<Vec<i32>>, i: i32, j: i32) -> i32 {
|
||||
// Если это верхняя левая ячейка, завершить поиск
|
||||
if i == 0 && j == 0 {
|
||||
return grid[0][0];
|
||||
}
|
||||
// Если индексы строки или столбца выходят за границы, вернуть стоимость +∞
|
||||
if i < 0 || j < 0 {
|
||||
return i32::MAX;
|
||||
}
|
||||
// Вычислить минимальную стоимость пути из левого верхнего угла до (i-1, j) и (i, j-1)
|
||||
let up = min_path_sum_dfs(grid, i - 1, j);
|
||||
let left = min_path_sum_dfs(grid, i, j - 1);
|
||||
// Вернуть минимальную стоимость пути из левого верхнего угла до (i, j)
|
||||
std::cmp::min(left, up) + grid[i as usize][j as usize]
|
||||
}
|
||||
|
||||
/* Минимальная сумма пути: поиск с мемоизацией */
|
||||
fn min_path_sum_dfs_mem(grid: &Vec<Vec<i32>>, mem: &mut Vec<Vec<i32>>, i: i32, j: i32) -> i32 {
|
||||
// Если это верхняя левая ячейка, завершить поиск
|
||||
if i == 0 && j == 0 {
|
||||
return grid[0][0];
|
||||
}
|
||||
// Если индексы строки или столбца выходят за границы, вернуть стоимость +∞
|
||||
if i < 0 || j < 0 {
|
||||
return i32::MAX;
|
||||
}
|
||||
// Если запись уже есть, вернуть сразу
|
||||
if mem[i as usize][j as usize] != -1 {
|
||||
return mem[i as usize][j as usize];
|
||||
}
|
||||
// Минимальная стоимость пути для левой и верхней ячеек
|
||||
let up = min_path_sum_dfs_mem(grid, mem, i - 1, j);
|
||||
let left = min_path_sum_dfs_mem(grid, mem, i, j - 1);
|
||||
// Сохранить и вернуть минимальную стоимость пути из левого верхнего угла до (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]
|
||||
}
|
||||
|
||||
/* Минимальная сумма пути: динамическое программирование */
|
||||
fn min_path_sum_dp(grid: &Vec<Vec<i32>>) -> i32 {
|
||||
let (n, m) = (grid.len(), grid[0].len());
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![vec![0; m]; n];
|
||||
dp[0][0] = grid[0][0];
|
||||
// Переход состояний: первая строка
|
||||
for j in 1..m {
|
||||
dp[0][j] = dp[0][j - 1] + grid[0][j];
|
||||
}
|
||||
// Переход состояний: первый столбец
|
||||
for i in 1..n {
|
||||
dp[i][0] = dp[i - 1][0] + grid[i][0];
|
||||
}
|
||||
// Переход состояний: остальные строки и столбцы
|
||||
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]
|
||||
}
|
||||
|
||||
/* Минимальная сумма пути: динамическое программирование с оптимизацией памяти */
|
||||
fn min_path_sum_dp_comp(grid: &Vec<Vec<i32>>) -> i32 {
|
||||
let (n, m) = (grid.len(), grid[0].len());
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![0; m];
|
||||
// Переход состояний: первая строка
|
||||
dp[0] = grid[0][0];
|
||||
for j in 1..m {
|
||||
dp[j] = dp[j - 1] + grid[0][j];
|
||||
}
|
||||
// Переход состояний: остальные строки
|
||||
for i in 1..n {
|
||||
// Переход состояний: первый столбец
|
||||
dp[0] = dp[0] + grid[i][0];
|
||||
// Переход состояний: остальные столбцы
|
||||
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());
|
||||
|
||||
// Полный перебор
|
||||
let res = min_path_sum_dfs(&grid, n as i32 - 1, m as i32 - 1);
|
||||
println!("Минимальная сумма пути из левого верхнего угла в правый нижний = {res}");
|
||||
|
||||
// Поиск с мемоизацией
|
||||
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!("Минимальная сумма пути из левого верхнего угла в правый нижний = {res}");
|
||||
|
||||
// Динамическое программирование
|
||||
let res = min_path_sum_dp(&grid);
|
||||
println!("Минимальная сумма пути из левого верхнего угла в правый нижний = {res}");
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
let res = min_path_sum_dp_comp(&grid);
|
||||
println!("Минимальная сумма пути из левого верхнего угла в правый нижний = {res}");
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* File: unbounded_knapsack.rs
|
||||
* Created Time: 2023-07-09
|
||||
* Author: codingonion (coderonion@gmail.com)
|
||||
*/
|
||||
|
||||
/* Полный рюкзак: динамическое программирование */
|
||||
fn unbounded_knapsack_dp(wgt: &[i32], val: &[i32], cap: usize) -> i32 {
|
||||
let n = wgt.len();
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![vec![0; cap + 1]; n + 1];
|
||||
// Переход состояний
|
||||
for i in 1..=n {
|
||||
for c in 1..=cap {
|
||||
if wgt[i - 1] > c as i32 {
|
||||
// Если вместимость рюкзака превышена, предмет i не выбирать
|
||||
dp[i][c] = dp[i - 1][c];
|
||||
} else {
|
||||
// Большее из двух решений: не брать или взять предмет 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];
|
||||
}
|
||||
|
||||
/* Полный рюкзак: динамическое программирование с оптимизацией памяти */
|
||||
fn unbounded_knapsack_dp_comp(wgt: &[i32], val: &[i32], cap: usize) -> i32 {
|
||||
let n = wgt.len();
|
||||
// Инициализация таблицы dp
|
||||
let mut dp = vec![0; cap + 1];
|
||||
// Переход состояний
|
||||
for i in 1..=n {
|
||||
for c in 1..=cap {
|
||||
if wgt[i - 1] > c as i32 {
|
||||
// Если вместимость рюкзака превышена, предмет i не выбирать
|
||||
dp[c] = dp[c];
|
||||
} else {
|
||||
// Большее из двух решений: не брать или взять предмет 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;
|
||||
|
||||
// Динамическое программирование
|
||||
let res = unbounded_knapsack_dp(&wgt, &val, cap);
|
||||
println!("Максимальная стоимость предметов без превышения вместимости рюкзака = {res}");
|
||||
|
||||
// Динамическое программирование с оптимизацией памяти
|
||||
let res = unbounded_knapsack_dp_comp(&wgt, &val, cap);
|
||||
println!("Максимальная стоимость предметов без превышения вместимости рюкзака = {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;
|
||||
|
||||
/* Тип неориентированного графа на основе списка смежности */
|
||||
pub struct GraphAdjList {
|
||||
// Список смежности, где key — вершина, а value — все смежные ей вершины
|
||||
pub adj_list: HashMap<Vertex, Vec<Vertex>>, // maybe HashSet<Vertex> for value part is better?
|
||||
}
|
||||
|
||||
impl GraphAdjList {
|
||||
/* Конструктор */
|
||||
pub fn new(edges: Vec<[Vertex; 2]>) -> Self {
|
||||
let mut graph = GraphAdjList {
|
||||
adj_list: HashMap::new(),
|
||||
};
|
||||
// Добавить все вершины и ребра
|
||||
for edge in edges {
|
||||
graph.add_vertex(edge[0]);
|
||||
graph.add_vertex(edge[1]);
|
||||
graph.add_edge(edge[0], edge[1]);
|
||||
}
|
||||
|
||||
graph
|
||||
}
|
||||
|
||||
/* Получить число вершин */
|
||||
#[allow(unused)]
|
||||
pub fn size(&self) -> usize {
|
||||
self.adj_list.len()
|
||||
}
|
||||
|
||||
/* Добавление ребра */
|
||||
pub fn add_edge(&mut self, vet1: Vertex, vet2: Vertex) {
|
||||
if vet1 == vet2 {
|
||||
panic!("value error");
|
||||
}
|
||||
// Добавить ребро vet1 - vet2
|
||||
self.adj_list.entry(vet1).or_default().push(vet2);
|
||||
self.adj_list.entry(vet2).or_default().push(vet1);
|
||||
}
|
||||
|
||||
/* Удаление ребра */
|
||||
#[allow(unused)]
|
||||
pub fn remove_edge(&mut self, vet1: Vertex, vet2: Vertex) {
|
||||
if vet1 == vet2 {
|
||||
panic!("value error");
|
||||
}
|
||||
// Удалить ребро 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));
|
||||
}
|
||||
|
||||
/* Добавление вершины */
|
||||
pub fn add_vertex(&mut self, vet: Vertex) {
|
||||
if self.adj_list.contains_key(&vet) {
|
||||
return;
|
||||
}
|
||||
// Добавить новый список в список смежности
|
||||
self.adj_list.insert(vet, vec![]);
|
||||
}
|
||||
|
||||
/* Удаление вершины */
|
||||
#[allow(unused)]
|
||||
pub fn remove_vertex(&mut self, vet: Vertex) {
|
||||
// Удалить из списка смежности список, соответствующий вершине vet
|
||||
self.adj_list.remove(&vet);
|
||||
// Обойти списки других вершин и удалить все ребра, содержащие vet
|
||||
for list in self.adj_list.values_mut() {
|
||||
list.retain(|&v| v != vet);
|
||||
}
|
||||
}
|
||||
|
||||
/* Вывести список смежности */
|
||||
pub fn print(&self) {
|
||||
println!("Список смежности =");
|
||||
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() {
|
||||
/* Инициализация неориентированного графа */
|
||||
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!("\nГраф после инициализации");
|
||||
graph.print();
|
||||
|
||||
/* Добавление ребра */
|
||||
// Вершины 1 и 2 соответствуют v[0] и v[2]
|
||||
graph.add_edge(v[0], v[2]);
|
||||
println!("\nГраф после добавления ребра 1-2");
|
||||
graph.print();
|
||||
|
||||
/* Удаление ребра */
|
||||
// Вершины 1 и 3 соответствуют v[0] и v[1]
|
||||
graph.remove_edge(v[0], v[1]);
|
||||
println!("\nГраф после удаления ребра 1-3");
|
||||
graph.print();
|
||||
|
||||
/* Добавление вершины */
|
||||
let v5 = Vertex { val: 6 };
|
||||
graph.add_vertex(v5);
|
||||
println!("\nГраф после добавления вершины 6");
|
||||
graph.print();
|
||||
|
||||
/* Удаление вершины */
|
||||
// Вершина 3 соответствует v[1]
|
||||
graph.remove_vertex(v[1]);
|
||||
println!("\nГраф после удаления вершины 3");
|
||||
graph.print();
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* File: graph_adjacency_matrix.rs
|
||||
* Created Time: 2023-07-12
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
|
||||
/* Тип неориентированного графа на основе матрицы смежности */
|
||||
pub struct GraphAdjMat {
|
||||
// Список вершин: элементы представляют «значения вершин», а индексы — «индексы вершин»
|
||||
pub vertices: Vec<i32>,
|
||||
// Матрица смежности, где индексы строк и столбцов соответствуют «индексам вершин»
|
||||
pub adj_mat: Vec<Vec<i32>>,
|
||||
}
|
||||
|
||||
impl GraphAdjMat {
|
||||
/* Конструктор */
|
||||
pub fn new(vertices: Vec<i32>, edges: Vec<[usize; 2]>) -> Self {
|
||||
let mut graph = GraphAdjMat {
|
||||
vertices: vec![],
|
||||
adj_mat: vec![],
|
||||
};
|
||||
// Добавление вершины
|
||||
for val in vertices {
|
||||
graph.add_vertex(val);
|
||||
}
|
||||
// Добавить ребра
|
||||
// Обратите внимание: элементы edges представляют собой индексы вершин, то есть соответствуют индексам элементов vertices
|
||||
for edge in edges {
|
||||
graph.add_edge(edge[0], edge[1])
|
||||
}
|
||||
|
||||
graph
|
||||
}
|
||||
|
||||
/* Получить число вершин */
|
||||
pub fn size(&self) -> usize {
|
||||
self.vertices.len()
|
||||
}
|
||||
|
||||
/* Добавление вершины */
|
||||
pub fn add_vertex(&mut self, val: i32) {
|
||||
let n = self.size();
|
||||
// Добавить значение новой вершины в список вершин
|
||||
self.vertices.push(val);
|
||||
// Добавить строку в матрицу смежности
|
||||
self.adj_mat.push(vec![0; n]);
|
||||
// Добавить столбец в матрицу смежности
|
||||
for row in self.adj_mat.iter_mut() {
|
||||
row.push(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Удаление вершины */
|
||||
pub fn remove_vertex(&mut self, index: usize) {
|
||||
if index >= self.size() {
|
||||
panic!("index error")
|
||||
}
|
||||
// Удалить вершину с индексом index из списка вершин
|
||||
self.vertices.remove(index);
|
||||
// Удалить строку с индексом index из матрицы смежности
|
||||
self.adj_mat.remove(index);
|
||||
// Удалить столбец с индексом index из матрицы смежности
|
||||
for row in self.adj_mat.iter_mut() {
|
||||
row.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
/* Добавление ребра */
|
||||
pub fn add_edge(&mut self, i: usize, j: usize) {
|
||||
// Параметры i и j соответствуют индексам элементов vertices
|
||||
// Обработка выхода индекса за границы и случая равенства
|
||||
if i >= self.size() || j >= self.size() || i == j {
|
||||
panic!("index error")
|
||||
}
|
||||
// В неориентированном графе матрица смежности симметрична относительно главной диагонали, то есть выполняется (i, j) == (j, i)
|
||||
self.adj_mat[i][j] = 1;
|
||||
self.adj_mat[j][i] = 1;
|
||||
}
|
||||
|
||||
/* Удаление ребра */
|
||||
// Параметры i и j соответствуют индексам элементов vertices
|
||||
pub fn remove_edge(&mut self, i: usize, j: usize) {
|
||||
// Параметры i и j соответствуют индексам элементов vertices
|
||||
// Обработка выхода индекса за границы и случая равенства
|
||||
if i >= self.size() || j >= self.size() || i == j {
|
||||
panic!("index error")
|
||||
}
|
||||
self.adj_mat[i][j] = 0;
|
||||
self.adj_mat[j][i] = 0;
|
||||
}
|
||||
|
||||
/* Вывести матрицу смежности */
|
||||
pub fn print(&self) {
|
||||
println!("Список вершин = {:?}", self.vertices);
|
||||
println!("Матрица смежности =");
|
||||
println!("[");
|
||||
for row in &self.adj_mat {
|
||||
println!(" {:?},", row);
|
||||
}
|
||||
println!("]")
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Инициализация неориентированного графа */
|
||||
// Обратите внимание: элементы edges представляют индексы вершин, то есть соответствуют индексам элементов vertices
|
||||
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!("\nГраф после инициализации");
|
||||
graph.print();
|
||||
|
||||
/* Добавление ребра */
|
||||
// Индексы вершин 1 и 2 равны 0 и 2 соответственно
|
||||
graph.add_edge(0, 2);
|
||||
println!("\nГраф после добавления ребра 1-2");
|
||||
graph.print();
|
||||
|
||||
/* Удаление ребра */
|
||||
// Индексы вершин 1 и 3 равны 0 и 1 соответственно
|
||||
graph.remove_edge(0, 1);
|
||||
println!("\nГраф после удаления ребра 1-3");
|
||||
graph.print();
|
||||
|
||||
/* Добавление вершины */
|
||||
graph.add_vertex(6);
|
||||
println!("\nГраф после добавления вершины 6");
|
||||
graph.print();
|
||||
|
||||
/* Удаление вершины */
|
||||
// Индекс вершины 3 равен 1
|
||||
graph.remove_vertex(1);
|
||||
println!("\nГраф после удаления вершины 3");
|
||||
graph.print();
|
||||
}
|
||||
@@ -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};
|
||||
|
||||
/* Обход в ширину */
|
||||
// Использовать список смежности для представления графа, чтобы получить все смежные вершины заданной вершины
|
||||
fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
|
||||
// Последовательность обхода вершин
|
||||
let mut res = vec![];
|
||||
// Хеш-множество для хранения уже посещенных вершин
|
||||
let mut visited = HashSet::new();
|
||||
visited.insert(start_vet);
|
||||
// Очередь используется для реализации BFS
|
||||
let mut que = VecDeque::new();
|
||||
que.push_back(start_vet);
|
||||
// Начиная с вершины vet, продолжать цикл, пока не будут посещены все вершины
|
||||
while let Some(vet) = que.pop_front() {
|
||||
res.push(vet); // Отметить посещенную вершину
|
||||
|
||||
// Обойти все смежные вершины данной вершины
|
||||
if let Some(adj_vets) = graph.adj_list.get(&vet) {
|
||||
for &adj_vet in adj_vets {
|
||||
if visited.contains(&adj_vet) {
|
||||
continue; // Пропустить уже посещенную вершину
|
||||
}
|
||||
que.push_back(adj_vet); // Помещать в очередь только непосещенные вершины
|
||||
visited.insert(adj_vet); // Отметить эту вершину как посещенную
|
||||
}
|
||||
}
|
||||
}
|
||||
// Вернуть последовательность обхода вершин
|
||||
res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Инициализация неориентированного графа */
|
||||
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!("\nГраф после инициализации");
|
||||
graph.print();
|
||||
|
||||
/* Обход в ширину */
|
||||
let res = graph_bfs(graph, v[0]);
|
||||
println!("\nПоследовательность вершин при обходе в ширину (BFS)");
|
||||
println!("{:?}", vets_to_vals(res));
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/* Вспомогательная функция обхода в глубину */
|
||||
fn dfs(graph: &GraphAdjList, visited: &mut HashSet<Vertex>, res: &mut Vec<Vertex>, vet: Vertex) {
|
||||
res.push(vet); // Отметить посещенную вершину
|
||||
visited.insert(vet); // Отметить эту вершину как посещенную
|
||||
// Обойти все смежные вершины данной вершины
|
||||
if let Some(adj_vets) = graph.adj_list.get(&vet) {
|
||||
for &adj_vet in adj_vets {
|
||||
if visited.contains(&adj_vet) {
|
||||
continue; // Пропустить уже посещенную вершину
|
||||
}
|
||||
// Рекурсивно обходить смежные вершины
|
||||
dfs(graph, visited, res, adj_vet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Обход в глубину */
|
||||
// Использовать список смежности для представления графа, чтобы получить все смежные вершины заданной вершины
|
||||
fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
|
||||
// Последовательность обхода вершин
|
||||
let mut res = vec![];
|
||||
// Хеш-множество для хранения уже посещенных вершин
|
||||
let mut visited = HashSet::new();
|
||||
dfs(&graph, &mut visited, &mut res, start_vet);
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Инициализация неориентированного графа */
|
||||
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!("\nГраф после инициализации");
|
||||
graph.print();
|
||||
|
||||
/* Обход в глубину */
|
||||
let res = graph_dfs(graph, v[0]);
|
||||
println!("\nПоследовательность вершин при обходе в глубину (DFS)");
|
||||
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)
|
||||
*/
|
||||
|
||||
/* Размен монет: жадный алгоритм */
|
||||
fn coin_change_greedy(coins: &[i32], mut amt: i32) -> i32 {
|
||||
// Предположить, что список coins упорядочен
|
||||
let mut i = coins.len() - 1;
|
||||
let mut count = 0;
|
||||
// Циклически выполнять жадный выбор, пока не останется суммы
|
||||
while amt > 0 {
|
||||
// Найти монету, которая меньше остатка суммы и наиболее к нему близка
|
||||
while i > 0 && coins[i] > amt {
|
||||
i -= 1;
|
||||
}
|
||||
// Выбрать coins[i]
|
||||
amt -= coins[i];
|
||||
count += 1;
|
||||
}
|
||||
// Если допустимое решение не найдено, вернуть -1
|
||||
if amt == 0 {
|
||||
count
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
// Жадный подход: гарантирует нахождение глобально оптимального решения
|
||||
let coins = [1, 5, 10, 20, 50, 100];
|
||||
let amt = 186;
|
||||
let res = coin_change_greedy(&coins, amt);
|
||||
println!("\ncoins = {:?}, amt = {}", coins, amt);
|
||||
println!("Минимальное число монет для набора суммы {} = {}", amt, res);
|
||||
|
||||
// Жадный подход: не гарантирует нахождение глобально оптимального решения
|
||||
let coins = [1, 20, 50];
|
||||
let amt = 60;
|
||||
let res = coin_change_greedy(&coins, amt);
|
||||
println!("\ncoins = {:?}, amt = {}", coins, amt);
|
||||
println!("Минимальное число монет для набора суммы {} = {}", amt, res);
|
||||
println!("На самом деле минимум равен 3: 20 + 20 + 20");
|
||||
|
||||
// Жадный подход: не гарантирует нахождение глобально оптимального решения
|
||||
let coins = [1, 49, 50];
|
||||
let amt = 98;
|
||||
let res = coin_change_greedy(&coins, amt);
|
||||
println!("\ncoins = {:?}, amt = {}", coins, amt);
|
||||
println!("Минимальное число монет для набора суммы {} = {}", amt, res);
|
||||
println!("На самом деле минимум равен 2: 49 + 49");
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* File: coin_change_greedy.rs
|
||||
* Created Time: 2023-07-22
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
|
||||
/* Предмет */
|
||||
struct Item {
|
||||
w: i32, // Вес предмета
|
||||
v: i32, // Стоимость предмета
|
||||
}
|
||||
|
||||
impl Item {
|
||||
fn new(w: i32, v: i32) -> Self {
|
||||
Self { w, v }
|
||||
}
|
||||
}
|
||||
|
||||
/* Дробный рюкзак: жадный алгоритм */
|
||||
fn fractional_knapsack(wgt: &[i32], val: &[i32], mut cap: i32) -> f64 {
|
||||
// Создать список предметов с двумя свойствами: вес и стоимость
|
||||
let mut items = wgt
|
||||
.iter()
|
||||
.zip(val.iter())
|
||||
.map(|(&w, &v)| Item::new(w, v))
|
||||
.collect::<Vec<Item>>();
|
||||
// Отсортировать по удельной стоимости item.v / item.w в порядке убывания
|
||||
items.sort_by(|a, b| {
|
||||
(b.v as f64 / b.w as f64)
|
||||
.partial_cmp(&(a.v as f64 / a.w as f64))
|
||||
.unwrap()
|
||||
});
|
||||
// Циклический жадный выбор
|
||||
let mut res = 0.0;
|
||||
for item in &items {
|
||||
if item.w <= cap {
|
||||
// Если оставшейся вместимости достаточно, положить в рюкзак текущий предмет целиком
|
||||
res += item.v as f64;
|
||||
cap -= item.w;
|
||||
} else {
|
||||
// Если оставшейся вместимости недостаточно, положить в рюкзак часть текущего предмета
|
||||
res += item.v as f64 / item.w as f64 * cap as f64;
|
||||
// Свободной вместимости больше не осталось, поэтому выйти из цикла
|
||||
break;
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
let wgt = [10, 20, 30, 40, 50];
|
||||
let val = [50, 120, 150, 210, 240];
|
||||
let cap = 50;
|
||||
|
||||
// Жадный алгоритм
|
||||
let res = fractional_knapsack(&wgt, &val, cap);
|
||||
println!("Максимальная стоимость предметов без превышения вместимости рюкзака = {}", res);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* File: coin_change_greedy.rs
|
||||
* Created Time: 2023-07-22
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
|
||||
/* Максимальная вместимость: жадный алгоритм */
|
||||
fn max_capacity(ht: &[i32]) -> i32 {
|
||||
// Инициализировать i и j так, чтобы они располагались по двум концам массива
|
||||
let mut i = 0;
|
||||
let mut j = ht.len() - 1;
|
||||
// Начальная максимальная вместимость равна 0
|
||||
let mut res = 0;
|
||||
// Выполнять жадный выбор в цикле, пока две доски не встретятся
|
||||
while i < j {
|
||||
// Обновить максимальную вместимость
|
||||
let cap = std::cmp::min(ht[i], ht[j]) * (j - i) as i32;
|
||||
res = std::cmp::max(res, cap);
|
||||
// Сдвигать внутрь более короткую сторону
|
||||
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];
|
||||
|
||||
// Жадный алгоритм
|
||||
let res = max_capacity(&ht);
|
||||
println!("Максимальная вместимость = {}", res);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* File: coin_change_greedy.rs
|
||||
* Created Time: 2023-07-22
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
|
||||
/* Максимальное произведение разрезания: жадный алгоритм */
|
||||
fn max_product_cutting(n: i32) -> i32 {
|
||||
// Когда n <= 3, обязательно нужно выделить одну 1
|
||||
if n <= 3 {
|
||||
return 1 * (n - 1);
|
||||
}
|
||||
// Жадно выделить множители 3, где a — число троек, а b — остаток
|
||||
let a = n / 3;
|
||||
let b = n % 3;
|
||||
if b == 1 {
|
||||
// Если остаток равен 1, преобразовать одну пару 1 * 3 в 2 * 2
|
||||
3_i32.pow(a as u32 - 1) * 2 * 2
|
||||
} else if b == 2 {
|
||||
// Если остаток равен 2, ничего не делать
|
||||
3_i32.pow(a as u32) * 2
|
||||
} else {
|
||||
// Если остаток равен 0, ничего не делать
|
||||
3_i32.pow(a as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
let n = 58;
|
||||
|
||||
// Жадный алгоритм
|
||||
let res = max_product_cutting(n);
|
||||
println!("Максимальное произведение после разрезания = {}", res);
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* File: array_hash_map.rs
|
||||
* Created Time: 2023-2-18
|
||||
* Author: xBLACICEx (xBLACKICEx@outlook.com)
|
||||
*/
|
||||
|
||||
/* Пара ключ-значение */
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Pair {
|
||||
pub key: i32,
|
||||
pub val: String,
|
||||
}
|
||||
/* Хеш-таблица на основе массива */
|
||||
pub struct ArrayHashMap {
|
||||
buckets: Vec<Option<Pair>>,
|
||||
}
|
||||
|
||||
impl ArrayHashMap {
|
||||
pub fn new() -> ArrayHashMap {
|
||||
// Инициализировать массив, содержащий 100 корзин
|
||||
Self {
|
||||
buckets: vec![None; 100],
|
||||
}
|
||||
}
|
||||
|
||||
/* Хеш-функция */
|
||||
fn hash_func(&self, key: i32) -> usize {
|
||||
key as usize % 100
|
||||
}
|
||||
|
||||
/* Операция поиска */
|
||||
pub fn get(&self, key: i32) -> Option<&String> {
|
||||
let index = self.hash_func(key);
|
||||
self.buckets[index].as_ref().map(|pair| &pair.val)
|
||||
}
|
||||
|
||||
/* Операция добавления */
|
||||
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(),
|
||||
});
|
||||
}
|
||||
|
||||
/* Операция удаления */
|
||||
pub fn remove(&mut self, key: i32) {
|
||||
let index = self.hash_func(key);
|
||||
// Присвоить None, что означает удаление
|
||||
self.buckets[index] = None;
|
||||
}
|
||||
|
||||
/* Получить все пары ключ-значение */
|
||||
pub fn entry_set(&self) -> Vec<&Pair> {
|
||||
self.buckets
|
||||
.iter()
|
||||
.filter_map(|pair| pair.as_ref())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/* Получить все ключи */
|
||||
pub fn key_set(&self) -> Vec<&i32> {
|
||||
self.buckets
|
||||
.iter()
|
||||
.filter_map(|pair| pair.as_ref().map(|pair| &pair.key))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/* Получить все значения */
|
||||
pub fn value_set(&self) -> Vec<&String> {
|
||||
self.buckets
|
||||
.iter()
|
||||
.filter_map(|pair| pair.as_ref().map(|pair| &pair.val))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/* Вывести хеш-таблицу */
|
||||
pub fn print(&self) {
|
||||
for pair in self.entry_set() {
|
||||
println!("{} -> {}", pair.key, pair.val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
/* Инициализация хеш-таблицы */
|
||||
let mut map = ArrayHashMap::new();
|
||||
/* Операция добавления */
|
||||
// Добавить пару (key, value) в хеш-таблицу
|
||||
map.put(12836, "Сяо Ха");
|
||||
map.put(15937, "Сяо Ло");
|
||||
map.put(16750, "Сяо Суань");
|
||||
map.put(13276, "Сяо Фа");
|
||||
map.put(10583, "Сяо Я");
|
||||
println!("\nПосле добавления хеш-таблица имеет вид\nКлюч -> Значение");
|
||||
map.print();
|
||||
|
||||
/* Операция поиска */
|
||||
// Ввести в хеш-таблицу ключ key и получить значение value
|
||||
let name = map.get(15937).unwrap();
|
||||
println!("\nДля номера 15937 найдено имя {}", name);
|
||||
|
||||
/* Операция удаления */
|
||||
// Удалить пару (key, value) из хеш-таблицы
|
||||
map.remove(10583);
|
||||
println!("\nПосле удаления 10583 хеш-таблица имеет вид\nКлюч -> Значение");
|
||||
map.print();
|
||||
|
||||
/* Обход хеш-таблицы */
|
||||
println!("\nОтдельный обход пар ключ-значение");
|
||||
for pair in map.entry_set() {
|
||||
println!("{} -> {}", pair.key, pair.val);
|
||||
}
|
||||
|
||||
println!("\nОтдельный обход ключей");
|
||||
for key in map.key_set() {
|
||||
println!("{}", key);
|
||||
}
|
||||
|
||||
println!("\nОтдельный обход значений");
|
||||
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!("Хеш-значение целого числа {} = {}", num, hash_num);
|
||||
|
||||
let bol = true;
|
||||
let mut bol_hasher = DefaultHasher::new();
|
||||
bol.hash(&mut bol_hasher);
|
||||
let hash_bol = bol_hasher.finish();
|
||||
println!("Хеш-значение булева значения {} = {}", 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!("Хеш-значение десятичного числа {} = {}", 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!("Хеш-значение строки {} = {}", str, hash_str);
|
||||
|
||||
let arr = (&12836, &"Сяо Ха");
|
||||
let mut tup_hasher = DefaultHasher::new();
|
||||
arr.hash(&mut tup_hasher);
|
||||
let hash_tup = tup_hasher.finish();
|
||||
println!("Хеш-значение кортежа {:?} = {}", arr, hash_tup);
|
||||
|
||||
let node = ListNode::new(42);
|
||||
let mut hasher = DefaultHasher::new();
|
||||
node.borrow().val.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
println!("Хеш-значение объекта узла {:?} = {}", node, hash);
|
||||
}
|
||||
@@ -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() {
|
||||
// Инициализация хеш-таблицы
|
||||
let mut map = HashMap::new();
|
||||
|
||||
// Операция добавления
|
||||
// Добавить пару (key, value) в хеш-таблицу
|
||||
map.insert(12836, "Сяо Ха");
|
||||
map.insert(15937, "Сяо Ло");
|
||||
map.insert(16750, "Сяо Суань");
|
||||
map.insert(13276, "Сяо Фа");
|
||||
map.insert(10583, "Сяо Я");
|
||||
println!("\nПосле добавления хеш-таблица имеет вид\nКлюч -> Значение");
|
||||
print_util::print_hash_map(&map);
|
||||
|
||||
// Операция поиска
|
||||
// Передать ключ key в хеш-таблицу и получить значение value
|
||||
let name = map.get(&15937).copied().unwrap();
|
||||
println!("\nДля номера 15937 найдено имя {name}");
|
||||
|
||||
// Операция удаления
|
||||
// Удалить пару (key, value) из хеш-таблицы
|
||||
_ = map.remove(&10583);
|
||||
println!("\nПосле удаления 10583 хеш-таблица имеет вид\nКлюч -> Значение");
|
||||
print_util::print_hash_map(&map);
|
||||
|
||||
// Обход хеш-таблицы
|
||||
println!("\nОтдельный обход пар ключ-значение");
|
||||
print_util::print_hash_map(&map);
|
||||
println!("\nОтдельный обход ключей");
|
||||
for key in map.keys() {
|
||||
println!("{key}");
|
||||
}
|
||||
println!("\nОтдельный обход значений");
|
||||
for value in map.values() {
|
||||
println!("{value}");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* File: hash_map_chaining.rs
|
||||
* Created Time: 2023-07-07
|
||||
* Author: WSL0809 (wslzzy@outlook.com)
|
||||
*/
|
||||
|
||||
#[derive(Clone)]
|
||||
/* Пара ключ-значение */
|
||||
struct Pair {
|
||||
key: i32,
|
||||
val: String,
|
||||
}
|
||||
|
||||
/* Хеш-таблица с цепочками */
|
||||
struct HashMapChaining {
|
||||
size: usize,
|
||||
capacity: usize,
|
||||
load_thres: f32,
|
||||
extend_ratio: usize,
|
||||
buckets: Vec<Vec<Pair>>,
|
||||
}
|
||||
|
||||
impl HashMapChaining {
|
||||
/* Конструктор */
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
size: 0,
|
||||
capacity: 4,
|
||||
load_thres: 2.0 / 3.0,
|
||||
extend_ratio: 2,
|
||||
buckets: vec![vec![]; 4],
|
||||
}
|
||||
}
|
||||
|
||||
/* Хеш-функция */
|
||||
fn hash_func(&self, key: i32) -> usize {
|
||||
key as usize % self.capacity
|
||||
}
|
||||
|
||||
/* Коэффициент загрузки */
|
||||
fn load_factor(&self) -> f32 {
|
||||
self.size as f32 / self.capacity as f32
|
||||
}
|
||||
|
||||
/* Операция удаления */
|
||||
fn remove(&mut self, key: i32) -> Option<String> {
|
||||
let index = self.hash_func(key);
|
||||
|
||||
// Обойти корзину и удалить из нее пару ключ-значение
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Если key не найден, вернуть None
|
||||
None
|
||||
}
|
||||
|
||||
/* Расширить хеш-таблицу */
|
||||
fn extend(&mut self) {
|
||||
// Временно сохранить исходную хеш-таблицу
|
||||
let buckets_tmp = std::mem::take(&mut self.buckets);
|
||||
|
||||
// Инициализация новой хеш-таблицы после расширения
|
||||
self.capacity *= self.extend_ratio;
|
||||
self.buckets = vec![Vec::new(); self.capacity as usize];
|
||||
self.size = 0;
|
||||
|
||||
// Перенести пары ключ-значение из исходной хеш-таблицы в новую
|
||||
for bucket in buckets_tmp {
|
||||
for pair in bucket {
|
||||
self.put(pair.key, pair.val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Вывести хеш-таблицу */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Операция добавления */
|
||||
fn put(&mut self, key: i32, val: String) {
|
||||
// Когда коэффициент загрузки превышает порог, выполнить расширение
|
||||
if self.load_factor() > self.load_thres {
|
||||
self.extend();
|
||||
}
|
||||
|
||||
let index = self.hash_func(key);
|
||||
|
||||
// Обойти корзину; если встретился указанный key, обновить соответствующее val и вернуть
|
||||
for pair in self.buckets[index].iter_mut() {
|
||||
if pair.key == key {
|
||||
pair.val = val;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Если такого key нет, добавить пару ключ-значение в конец
|
||||
let pair = Pair { key, val };
|
||||
self.buckets[index].push(pair);
|
||||
self.size += 1;
|
||||
}
|
||||
|
||||
/* Операция поиска */
|
||||
fn get(&self, key: i32) -> Option<&str> {
|
||||
let index = self.hash_func(key);
|
||||
|
||||
// Обойти корзину; если найден key, вернуть соответствующее val
|
||||
for pair in self.buckets[index].iter() {
|
||||
if pair.key == key {
|
||||
return Some(&pair.val);
|
||||
}
|
||||
}
|
||||
|
||||
// Если key не найден, вернуть None
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
pub fn main() {
|
||||
/* Инициализация хеш-таблицы */
|
||||
let mut map = HashMapChaining::new();
|
||||
|
||||
/* Операция добавления */
|
||||
// Добавить пару (key, value) в хеш-таблицу
|
||||
map.put(12836, "Сяо Ха".to_string());
|
||||
map.put(15937, "Сяо Ло".to_string());
|
||||
map.put(16750, "Сяо Суань".to_string());
|
||||
map.put(13276, "Сяо Фа".to_string());
|
||||
map.put(10583, "Сяо Я".to_string());
|
||||
println!("\nПосле добавления хеш-таблица имеет вид\nКлюч -> Значение");
|
||||
map.print();
|
||||
|
||||
/* Операция поиска */
|
||||
// Ввести в хеш-таблицу ключ key и получить значение value
|
||||
println!(
|
||||
"\nПо номеру 13276 найдено имя {}",\nmatch map.get(13276) {\n Some(value) => value,\n None => "Not a valid Key",\n}
|
||||
);
|
||||
|
||||
/* Операция удаления */
|
||||
// Удалить пару (key, value) из хеш-таблицы
|
||||
map.remove(12836);
|
||||
println!("\nПосле удаления 12836 хеш-таблица имеет вид\nКлюч -> Значение");
|
||||
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;
|
||||
|
||||
/* Хеш-таблица с открытой адресацией */
|
||||
struct HashMapOpenAddressing {
|
||||
size: usize, // Число пар ключ-значение
|
||||
capacity: usize, // Вместимость хеш-таблицы
|
||||
load_thres: f64, // Порог коэффициента загрузки для запуска расширения
|
||||
extend_ratio: usize, // Коэффициент расширения
|
||||
buckets: Vec<Option<Pair>>, // Массив корзин
|
||||
TOMBSTONE: Option<Pair>, // Удалить метку
|
||||
}
|
||||
|
||||
impl HashMapOpenAddressing {
|
||||
/* Конструктор */
|
||||
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(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/* Хеш-функция */
|
||||
fn hash_func(&self, key: i32) -> usize {
|
||||
(key % self.capacity as i32) as usize
|
||||
}
|
||||
|
||||
/* Коэффициент загрузки */
|
||||
fn load_factor(&self) -> f64 {
|
||||
self.size as f64 / self.capacity as f64
|
||||
}
|
||||
|
||||
/* Найти индекс корзины, соответствующий key */
|
||||
fn find_bucket(&mut self, key: i32) -> usize {
|
||||
let mut index = self.hash_func(key);
|
||||
let mut first_tombstone = -1;
|
||||
// Выполнять линейное пробирование и завершить при встрече с пустой корзиной
|
||||
while self.buckets[index].is_some() {
|
||||
// Если встретился key, вернуть соответствующий индекс корзины
|
||||
if self.buckets[index].as_ref().unwrap().key == key {
|
||||
// Если ранее встретилась метка удаления, переместить пару ключ-значение в этот индекс
|
||||
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 index; // Вернуть индекс корзины
|
||||
}
|
||||
// Записать первую встретившуюся метку удаления
|
||||
if first_tombstone == -1 && self.buckets[index] == self.TOMBSTONE {
|
||||
first_tombstone = index as i32;
|
||||
}
|
||||
// Вычислить индекс корзины; при выходе за конец вернуться к началу
|
||||
index = (index + 1) % self.capacity;
|
||||
}
|
||||
// Если key не существует, вернуть индекс точки добавления
|
||||
if first_tombstone == -1 {
|
||||
index
|
||||
} else {
|
||||
first_tombstone as usize
|
||||
}
|
||||
}
|
||||
|
||||
/* Операция поиска */
|
||||
fn get(&mut self, key: i32) -> Option<&str> {
|
||||
// Найти индекс корзины, соответствующий key
|
||||
let index = self.find_bucket(key);
|
||||
// Если пара ключ-значение найдена, вернуть соответствующее val
|
||||
if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {
|
||||
return self.buckets[index].as_ref().map(|pair| &pair.val as &str);
|
||||
}
|
||||
// Если пары ключ-значение не существует, вернуть null
|
||||
None
|
||||
}
|
||||
|
||||
/* Операция добавления */
|
||||
fn put(&mut self, key: i32, val: String) {
|
||||
// Когда коэффициент загрузки превышает порог, выполнить расширение
|
||||
if self.load_factor() > self.load_thres {
|
||||
self.extend();
|
||||
}
|
||||
// Найти индекс корзины, соответствующий key
|
||||
let index = self.find_bucket(key);
|
||||
// Если пара ключ-значение найдена, перезаписать val и вернуть
|
||||
if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {
|
||||
self.buckets[index].as_mut().unwrap().val = val;
|
||||
return;
|
||||
}
|
||||
// Если пары ключ-значение нет, добавить ее
|
||||
self.buckets[index] = Some(Pair { key, val });
|
||||
self.size += 1;
|
||||
}
|
||||
|
||||
/* Операция удаления */
|
||||
fn remove(&mut self, key: i32) {
|
||||
// Найти индекс корзины, соответствующий key
|
||||
let index = self.find_bucket(key);
|
||||
// Если пара ключ-значение найдена, заменить ее меткой удаления
|
||||
if self.buckets[index].is_some() && self.buckets[index] != self.TOMBSTONE {
|
||||
self.buckets[index] = self.TOMBSTONE.clone();
|
||||
self.size -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Расширить хеш-таблицу */
|
||||
fn extend(&mut self) {
|
||||
// Временно сохранить исходную хеш-таблицу
|
||||
let buckets_tmp = self.buckets.clone();
|
||||
// Инициализация новой хеш-таблицы после расширения
|
||||
self.capacity *= self.extend_ratio;
|
||||
self.buckets = vec![None; self.capacity];
|
||||
self.size = 0;
|
||||
|
||||
// Перенести пары ключ-значение из исходной хеш-таблицы в новую
|
||||
for pair in buckets_tmp {
|
||||
if pair.is_none() || pair == self.TOMBSTONE {
|
||||
continue;
|
||||
}
|
||||
let pair = pair.unwrap();
|
||||
|
||||
self.put(pair.key, pair.val);
|
||||
}
|
||||
}
|
||||
/* Вывести хеш-таблицу */
|
||||
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() {
|
||||
/* Инициализация хеш-таблицы */
|
||||
let mut hashmap = HashMapOpenAddressing::new();
|
||||
|
||||
/* Операция добавления */
|
||||
// Добавить пару (key, value) в хеш-таблицу
|
||||
hashmap.put(12836, "Сяо Ха".to_string());
|
||||
hashmap.put(15937, "Сяо Ло".to_string());
|
||||
hashmap.put(16750, "Сяо Суань".to_string());
|
||||
hashmap.put(13276, "Сяо Фа".to_string());
|
||||
hashmap.put(10583, "Сяо Я".to_string());
|
||||
|
||||
println!("\nПосле добавления хеш-таблица имеет вид\nКлюч -> Значение");
|
||||
hashmap.print();
|
||||
|
||||
/* Операция поиска */
|
||||
// Передать ключ key в хеш-таблицу и получить значение val
|
||||
let name = hashmap.get(13276).unwrap();
|
||||
println!("\nДля номера 13276 найдено имя {}", name);
|
||||
|
||||
/* Операция удаления */
|
||||
// Удалить пару (key, val) из хеш-таблицы
|
||||
hashmap.remove(16750);
|
||||
println!("\nПосле удаления 16750 хеш-таблица имеет вид\nКлюч -> Значение");
|
||||
hashmap.print();
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* File: simple_hash.rs
|
||||
* Created Time: 2023-09-07
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
|
||||
/* Аддитивное хеширование */
|
||||
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
|
||||
}
|
||||
|
||||
/* Мультипликативное хеширование */
|
||||
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-хеширование */
|
||||
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
|
||||
}
|
||||
|
||||
/* Хеширование с циклическим сдвигом */
|
||||
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!("Хеш-сумма сложением = {hash}");
|
||||
|
||||
let hash = mul_hash(key);
|
||||
println!("Хеш-сумма умножением = {hash}");
|
||||
|
||||
let hash = xor_hash(key);
|
||||
println!("Хеш-сумма XOR = {hash}");
|
||||
|
||||
let hash = rot_hash(key);
|
||||
println!("Хеш-сумма с циклическим сдвигом = {hash}");
|
||||
}
|
||||
@@ -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); // Добавление элемента в кучу
|
||||
println!("\nПосле добавления элемента {} в кучу", 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!("\nПосле извлечения элемента вершины кучи {}", val);
|
||||
print_util::print_heap(heap.iter().map(|&val| val).collect());
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Инициализация кучи */
|
||||
// Инициализация минимальной кучи
|
||||
#[allow(unused_assignments)]
|
||||
let mut min_heap = BinaryHeap::new();
|
||||
// BinaryHeap в Rust является максимальной кучей; для минимальной кучи обычно используют оболочку Reverse
|
||||
// Инициализировать максимальную кучу
|
||||
let mut max_heap = BinaryHeap::new();
|
||||
|
||||
println!("\nНиже приведен тестовый пример для max-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);
|
||||
|
||||
/* Получение элемента с вершины кучи */
|
||||
let peek = max_heap.peek().unwrap();
|
||||
println!("\nЭлемент на вершине кучи = {}", peek);
|
||||
|
||||
/* Извлечение элемента с вершины кучи */
|
||||
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);
|
||||
|
||||
/* Получение размера кучи */
|
||||
let size = max_heap.len();
|
||||
println!("\nКоличество элементов в куче = {}", size);
|
||||
|
||||
/* Проверка, пуста ли куча */
|
||||
let is_empty = max_heap.is_empty();
|
||||
println!("\nПуста ли куча: {}", is_empty);
|
||||
|
||||
/* Построить кучу по входному списку */
|
||||
// Временная сложность равна O(n), а не O(nlogn)
|
||||
min_heap = BinaryHeap::from(
|
||||
vec![1, 3, 2, 5, 4]
|
||||
.into_iter()
|
||||
.map(|val| Reverse(val))
|
||||
.collect::<Vec<Reverse<i32>>>(),
|
||||
);
|
||||
println!("\nПосле построения min-heap из входного списка");
|
||||
print_util::print_heap(min_heap.iter().map(|&val| val.0).collect());
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/* Максимальная куча */
|
||||
struct MaxHeap {
|
||||
// Использовать vector вместо массива, чтобы не учитывать проблему расширения
|
||||
max_heap: Vec<i32>,
|
||||
}
|
||||
|
||||
impl MaxHeap {
|
||||
/* Конструктор, строящий кучу по входному списку */
|
||||
fn new(nums: Vec<i32>) -> Self {
|
||||
// Добавить элементы списка в кучу без изменений
|
||||
let mut heap = MaxHeap { max_heap: nums };
|
||||
// Выполнить heapify для всех узлов, кроме листовых
|
||||
for i in (0..=Self::parent(heap.size() - 1)).rev() {
|
||||
heap.sift_down(i);
|
||||
}
|
||||
heap
|
||||
}
|
||||
|
||||
/* Получить индекс левого дочернего узла */
|
||||
fn left(i: usize) -> usize {
|
||||
2 * i + 1
|
||||
}
|
||||
|
||||
/* Получить индекс правого дочернего узла */
|
||||
fn right(i: usize) -> usize {
|
||||
2 * i + 2
|
||||
}
|
||||
|
||||
/* Получить индекс родительского узла */
|
||||
fn parent(i: usize) -> usize {
|
||||
(i - 1) / 2 // Округление вниз при делении
|
||||
}
|
||||
|
||||
/* Поменять элементы местами */
|
||||
fn swap(&mut self, i: usize, j: usize) {
|
||||
self.max_heap.swap(i, j);
|
||||
}
|
||||
|
||||
/* Получение размера кучи */
|
||||
fn size(&self) -> usize {
|
||||
self.max_heap.len()
|
||||
}
|
||||
|
||||
/* Проверка, пуста ли куча */
|
||||
fn is_empty(&self) -> bool {
|
||||
self.max_heap.is_empty()
|
||||
}
|
||||
|
||||
/* Доступ к элементу на вершине кучи */
|
||||
fn peek(&self) -> Option<i32> {
|
||||
self.max_heap.first().copied()
|
||||
}
|
||||
|
||||
/* Добавление элемента в кучу */
|
||||
fn push(&mut self, val: i32) {
|
||||
// Добавление узла
|
||||
self.max_heap.push(val);
|
||||
// Просеивание снизу вверх
|
||||
self.sift_up(self.size() - 1);
|
||||
}
|
||||
|
||||
/* Начиная с узла i, выполнить просеивание снизу вверх */
|
||||
fn sift_up(&mut self, mut i: usize) {
|
||||
loop {
|
||||
// Если узел i уже является вершиной кучи, завершить просеивание
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
// Получение родительского узла для узла i
|
||||
let p = Self::parent(i);
|
||||
// Когда «узел не требует исправления», завершить просеивание
|
||||
if self.max_heap[i] <= self.max_heap[p] {
|
||||
break;
|
||||
}
|
||||
// Поменять два узла местами
|
||||
self.swap(i, p);
|
||||
// Циклическое просеивание вверх
|
||||
i = p;
|
||||
}
|
||||
}
|
||||
|
||||
/* Извлечение элемента из кучи */
|
||||
fn pop(&mut self) -> i32 {
|
||||
// Обработка пустого случая
|
||||
if self.is_empty() {
|
||||
panic!("index out of bounds");
|
||||
}
|
||||
// Поменять корневой узел с самым правым листом местами (поменять первый и последний элементы)
|
||||
self.swap(0, self.size() - 1);
|
||||
// Удаление узла
|
||||
let val = self.max_heap.pop().unwrap();
|
||||
// Просеивание сверху вниз
|
||||
self.sift_down(0);
|
||||
// Вернуть элемент с вершины кучи
|
||||
val
|
||||
}
|
||||
|
||||
/* Начиная с узла i, выполнить просеивание сверху вниз */
|
||||
fn sift_down(&mut self, mut i: usize) {
|
||||
loop {
|
||||
// Определить узел с максимальным значением среди i, l и r и обозначить его как ma
|
||||
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;
|
||||
}
|
||||
// Если узел i уже максимален или индексы l и r вне границ, дальнейшее просеивание не требуется, выйти
|
||||
if ma == i {
|
||||
break;
|
||||
}
|
||||
// Поменять два узла местами
|
||||
self.swap(i, ma);
|
||||
// Циклическое просеивание вниз
|
||||
i = ma;
|
||||
}
|
||||
}
|
||||
|
||||
/* Вывести кучу (двоичное дерево) */
|
||||
fn print(&self) {
|
||||
print_util::print_heap(self.max_heap.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Инициализация максимальной кучи */
|
||||
let mut max_heap = MaxHeap::new(vec![9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2]);
|
||||
println!("\nПосле построения кучи из входного списка");
|
||||
max_heap.print();
|
||||
|
||||
/* Получение элемента с вершины кучи */
|
||||
let peek = max_heap.peek();
|
||||
if let Some(peek) = peek {
|
||||
println!("\nЭлемент на вершине кучи = {}", peek);
|
||||
}
|
||||
|
||||
/* Добавление элемента в кучу */
|
||||
let val = 7;
|
||||
max_heap.push(val);
|
||||
println!("\nПосле добавления элемента {} в кучу", val);
|
||||
max_heap.print();
|
||||
|
||||
/* Извлечение элемента с вершины кучи */
|
||||
let peek = max_heap.pop();
|
||||
println!("\nПосле извлечения элемента вершины кучи {}", peek);
|
||||
max_heap.print();
|
||||
|
||||
/* Получение размера кучи */
|
||||
let size = max_heap.size();
|
||||
println!("\nКоличество элементов в куче = {}", size);
|
||||
|
||||
/* Проверка, пуста ли куча */
|
||||
let is_empty = max_heap.is_empty();
|
||||
println!("\nПуста ли куча: {}", is_empty);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/* Найти k наибольших элементов массива с помощью кучи */
|
||||
fn top_k_heap(nums: Vec<i32>, k: usize) -> BinaryHeap<Reverse<i32>> {
|
||||
// BinaryHeap — это максимальная куча; с помощью Reverse элементы инвертируются, чтобы реализовать минимальную кучу
|
||||
let mut heap = BinaryHeap::<Reverse<i32>>::new();
|
||||
// Поместить первые k элементов массива в кучу
|
||||
for &num in nums.iter().take(k) {
|
||||
heap.push(Reverse(num));
|
||||
}
|
||||
// Начиная с элемента k+1, поддерживать длину кучи равной k
|
||||
for &num in nums.iter().skip(k) {
|
||||
// Если текущий элемент больше элемента на вершине кучи, извлечь вершину кучи и добавить текущий элемент в кучу
|
||||
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!("Наибольшие {} элементов", 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)
|
||||
*/
|
||||
|
||||
/* Бинарный поиск (двусторонне замкнутый интервал) */
|
||||
fn binary_search(nums: &[i32], target: i32) -> i32 {
|
||||
// Инициализировать двусторонне замкнутый интервал [0, n-1], то есть i и j указывают на первый и последний элементы массива соответственно
|
||||
let mut i = 0;
|
||||
let mut j = nums.len() as i32 - 1;
|
||||
// Цикл завершается, когда диапазон поиска пуст (при i > j диапазон пуст)
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2; // Вычислить индекс середины m
|
||||
if nums[m as usize] < target {
|
||||
// Это означает, что target находится в интервале [m+1, j]
|
||||
i = m + 1;
|
||||
} else if nums[m as usize] > target {
|
||||
// Это означает, что target находится в интервале [i, m-1]
|
||||
j = m - 1;
|
||||
} else {
|
||||
// Целевой элемент найден, вернуть его индекс
|
||||
return m;
|
||||
}
|
||||
}
|
||||
// Целевой элемент не найден, вернуть -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Бинарный поиск (лево замкнутый, право открытый интервал) */
|
||||
fn binary_search_lcro(nums: &[i32], target: i32) -> i32 {
|
||||
// Инициализировать лево замкнутый, право открытый интервал [0, n), то есть i и j указывают на первый элемент массива и позицию сразу за последним элементом соответственно
|
||||
let mut i = 0;
|
||||
let mut j = nums.len() as i32;
|
||||
// Цикл завершается, когда диапазон поиска пуст (при i = j диапазон пуст)
|
||||
while i < j {
|
||||
let m = i + (j - i) / 2; // Вычислить индекс середины m
|
||||
if nums[m as usize] < target {
|
||||
// Это означает, что target находится в интервале [m+1, j)
|
||||
i = m + 1;
|
||||
} else if nums[m as usize] > target {
|
||||
// Это означает, что target находится в интервале [i, m)
|
||||
j = m;
|
||||
} else {
|
||||
// Целевой элемент найден, вернуть его индекс
|
||||
return m;
|
||||
}
|
||||
}
|
||||
// Целевой элемент не найден, вернуть -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
pub fn main() {
|
||||
let target = 6;
|
||||
let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35];
|
||||
|
||||
// Бинарный поиск (двусторонне замкнутый интервал)
|
||||
let mut index = binary_search(&nums, target);
|
||||
println!("Индекс целевого элемента 6 = {index}");
|
||||
|
||||
// Бинарный поиск (лево замкнутый, право открытый интервал)
|
||||
index = binary_search_lcro(&nums, target);
|
||||
println!("Индекс целевого элемента 6 = {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;
|
||||
|
||||
/* Бинарный поиск самого левого target */
|
||||
fn binary_search_left_edge(nums: &[i32], target: i32) -> i32 {
|
||||
// Эквивалентно поиску точки вставки target
|
||||
let i = binary_search_insertion(nums, target);
|
||||
// target не найден, вернуть -1
|
||||
if i == nums.len() as i32 || nums[i as usize] != target {
|
||||
return -1;
|
||||
}
|
||||
// Найти target и вернуть индекс i
|
||||
i
|
||||
}
|
||||
|
||||
/* Бинарный поиск самого правого target */
|
||||
fn binary_search_right_edge(nums: &[i32], target: i32) -> i32 {
|
||||
// Преобразовать задачу в поиск самого левого target + 1
|
||||
let i = binary_search_insertion(nums, target + 1);
|
||||
// j указывает на самый правый target, а i — на первый элемент больше target
|
||||
let j = i - 1;
|
||||
// target не найден, вернуть -1
|
||||
if j == -1 || nums[j as usize] != target {
|
||||
return -1;
|
||||
}
|
||||
// Найти target и вернуть индекс j
|
||||
j
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
// Массив с повторяющимися элементами
|
||||
let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
|
||||
println!("\nМассив nums = {:?}", nums);
|
||||
|
||||
// Бинарный поиск левой и правой границы
|
||||
for target in [6, 7] {
|
||||
let index = binary_search_left_edge(&nums, target);
|
||||
println!("Индекс самого левого элемента {} равен {}", target, index);
|
||||
let index = binary_search_right_edge(&nums, target);
|
||||
println!("Индекс самого правого элемента {} равен {}", target, index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* File: binary_search_insertion.rs
|
||||
* Created Time: 2023-08-30
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
#![allow(unused)]
|
||||
|
||||
/* Бинарный поиск точки вставки (без повторяющихся элементов) */
|
||||
fn binary_search_insertion_simple(nums: &[i32], target: i32) -> i32 {
|
||||
let (mut i, mut j) = (0, nums.len() as i32 - 1); // Инициализировать двусторонне замкнутый интервал [0, n-1]
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2; // Вычислить индекс середины m
|
||||
if nums[m as usize] < target {
|
||||
i = m + 1; // target находится в интервале [m+1, j]
|
||||
} else if nums[m as usize] > target {
|
||||
j = m - 1; // target находится в интервале [i, m-1]
|
||||
} else {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
// target не найден, вернуть точку вставки i
|
||||
i
|
||||
}
|
||||
|
||||
/* Бинарный поиск точки вставки (с повторяющимися элементами) */
|
||||
pub fn binary_search_insertion(nums: &[i32], target: i32) -> i32 {
|
||||
let (mut i, mut j) = (0, nums.len() as i32 - 1); // Инициализировать двусторонне замкнутый интервал [0, n-1]
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2; // Вычислить индекс середины m
|
||||
if nums[m as usize] < target {
|
||||
i = m + 1; // target находится в интервале [m+1, j]
|
||||
} else if nums[m as usize] > target {
|
||||
j = m - 1; // target находится в интервале [i, m-1]
|
||||
} else {
|
||||
j = m - 1; // Первый элемент меньше target находится в интервале [i, m-1]
|
||||
}
|
||||
}
|
||||
// Вернуть точку вставки i
|
||||
i
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
// Массив без повторяющихся элементов
|
||||
let nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35];
|
||||
println!("\nМассив nums = {:?}", nums);
|
||||
// Бинарный поиск точки вставки
|
||||
for target in [6, 9] {
|
||||
let index = binary_search_insertion_simple(&nums, target);
|
||||
println!("Индекс позиции вставки элемента {} равен {}", target, index);
|
||||
}
|
||||
|
||||
// Массив с повторяющимися элементами
|
||||
let nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15];
|
||||
println!("\nМассив nums = {:?}", nums);
|
||||
// Бинарный поиск точки вставки
|
||||
for target in [2, 6, 20] {
|
||||
let index = binary_search_insertion(&nums, target);
|
||||
println!("Индекс позиции вставки элемента {} равен {}", 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;
|
||||
|
||||
/* Хеш-поиск (массив) */
|
||||
fn hashing_search_array<'a>(map: &'a HashMap<i32, usize>, target: i32) -> Option<&'a usize> {
|
||||
// key хеш-таблицы: целевой элемент, value: индекс
|
||||
// Если такого key нет в хеш-таблице, вернуть None
|
||||
map.get(&target)
|
||||
}
|
||||
|
||||
/* Хеш-поиск (связный список) */
|
||||
fn hashing_search_linked_list(
|
||||
map: &HashMap<i32, Rc<RefCell<ListNode<i32>>>>,
|
||||
target: i32,
|
||||
) -> Option<&Rc<RefCell<ListNode<i32>>>> {
|
||||
// key хеш-таблицы: значение целевого узла, value: объект узла
|
||||
// Если такого key нет в хеш-таблице, вернуть None
|
||||
map.get(&target)
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
pub fn main() {
|
||||
let target = 3;
|
||||
|
||||
/* Хеш-поиск (массив) */
|
||||
let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8];
|
||||
// Инициализация хеш-таблицы
|
||||
let mut map = HashMap::new();
|
||||
for (i, num) in nums.iter().enumerate() {
|
||||
map.insert(*num, i); // key: элемент, value: индекс
|
||||
}
|
||||
let index = hashing_search_array(&map, target);
|
||||
println!("Индекс целевого элемента 3 = {}", index.unwrap());
|
||||
|
||||
/* Хеш-поиск (связный список) */
|
||||
let head = ListNode::arr_to_linked_list(&nums);
|
||||
// Инициализировать хеш-таблицу
|
||||
// let mut map1 = HashMap::new();
|
||||
let map1 = ListNode::linked_list_to_hashmap(head);
|
||||
let node = hashing_search_linked_list(&map1, target);
|
||||
println!("Объект узла со значением 3 = {:?}", 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;
|
||||
|
||||
/* Линейный поиск (массив) */
|
||||
fn linear_search_array(nums: &[i32], target: i32) -> i32 {
|
||||
// Обход массива
|
||||
for (i, num) in nums.iter().enumerate() {
|
||||
// Целевой элемент найден, вернуть его индекс
|
||||
if num == &target {
|
||||
return i as i32;
|
||||
}
|
||||
}
|
||||
// Целевой элемент не найден, вернуть -1
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Линейный поиск (связный список) */
|
||||
fn linear_search_linked_list(
|
||||
head: Rc<RefCell<ListNode<i32>>>,
|
||||
target: i32,
|
||||
) -> Option<Rc<RefCell<ListNode<i32>>>> {
|
||||
// Найти целевой узел и вернуть его
|
||||
if head.borrow().val == target {
|
||||
return Some(head);
|
||||
};
|
||||
// Найти целевой узел и вернуть его
|
||||
if let Some(node) = &head.borrow_mut().next {
|
||||
return linear_search_linked_list(node.clone(), target);
|
||||
}
|
||||
// Целевой узел не найден, вернуть None
|
||||
return None;
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
pub fn main() {
|
||||
let target = 3;
|
||||
|
||||
/* Выполнить линейный поиск в массиве */
|
||||
let nums = [1, 5, 3, 2, 4, 7, 5, 9, 10, 8];
|
||||
let index = linear_search_array(&nums, target);
|
||||
println!("Индекс целевого элемента 3 = {}", index);
|
||||
|
||||
/* Выполнить линейный поиск в связном списке */
|
||||
let head = ListNode::arr_to_linked_list(&nums);
|
||||
let node = linear_search_linked_list(head.unwrap(), target);
|
||||
println!("Объект узла со значением 3 = {:?}", 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;
|
||||
|
||||
/* Метод 1: полный перебор */
|
||||
pub fn two_sum_brute_force(nums: &Vec<i32>, target: i32) -> Option<Vec<i32>> {
|
||||
let size = nums.len();
|
||||
// Два вложенных цикла, временная сложность 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
|
||||
}
|
||||
|
||||
/* Метод 2: вспомогательная хеш-таблица */
|
||||
pub fn two_sum_hash_table(nums: &Vec<i32>, target: i32) -> Option<Vec<i32>> {
|
||||
// Вспомогательная хеш-таблица, пространственная сложность O(n)
|
||||
let mut dic = HashMap::new();
|
||||
// Один цикл, временная сложность 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;
|
||||
|
||||
// ====== Основной код ======
|
||||
// Метод 1
|
||||
let res = two_sum_brute_force(&nums, target).unwrap();
|
||||
print!("Результат метода 1 res = ");
|
||||
print_util::print_array(&res);
|
||||
// Метод 2
|
||||
let res = two_sum_hash_table(&nums, target).unwrap();
|
||||
print!("\nРезультат метода 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;
|
||||
|
||||
/* Пузырьковая сортировка */
|
||||
fn bubble_sort(nums: &mut [i32]) {
|
||||
// Внешний цикл: неотсортированный диапазон [0, i]
|
||||
for i in (1..nums.len()).rev() {
|
||||
// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конец
|
||||
for j in 0..i {
|
||||
if nums[j] > nums[j + 1] {
|
||||
// Поменять местами nums[j] и nums[j + 1]
|
||||
nums.swap(j, j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Пузырьковая сортировка (оптимизация флагом) */
|
||||
fn bubble_sort_with_flag(nums: &mut [i32]) {
|
||||
// Внешний цикл: неотсортированный диапазон [0, i]
|
||||
for i in (1..nums.len()).rev() {
|
||||
let mut flag = false; // Инициализировать флаг
|
||||
// Внутренний цикл: переместить максимальный элемент неотсортированного диапазона [0, i] в его правый конец
|
||||
for j in 0..i {
|
||||
if nums[j] > nums[j + 1] {
|
||||
// Поменять местами nums[j] и nums[j + 1]
|
||||
nums.swap(j, j + 1);
|
||||
flag = true; // Записать обмен элементов
|
||||
}
|
||||
}
|
||||
if !flag {
|
||||
break; // На этой итерации «всплытия» не было ни одного обмена, сразу выйти
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
pub fn main() {
|
||||
let mut nums = [4, 1, 3, 1, 5, 2];
|
||||
bubble_sort(&mut nums);
|
||||
print!("После пузырьковой сортировки nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
let mut nums1 = [4, 1, 3, 1, 5, 2];
|
||||
bubble_sort_with_flag(&mut nums1);
|
||||
print!("\nПосле пузырьковой сортировки 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;
|
||||
|
||||
/* Сортировка корзинами */
|
||||
fn bucket_sort(nums: &mut [f64]) {
|
||||
// Инициализировать k = n/2 корзин, предполагая распределение 2 элементов в каждую корзину
|
||||
let k = nums.len() / 2;
|
||||
let mut buckets = vec![vec![]; k];
|
||||
// 1. Распределить элементы массива по корзинам
|
||||
for &num in nums.iter() {
|
||||
// Входные данные лежат в диапазоне [0, 1); использовать num * k для отображения в диапазон индексов [0, k-1]
|
||||
let i = (num * k as f64) as usize;
|
||||
// Добавить num в корзину i
|
||||
buckets[i].push(num);
|
||||
}
|
||||
// 2. Выполнить сортировку внутри каждой корзины
|
||||
for bucket in &mut buckets {
|
||||
// Использовать встроенную функцию сортировки; ее также можно заменить другим алгоритмом сортировки
|
||||
bucket.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
}
|
||||
// 3. Обойти корзины и объединить результаты
|
||||
let mut i = 0;
|
||||
for bucket in buckets.iter() {
|
||||
for &num in bucket.iter() {
|
||||
nums[i] = num;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
// Пусть входные данные — числа с плавающей точкой из диапазона [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!("После сортировки корзинами 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;
|
||||
|
||||
/* Сортировка подсчетом */
|
||||
// Простая реализация, не подходит для сортировки объектов
|
||||
fn counting_sort_naive(nums: &mut [i32]) {
|
||||
// 1. Найти максимальный элемент массива m
|
||||
let m = *nums.iter().max().unwrap();
|
||||
// 2. Подсчитать число появлений каждой цифры
|
||||
// counter[num] обозначает число появлений num
|
||||
let mut counter = vec![0; m as usize + 1];
|
||||
for &num in nums.iter() {
|
||||
counter[num as usize] += 1;
|
||||
}
|
||||
// 3. Обойти counter и заполнить исходный массив nums элементами
|
||||
let mut i = 0;
|
||||
for num in 0..m + 1 {
|
||||
for _ in 0..counter[num as usize] {
|
||||
nums[i] = num;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Сортировка подсчетом */
|
||||
// Полная реализация, позволяет сортировать объекты и является стабильной сортировкой
|
||||
fn counting_sort(nums: &mut [i32]) {
|
||||
// 1. Найти максимальный элемент массива m
|
||||
let m = *nums.iter().max().unwrap() as usize;
|
||||
// 2. Подсчитать число появлений каждой цифры
|
||||
// counter[num] обозначает число появлений num
|
||||
let mut counter = vec![0; m + 1];
|
||||
for &num in nums.iter() {
|
||||
counter[num as usize] += 1;
|
||||
}
|
||||
// 3. Вычислить префиксные суммы counter и преобразовать «число появлений» в «конечный индекс»
|
||||
// То есть counter[num]-1 — это индекс последнего появления num в res
|
||||
for i in 0..m {
|
||||
counter[i + 1] += counter[i];
|
||||
}
|
||||
// 4. Обойти nums в обратном порядке и поместить элементы в результирующий массив res
|
||||
// Инициализировать массив res для хранения результата
|
||||
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; // Поместить num по соответствующему индексу
|
||||
counter[num as usize] -= 1; // Уменьшить префиксную сумму на 1, чтобы получить индекс следующего размещения num
|
||||
}
|
||||
// Перезаписать исходный массив nums массивом результата res
|
||||
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!("После сортировки подсчетом (объекты не поддерживаются) nums = ");
|
||||
print_util::print_array(&nums);
|
||||
|
||||
let mut nums1 = [1, 0, 1, 2, 0, 4, 0, 2, 2, 4];
|
||||
counting_sort(&mut nums1);
|
||||
print!("\nПосле сортировки подсчетом 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;
|
||||
|
||||
/* Длина кучи равна n; начиная с узла i, выполнить просеивание сверху вниз */
|
||||
fn sift_down(nums: &mut [i32], n: usize, mut i: usize) {
|
||||
loop {
|
||||
// Определить узел с максимальным значением среди i, l и r и обозначить его как ma
|
||||
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;
|
||||
}
|
||||
// Если узел i уже максимален или индексы l и r вне границ, дальнейшее просеивание не требуется, выйти
|
||||
if ma == i {
|
||||
break;
|
||||
}
|
||||
// Поменять два узла местами
|
||||
nums.swap(i, ma);
|
||||
// Циклическое просеивание вниз
|
||||
i = ma;
|
||||
}
|
||||
}
|
||||
|
||||
/* Сортировка кучей */
|
||||
fn heap_sort(nums: &mut [i32]) {
|
||||
// Построение кучи: выполнить heapify для всех узлов, кроме листовых
|
||||
for i in (0..nums.len() / 2).rev() {
|
||||
sift_down(nums, nums.len(), i);
|
||||
}
|
||||
// Извлекать максимальный элемент из кучи в течение n-1 итераций
|
||||
for i in (1..nums.len()).rev() {
|
||||
// Поменять корневой узел с самым правым листом местами (поменять первый и последний элементы)
|
||||
nums.swap(0, i);
|
||||
// Начиная с корневого узла, выполнить просеивание сверху вниз
|
||||
sift_down(nums, i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
let mut nums = [4, 1, 3, 1, 5, 2];
|
||||
heap_sort(&mut nums);
|
||||
print!("После сортировки кучей 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;
|
||||
|
||||
/* Сортировка вставками */
|
||||
fn insertion_sort(nums: &mut [i32]) {
|
||||
// Внешний цикл: отсортированный диапазон [0, i-1]
|
||||
for i in 1..nums.len() {
|
||||
let (base, mut j) = (nums[i], (i - 1) as i32);
|
||||
// Внутренний цикл: вставить base в правильную позицию отсортированного диапазона [0, i-1]
|
||||
while j >= 0 && nums[j as usize] > base {
|
||||
nums[(j + 1) as usize] = nums[j as usize]; // Сдвинуть nums[j] на одну позицию вправо
|
||||
j -= 1;
|
||||
}
|
||||
nums[(j + 1) as usize] = base; // Поместить base в правильную позицию
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
let mut nums = [4, 1, 3, 1, 5, 2];
|
||||
insertion_sort(&mut nums);
|
||||
print!("После сортировки вставками nums = ");
|
||||
print_util::print_array(&nums);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* File: merge_sort.rs
|
||||
* Created Time: 2023-02-14
|
||||
* Author: xBLACKICEx (xBLACKICEx@outlook.com)
|
||||
*/
|
||||
|
||||
/* Объединить левый и правый подмассивы */
|
||||
fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) {
|
||||
// Диапазон левого подмассива: [left, mid], диапазон правого подмассива: [mid+1, right]
|
||||
// Создать временный массив tmp для хранения результата слияния
|
||||
let tmp_size = right - left + 1;
|
||||
let mut tmp = vec![0; tmp_size];
|
||||
// Инициализировать начальные индексы левого и правого подмассивов
|
||||
let (mut i, mut j, mut k) = (left, mid + 1, 0);
|
||||
// Пока в левом и правом подмассивах еще есть элементы, сравнивать их и копировать меньший во временный массив
|
||||
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;
|
||||
}
|
||||
// Скопировать оставшиеся элементы левого и правого подмассивов во временный массив
|
||||
while i <= mid {
|
||||
tmp[k] = nums[i];
|
||||
k += 1;
|
||||
i += 1;
|
||||
}
|
||||
while j <= right {
|
||||
tmp[k] = nums[j];
|
||||
k += 1;
|
||||
j += 1;
|
||||
}
|
||||
// Скопировать элементы временного массива tmp обратно в соответствующий диапазон исходного массива nums
|
||||
for k in 0..tmp_size {
|
||||
nums[left + k] = tmp[k];
|
||||
}
|
||||
}
|
||||
|
||||
/* Сортировка слиянием */
|
||||
fn merge_sort(nums: &mut [i32], left: usize, right: usize) {
|
||||
// Условие завершения
|
||||
if left >= right {
|
||||
return; // Завершить рекурсию, когда длина подмассива равна 1
|
||||
}
|
||||
|
||||
// Этап разбиения
|
||||
let mid = left + (right - left) / 2; // Вычислить середину
|
||||
merge_sort(nums, left, mid); // Рекурсивно обработать левый подмассив
|
||||
merge_sort(nums, mid + 1, right); // Рекурсивно обработать правый подмассив
|
||||
|
||||
// Этап слияния
|
||||
merge(nums, left, mid, right);
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Сортировка слиянием */
|
||||
let mut nums = [7, 3, 2, 6, 0, 1, 5, 4];
|
||||
let right = nums.len() - 1;
|
||||
merge_sort(&mut nums, 0, right);
|
||||
println!("После сортировки слиянием nums = {:?}", nums);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* File: quick_sort.rs
|
||||
* Created Time: 2023-02-16
|
||||
* Author: xBLACKICEx (xBLACKICE@outlook.com)
|
||||
*/
|
||||
|
||||
/* Быстрая сортировка */
|
||||
struct QuickSort;
|
||||
|
||||
impl QuickSort {
|
||||
/* Разбиение с опорными указателями */
|
||||
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
|
||||
// Взять nums[left] в качестве опорного элемента
|
||||
let (mut i, mut j) = (left, right);
|
||||
while i < j {
|
||||
while i < j && nums[j] >= nums[left] {
|
||||
j -= 1; // Идти справа налево в поисках первого элемента меньше опорного
|
||||
}
|
||||
while i < j && nums[i] <= nums[left] {
|
||||
i += 1; // Идти слева направо в поисках первого элемента больше опорного
|
||||
}
|
||||
nums.swap(i, j); // Поменять эти два элемента местами
|
||||
}
|
||||
nums.swap(i, left); // Переместить опорный элемент на границу двух подмассивов
|
||||
i // Вернуть индекс опорного элемента
|
||||
}
|
||||
|
||||
/* Быстрая сортировка */
|
||||
pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) {
|
||||
// Завершить рекурсию, когда длина подмассива равна 1
|
||||
if left >= right {
|
||||
return;
|
||||
}
|
||||
// Разбиение с опорными указателями
|
||||
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
|
||||
// Рекурсивно обработать левый и правый подмассивы
|
||||
Self::quick_sort(left, pivot - 1, nums);
|
||||
Self::quick_sort(pivot + 1, right, nums);
|
||||
}
|
||||
}
|
||||
|
||||
/* Быстрая сортировка (оптимизация медианным опорным элементом) */
|
||||
struct QuickSortMedian;
|
||||
|
||||
impl QuickSortMedian {
|
||||
/* Выбрать медиану из трех кандидатов */
|
||||
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 находится между l и r
|
||||
}
|
||||
if (m <= l && l <= r) || (r <= l && l <= m) {
|
||||
return left; // l находится между m и r
|
||||
}
|
||||
right
|
||||
}
|
||||
|
||||
/* Разбиение с опорными указателями (медиана трех) */
|
||||
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
|
||||
// Выбрать медиану из трех кандидатов
|
||||
let med = Self::median_three(nums, left, (left + right) / 2, right);
|
||||
// Переместить медиану в крайний левый элемент массива
|
||||
nums.swap(left, med);
|
||||
// Взять nums[left] в качестве опорного элемента
|
||||
let (mut i, mut j) = (left, right);
|
||||
while i < j {
|
||||
while i < j && nums[j] >= nums[left] {
|
||||
j -= 1; // Идти справа налево в поисках первого элемента меньше опорного
|
||||
}
|
||||
while i < j && nums[i] <= nums[left] {
|
||||
i += 1; // Идти слева направо в поисках первого элемента больше опорного
|
||||
}
|
||||
nums.swap(i, j); // Поменять эти два элемента местами
|
||||
}
|
||||
nums.swap(i, left); // Переместить опорный элемент на границу двух подмассивов
|
||||
i // Вернуть индекс опорного элемента
|
||||
}
|
||||
|
||||
/* Быстрая сортировка */
|
||||
pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) {
|
||||
// Завершить рекурсию, когда длина подмассива равна 1
|
||||
if left >= right {
|
||||
return;
|
||||
}
|
||||
// Разбиение с опорными указателями
|
||||
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
|
||||
// Рекурсивно обработать левый и правый подмассивы
|
||||
Self::quick_sort(left, pivot - 1, nums);
|
||||
Self::quick_sort(pivot + 1, right, nums);
|
||||
}
|
||||
}
|
||||
|
||||
/* Быстрая сортировка (оптимизация глубины рекурсии) */
|
||||
struct QuickSortTailCall;
|
||||
|
||||
impl QuickSortTailCall {
|
||||
/* Разбиение с опорными указателями */
|
||||
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
|
||||
// Взять nums[left] в качестве опорного элемента
|
||||
let (mut i, mut j) = (left, right);
|
||||
while i < j {
|
||||
while i < j && nums[j] >= nums[left] {
|
||||
j -= 1; // Идти справа налево в поисках первого элемента меньше опорного
|
||||
}
|
||||
while i < j && nums[i] <= nums[left] {
|
||||
i += 1; // Идти слева направо в поисках первого элемента больше опорного
|
||||
}
|
||||
nums.swap(i, j); // Поменять эти два элемента местами
|
||||
}
|
||||
nums.swap(i, left); // Переместить опорный элемент на границу двух подмассивов
|
||||
i // Вернуть индекс опорного элемента
|
||||
}
|
||||
|
||||
/* Быстрая сортировка (оптимизация глубины рекурсии) */
|
||||
pub fn quick_sort(mut left: i32, mut right: i32, nums: &mut [i32]) {
|
||||
// Завершить, когда длина подмассива равна 1
|
||||
while left < right {
|
||||
// Операция разбиения с опорными указателями
|
||||
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
|
||||
// Выполнить быструю сортировку для более короткого из двух подмассивов
|
||||
if pivot - left < right - pivot {
|
||||
Self::quick_sort(left, pivot - 1, nums); // Рекурсивно отсортировать левый подмассив
|
||||
left = pivot + 1; // Оставшийся неотсортированный диапазон: [pivot + 1, right]
|
||||
} else {
|
||||
Self::quick_sort(pivot + 1, right, nums); // Рекурсивно отсортировать правый подмассив
|
||||
right = pivot - 1; // Оставшийся неотсортированный диапазон: [left, pivot - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Быстрая сортировка */
|
||||
let mut nums = [2, 4, 1, 0, 3, 5];
|
||||
QuickSort::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
|
||||
println!("После быстрой сортировки nums = {:?}", nums);
|
||||
|
||||
/* Быстрая сортировка (оптимизация медианным опорным элементом) */
|
||||
let mut nums = [2, 4, 1, 0, 3, 5];
|
||||
QuickSortMedian::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
|
||||
println!("После быстрой сортировки (оптимизация медианным опорным элементом) nums = {:?}", nums);
|
||||
|
||||
/* Быстрая сортировка (оптимизация глубины рекурсии) */
|
||||
let mut nums = [2, 4, 1, 0, 3, 5];
|
||||
QuickSortTailCall::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
|
||||
println!("После быстрой сортировки (оптимизация глубины рекурсии) 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;
|
||||
|
||||
/* Получить k-й разряд элемента num, где exp = 10^(k-1) */
|
||||
fn digit(num: i32, exp: i32) -> usize {
|
||||
// Передача exp вместо k позволяет избежать повторного дорогостоящего вычисления степени
|
||||
return ((num / exp) % 10) as usize;
|
||||
}
|
||||
|
||||
/* Сортировка подсчетом (сортировка по k-му разряду nums) */
|
||||
fn counting_sort_digit(nums: &mut [i32], exp: i32) {
|
||||
// Разряды десятичной системы лежат в диапазоне 0~9, поэтому нужен массив корзин длины 10
|
||||
let mut counter = [0; 10];
|
||||
let n = nums.len();
|
||||
// Подсчитать число появлений каждой цифры от 0 до 9
|
||||
for i in 0..n {
|
||||
let d = digit(nums[i], exp); // Получить k-й разряд nums[i], обозначив его как d
|
||||
counter[d] += 1; // Подсчитать число появлений цифры d
|
||||
}
|
||||
// Вычислить префиксные суммы и преобразовать «число появлений» в «индекс массива»
|
||||
for i in 1..10 {
|
||||
counter[i] += counter[i - 1];
|
||||
}
|
||||
// Выполняя обратный проход, заполнить res элементами по статистике в корзинах
|
||||
let mut res = vec![0; n];
|
||||
for i in (0..n).rev() {
|
||||
let d = digit(nums[i], exp);
|
||||
let j = counter[d] - 1; // Получить индекс j цифры d в массиве
|
||||
res[j] = nums[i]; // Поместить текущий элемент по индексу j
|
||||
counter[d] -= 1; // Уменьшить количество d на 1
|
||||
}
|
||||
// Перезаписать исходный массив nums результатом
|
||||
nums.copy_from_slice(&res);
|
||||
}
|
||||
|
||||
/* Поразрядная сортировка */
|
||||
fn radix_sort(nums: &mut [i32]) {
|
||||
// Получить максимальный элемент массива, чтобы определить максимальное число разрядов
|
||||
let m = *nums.into_iter().max().unwrap();
|
||||
// Проходить разряды от младшего к старшему
|
||||
let mut exp = 1;
|
||||
while exp <= m {
|
||||
counting_sort_digit(nums, exp);
|
||||
exp *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
// Поразрядная сортировка
|
||||
let mut nums = [
|
||||
10546151, 35663510, 42865989, 34862445, 81883077, 88906420, 72429244, 30524779, 82060337,
|
||||
63832996,
|
||||
];
|
||||
radix_sort(&mut nums);
|
||||
print!("После поразрядной сортировки 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;
|
||||
|
||||
/* Сортировка выбором */
|
||||
fn selection_sort(nums: &mut [i32]) {
|
||||
if nums.is_empty() {
|
||||
return;
|
||||
}
|
||||
let n = nums.len();
|
||||
// Внешний цикл: неотсортированный диапазон [i, n-1]
|
||||
for i in 0..n - 1 {
|
||||
// Внутренний цикл: найти минимальный элемент в неотсортированном диапазоне
|
||||
let mut k = i;
|
||||
for j in i + 1..n {
|
||||
if nums[j] < nums[k] {
|
||||
k = j; // Записать индекс минимального элемента
|
||||
}
|
||||
}
|
||||
// Поменять этот минимальный элемент местами с первым элементом неотсортированного диапазона
|
||||
nums.swap(i, k);
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
pub fn main() {
|
||||
let mut nums = [4, 1, 3, 1, 5, 2];
|
||||
selection_sort(&mut nums);
|
||||
print!("\nПосле сортировки выбором 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;
|
||||
/* Двусторонняя очередь на основе кольцевого массива */
|
||||
struct ArrayDeque<T> {
|
||||
nums: Vec<T>, // Массив для хранения элементов двусторонней очереди
|
||||
front: usize, // Указатель head, указывающий на первый элемент очереди
|
||||
que_size: usize, // Длина двусторонней очереди
|
||||
}
|
||||
|
||||
impl<T: Copy + Default> ArrayDeque<T> {
|
||||
/* Конструктор */
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
Self {
|
||||
nums: vec![T::default(); capacity],
|
||||
front: 0,
|
||||
que_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/* Получить вместимость двусторонней очереди */
|
||||
pub fn capacity(&self) -> usize {
|
||||
self.nums.len()
|
||||
}
|
||||
|
||||
/* Получение длины двусторонней очереди */
|
||||
pub fn size(&self) -> usize {
|
||||
self.que_size
|
||||
}
|
||||
|
||||
/* Проверка, пуста ли двусторонняя очередь */
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.que_size == 0
|
||||
}
|
||||
|
||||
/* Вычислить индекс в кольцевом массиве */
|
||||
fn index(&self, i: i32) -> usize {
|
||||
// С помощью операции взятия по модулю соединить начало и конец массива
|
||||
// Когда i выходит за конец массива, он возвращается в начало
|
||||
// Когда i выходит за начало массива, он возвращается в конец
|
||||
((i + self.capacity() as i32) % self.capacity() as i32) as usize
|
||||
}
|
||||
|
||||
/* Добавление в голову очереди */
|
||||
pub fn push_first(&mut self, num: T) {
|
||||
if self.que_size == self.capacity() {
|
||||
println!("Двусторонняя очередь заполнена");
|
||||
return;
|
||||
}
|
||||
// Указатель головы сдвигается на одну позицию влево
|
||||
// С помощью операции взятия по модулю front после выхода за начало массива возвращается в хвост
|
||||
self.front = self.index(self.front as i32 - 1);
|
||||
// Добавить num в голову очереди
|
||||
self.nums[self.front] = num;
|
||||
self.que_size += 1;
|
||||
}
|
||||
|
||||
/* Добавление в хвост очереди */
|
||||
pub fn push_last(&mut self, num: T) {
|
||||
if self.que_size == self.capacity() {
|
||||
println!("Двусторонняя очередь заполнена");
|
||||
return;
|
||||
}
|
||||
// Вычислить указатель хвоста, указывающий на индекс хвоста + 1
|
||||
let rear = self.index(self.front as i32 + self.que_size as i32);
|
||||
// Добавить num в хвост очереди
|
||||
self.nums[rear] = num;
|
||||
self.que_size += 1;
|
||||
}
|
||||
|
||||
/* Извлечение из головы очереди */
|
||||
fn pop_first(&mut self) -> T {
|
||||
let num = self.peek_first();
|
||||
// Указатель головы сдвигается на одну позицию назад
|
||||
self.front = self.index(self.front as i32 + 1);
|
||||
self.que_size -= 1;
|
||||
num
|
||||
}
|
||||
|
||||
/* Извлечение из хвоста очереди */
|
||||
fn pop_last(&mut self) -> T {
|
||||
let num = self.peek_last();
|
||||
self.que_size -= 1;
|
||||
num
|
||||
}
|
||||
|
||||
/* Доступ к элементу в начале очереди */
|
||||
fn peek_first(&self) -> T {
|
||||
if self.is_empty() {
|
||||
panic!("двусторонняя очередь пуста")
|
||||
};
|
||||
self.nums[self.front]
|
||||
}
|
||||
|
||||
/* Доступ к элементу в конце очереди */
|
||||
fn peek_last(&self) -> T {
|
||||
if self.is_empty() {
|
||||
panic!("двусторонняя очередь пуста")
|
||||
};
|
||||
// Вычислить индекс хвостового элемента
|
||||
let last = self.index(self.front as i32 + self.que_size as i32 - 1);
|
||||
self.nums[last]
|
||||
}
|
||||
|
||||
/* Вернуть массив для вывода */
|
||||
fn to_array(&self) -> Vec<T> {
|
||||
// Преобразовывать только элементы списка в пределах фактической длины
|
||||
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() {
|
||||
/* Инициализация двусторонней очереди */
|
||||
let mut deque = ArrayDeque::new(10);
|
||||
deque.push_last(3);
|
||||
deque.push_last(2);
|
||||
deque.push_last(5);
|
||||
print!("Двусторонняя очередь deque = ");
|
||||
print_util::print_array(&deque.to_array());
|
||||
|
||||
/* Доступ к элементу */
|
||||
let peek_first = deque.peek_first();
|
||||
print!("\nПервый элемент peek_first = {}", peek_first);
|
||||
let peek_last = deque.peek_last();
|
||||
print!("\nПоследний элемент peek_last = {}", peek_last);
|
||||
|
||||
/* Добавление элемента в очередь */
|
||||
deque.push_last(4);
|
||||
print!("\nПосле добавления элемента 4 в хвост deque = ");
|
||||
print_util::print_array(&deque.to_array());
|
||||
deque.push_first(1);
|
||||
print!("\nПосле добавления элемента 1 в голову deque = ");
|
||||
print_util::print_array(&deque.to_array());
|
||||
|
||||
/* Извлечение элемента из очереди */
|
||||
let pop_last = deque.pop_last();
|
||||
print!("\nИзвлеченный из хвоста элемент = {}, deque после извлечения из хвоста = ", pop_last);
|
||||
print_util::print_array(&deque.to_array());
|
||||
let pop_first = deque.pop_first();
|
||||
print!("\nИзвлеченный из головы элемент = {}, deque после извлечения из головы = ", pop_first);
|
||||
print_util::print_array(&deque.to_array());
|
||||
|
||||
/* Получение длины двусторонней очереди */
|
||||
let size = deque.size();
|
||||
print!("\nДлина двусторонней очереди size = {}", size);
|
||||
|
||||
/* Проверка, пуста ли двусторонняя очередь */
|
||||
let is_empty = deque.is_empty();
|
||||
print!("\nПуста ли двусторонняя очередь = {}", is_empty);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* File: array_queue.rs
|
||||
* Created Time: 2023-02-06
|
||||
* Author: WSL0809 (wslzzy@outlook.com)
|
||||
*/
|
||||
|
||||
/* Очередь на основе кольцевого массива */
|
||||
struct ArrayQueue<T> {
|
||||
nums: Vec<T>, // Массив для хранения элементов очереди
|
||||
front: i32, // Указатель head, указывающий на первый элемент очереди
|
||||
que_size: i32, // Длина очереди
|
||||
que_capacity: i32, // Вместимость очереди
|
||||
}
|
||||
|
||||
impl<T: Copy + Default> ArrayQueue<T> {
|
||||
/* Конструктор */
|
||||
fn new(capacity: i32) -> ArrayQueue<T> {
|
||||
ArrayQueue {
|
||||
nums: vec![T::default(); capacity as usize],
|
||||
front: 0,
|
||||
que_size: 0,
|
||||
que_capacity: capacity,
|
||||
}
|
||||
}
|
||||
|
||||
/* Получить вместимость очереди */
|
||||
fn capacity(&self) -> i32 {
|
||||
self.que_capacity
|
||||
}
|
||||
|
||||
/* Получение длины очереди */
|
||||
fn size(&self) -> i32 {
|
||||
self.que_size
|
||||
}
|
||||
|
||||
/* Проверка, пуста ли очередь */
|
||||
fn is_empty(&self) -> bool {
|
||||
self.que_size == 0
|
||||
}
|
||||
|
||||
/* Поместить в очередь */
|
||||
fn push(&mut self, num: T) {
|
||||
if self.que_size == self.capacity() {
|
||||
println!("Очередь заполнена");
|
||||
return;
|
||||
}
|
||||
// Вычислить указатель хвоста, указывающий на индекс хвоста + 1
|
||||
// С помощью операции взятия по модулю вернуть rear к началу после выхода за конец массива
|
||||
let rear = (self.front + self.que_size) % self.que_capacity;
|
||||
// Добавить num в хвост очереди
|
||||
self.nums[rear as usize] = num;
|
||||
self.que_size += 1;
|
||||
}
|
||||
|
||||
/* Извлечь из очереди */
|
||||
fn pop(&mut self) -> T {
|
||||
let num = self.peek();
|
||||
// Указатель head сдвигается на одну позицию назад; если он выходит за конец, то возвращается в начало массива
|
||||
self.front = (self.front + 1) % self.que_capacity;
|
||||
self.que_size -= 1;
|
||||
num
|
||||
}
|
||||
|
||||
/* Доступ к элементу в начале очереди */
|
||||
fn peek(&self) -> T {
|
||||
if self.is_empty() {
|
||||
panic!("index out of bounds");
|
||||
}
|
||||
self.nums[self.front as usize]
|
||||
}
|
||||
|
||||
/* Вернуть массив */
|
||||
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() {
|
||||
/* Инициализация очереди */
|
||||
let capacity = 10;
|
||||
let mut queue = ArrayQueue::new(capacity);
|
||||
|
||||
/* Добавление элемента в очередь */
|
||||
queue.push(1);
|
||||
queue.push(3);
|
||||
queue.push(2);
|
||||
queue.push(5);
|
||||
queue.push(4);
|
||||
println!("Очередь queue = {:?}", queue.to_vector());
|
||||
|
||||
/* Доступ к элементу в начале очереди */
|
||||
let peek = queue.peek();
|
||||
println!("Первый элемент peek = {}", peek);
|
||||
|
||||
/* Извлечение элемента из очереди */
|
||||
let pop = queue.pop();
|
||||
println!(
|
||||
"Извлеченный элемент pop = {:?}, queue после извлечения = {:?}",
|
||||
pop,
|
||||
queue.to_vector()
|
||||
);
|
||||
|
||||
/* Получение длины очереди */
|
||||
let size = queue.size();
|
||||
println!("Длина очереди size = {}", size);
|
||||
|
||||
/* Проверка, пуста ли очередь */
|
||||
let is_empty = queue.is_empty();
|
||||
println!("Пуста ли очередь = {}", is_empty);
|
||||
|
||||
/* Проверка кольцевого массива */
|
||||
for i in 0..10 {
|
||||
queue.push(i);
|
||||
queue.pop();
|
||||
println!("После {:?}-го раунда операций 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;
|
||||
|
||||
/* Стек на основе массива */
|
||||
struct ArrayStack<T> {
|
||||
stack: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> ArrayStack<T> {
|
||||
/* Инициализация стека */
|
||||
fn new() -> ArrayStack<T> {
|
||||
ArrayStack::<T> {
|
||||
stack: Vec::<T>::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/* Получение длины стека */
|
||||
fn size(&self) -> usize {
|
||||
self.stack.len()
|
||||
}
|
||||
|
||||
/* Проверка, пуст ли стек */
|
||||
fn is_empty(&self) -> bool {
|
||||
self.size() == 0
|
||||
}
|
||||
|
||||
/* Поместить в стек */
|
||||
fn push(&mut self, num: T) {
|
||||
self.stack.push(num);
|
||||
}
|
||||
|
||||
/* Извлечь из стека */
|
||||
fn pop(&mut self) -> Option<T> {
|
||||
self.stack.pop()
|
||||
}
|
||||
|
||||
/* Доступ к верхнему элементу стека */
|
||||
fn peek(&self) -> Option<&T> {
|
||||
if self.is_empty() {
|
||||
panic!("стек пуст")
|
||||
};
|
||||
self.stack.last()
|
||||
}
|
||||
|
||||
/* Вернуть &Vec */
|
||||
fn to_array(&self) -> &Vec<T> {
|
||||
&self.stack
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
// Инициализация стека
|
||||
let mut stack = ArrayStack::<i32>::new();
|
||||
|
||||
// Помещение элемента в стек
|
||||
stack.push(1);
|
||||
stack.push(3);
|
||||
stack.push(2);
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
print!("Стек stack = ");
|
||||
print_util::print_array(stack.to_array());
|
||||
|
||||
// Доступ к верхнему элементу стека
|
||||
let peek = stack.peek().unwrap();
|
||||
print!("\nВерхний элемент peek = {}", peek);
|
||||
|
||||
// Извлечение элемента из стека
|
||||
let pop = stack.pop().unwrap();
|
||||
print!("\nИзвлеченный элемент pop = {pop}, stack после извлечения = ");
|
||||
print_util::print_array(stack.to_array());
|
||||
|
||||
// Получение длины стека
|
||||
let size = stack.size();
|
||||
print!("\nДлина стека size = {size}");
|
||||
|
||||
// Проверка на пустоту
|
||||
let is_empty = stack.is_empty();
|
||||
print!("\nПуст ли стек = {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() {
|
||||
// Инициализация двусторонней очереди
|
||||
let mut deque: VecDeque<i32> = VecDeque::new();
|
||||
deque.push_back(3);
|
||||
deque.push_back(2);
|
||||
deque.push_back(5);
|
||||
print!("Двусторонняя очередь deque = ");
|
||||
print_util::print_queue(&deque);
|
||||
|
||||
// Доступ к элементу
|
||||
let peek_first = deque.front().unwrap();
|
||||
print!("\nПервый элемент peekFirst = {peek_first}");
|
||||
let peek_last = deque.back().unwrap();
|
||||
print!("\nПоследний элемент peekLast = {peek_last}");
|
||||
|
||||
/* Добавление элемента в очередь */
|
||||
deque.push_back(4);
|
||||
print!("\nПосле добавления элемента 4 в хвост deque = ");
|
||||
print_util::print_queue(&deque);
|
||||
deque.push_front(1);
|
||||
print!("\nПосле добавления элемента 1 в голову deque = ");
|
||||
print_util::print_queue(&deque);
|
||||
|
||||
// Извлечение элемента из очереди
|
||||
let pop_last = deque.pop_back().unwrap();
|
||||
print!("\nИзвлеченный из хвоста элемент = {pop_last}, deque после извлечения из хвоста = ");
|
||||
print_util::print_queue(&deque);
|
||||
let pop_first = deque.pop_front().unwrap();
|
||||
print!("\nИзвлеченный из головы элемент = {pop_first}, deque после извлечения из головы = ");
|
||||
print_util::print_queue(&deque);
|
||||
|
||||
// Получение длины двусторонней очереди
|
||||
let size = deque.len();
|
||||
print!("\nДлина двусторонней очереди size = {size}");
|
||||
|
||||
// Проверка, пуста ли двусторонняя очередь
|
||||
let is_empty = deque.is_empty();
|
||||
print!("\nПуста ли двусторонняя очередь = {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;
|
||||
|
||||
/* Узел двусвязного списка */
|
||||
pub struct ListNode<T> {
|
||||
pub val: T, // Значение узла
|
||||
pub next: Option<Rc<RefCell<ListNode<T>>>>, // Указатель на узел-преемник
|
||||
pub prev: 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,
|
||||
prev: None,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/* Двусторонняя очередь на основе двусвязного списка */
|
||||
#[allow(dead_code)]
|
||||
pub struct LinkedListDeque<T> {
|
||||
front: Option<Rc<RefCell<ListNode<T>>>>, // Головной узел front
|
||||
rear: Option<Rc<RefCell<ListNode<T>>>>, // Хвостовой узел rear
|
||||
que_size: usize, // Длина двусторонней очереди
|
||||
}
|
||||
|
||||
impl<T: Copy> LinkedListDeque<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
front: None,
|
||||
rear: None,
|
||||
que_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/* Получение длины двусторонней очереди */
|
||||
pub fn size(&self) -> usize {
|
||||
return self.que_size;
|
||||
}
|
||||
|
||||
/* Проверка, пуста ли двусторонняя очередь */
|
||||
pub fn is_empty(&self) -> bool {
|
||||
return self.que_size == 0;
|
||||
}
|
||||
|
||||
/* Операция добавления в очередь */
|
||||
fn push(&mut self, num: T, is_front: bool) {
|
||||
let node = ListNode::new(num);
|
||||
// Операция добавления в голову очереди
|
||||
if is_front {
|
||||
match self.front.take() {
|
||||
// Если связный список пуст, сделать так, чтобы и front, и rear указывали на node
|
||||
None => {
|
||||
self.rear = Some(node.clone());
|
||||
self.front = Some(node);
|
||||
}
|
||||
// Добавить node в голову списка
|
||||
Some(old_front) => {
|
||||
old_front.borrow_mut().prev = Some(node.clone());
|
||||
node.borrow_mut().next = Some(old_front);
|
||||
self.front = Some(node); // Обновить головной узел
|
||||
}
|
||||
}
|
||||
}
|
||||
// Операция добавления в хвост очереди
|
||||
else {
|
||||
match self.rear.take() {
|
||||
// Если связный список пуст, сделать так, чтобы и front, и rear указывали на node
|
||||
None => {
|
||||
self.front = Some(node.clone());
|
||||
self.rear = Some(node);
|
||||
}
|
||||
// Добавить node в хвост списка
|
||||
Some(old_rear) => {
|
||||
old_rear.borrow_mut().next = Some(node.clone());
|
||||
node.borrow_mut().prev = Some(old_rear);
|
||||
self.rear = Some(node); // Обновить хвостовой узел
|
||||
}
|
||||
}
|
||||
}
|
||||
self.que_size += 1; // Обновить длину очереди
|
||||
}
|
||||
|
||||
/* Добавление в голову очереди */
|
||||
pub fn push_first(&mut self, num: T) {
|
||||
self.push(num, true);
|
||||
}
|
||||
|
||||
/* Добавление в хвост очереди */
|
||||
pub fn push_last(&mut self, num: T) {
|
||||
self.push(num, false);
|
||||
}
|
||||
|
||||
/* Операция извлечения из очереди */
|
||||
fn pop(&mut self, is_front: bool) -> Option<T> {
|
||||
// Если очередь пуста, сразу вернуть None
|
||||
if self.is_empty() {
|
||||
return None;
|
||||
};
|
||||
// Операция извлечения из головы очереди
|
||||
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); // Обновить головной узел
|
||||
}
|
||||
None => {
|
||||
self.rear.take();
|
||||
}
|
||||
}
|
||||
self.que_size -= 1; // Обновить длину очереди
|
||||
old_front.borrow().val
|
||||
})
|
||||
}
|
||||
// Операция извлечения из хвоста очереди
|
||||
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); // Обновить хвостовой узел
|
||||
}
|
||||
None => {
|
||||
self.front.take();
|
||||
}
|
||||
}
|
||||
self.que_size -= 1; // Обновить длину очереди
|
||||
old_rear.borrow().val
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/* Извлечение из головы очереди */
|
||||
pub fn pop_first(&mut self) -> Option<T> {
|
||||
return self.pop(true);
|
||||
}
|
||||
|
||||
/* Извлечение из хвоста очереди */
|
||||
pub fn pop_last(&mut self) -> Option<T> {
|
||||
return self.pop(false);
|
||||
}
|
||||
|
||||
/* Доступ к элементу в начале очереди */
|
||||
pub fn peek_first(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
|
||||
self.front.as_ref()
|
||||
}
|
||||
|
||||
/* Доступ к элементу в конце очереди */
|
||||
pub fn peek_last(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
|
||||
self.rear.as_ref()
|
||||
}
|
||||
|
||||
/* Вернуть массив для вывода */
|
||||
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() {
|
||||
/* Инициализация двусторонней очереди */
|
||||
let mut deque = LinkedListDeque::new();
|
||||
deque.push_last(3);
|
||||
deque.push_last(2);
|
||||
deque.push_last(5);
|
||||
print!("Двусторонняя очередь deque = ");
|
||||
print_util::print_array(&deque.to_array(deque.peek_first()));
|
||||
|
||||
/* Доступ к элементу */
|
||||
let peek_first = deque.peek_first().unwrap().borrow().val;
|
||||
print!("\nПервый элемент peek_first = {}", peek_first);
|
||||
let peek_last = deque.peek_last().unwrap().borrow().val;
|
||||
print!("\nПоследний элемент peek_last = {}", peek_last);
|
||||
|
||||
/* Добавление элемента в очередь */
|
||||
deque.push_last(4);
|
||||
print!("\nПосле добавления элемента 4 в хвост deque = ");
|
||||
print_util::print_array(&deque.to_array(deque.peek_first()));
|
||||
deque.push_first(1);
|
||||
print!("\nПосле добавления элемента 1 в голову deque = ");
|
||||
print_util::print_array(&deque.to_array(deque.peek_first()));
|
||||
|
||||
/* Извлечение элемента из очереди */
|
||||
let pop_last = deque.pop_last().unwrap();
|
||||
print!("\nИзвлеченный из хвоста элемент = {}, deque после извлечения из хвоста = ", pop_last);
|
||||
print_util::print_array(&deque.to_array(deque.peek_first()));
|
||||
let pop_first = deque.pop_first().unwrap();
|
||||
print!("\nИзвлеченный из головы элемент = {}, deque после извлечения из головы = ", pop_first);
|
||||
print_util::print_array(&deque.to_array(deque.peek_first()));
|
||||
|
||||
/* Получение длины двусторонней очереди */
|
||||
let size = deque.size();
|
||||
print!("\nДлина двусторонней очереди size = {}", size);
|
||||
|
||||
/* Проверка, пуста ли двусторонняя очередь */
|
||||
let is_empty = deque.is_empty();
|
||||
print!("\nПуста ли двусторонняя очередь = {}", 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;
|
||||
|
||||
/* Очередь на основе связного списка */
|
||||
#[allow(dead_code)]
|
||||
pub struct LinkedListQueue<T> {
|
||||
front: Option<Rc<RefCell<ListNode<T>>>>, // Головной узел front
|
||||
rear: Option<Rc<RefCell<ListNode<T>>>>, // Хвостовой узел rear
|
||||
que_size: usize, // Длина очереди
|
||||
}
|
||||
|
||||
impl<T: Copy> LinkedListQueue<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
front: None,
|
||||
rear: None,
|
||||
que_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/* Получение длины очереди */
|
||||
pub fn size(&self) -> usize {
|
||||
return self.que_size;
|
||||
}
|
||||
|
||||
/* Проверка, пуста ли очередь */
|
||||
pub fn is_empty(&self) -> bool {
|
||||
return self.que_size == 0;
|
||||
}
|
||||
|
||||
/* Поместить в очередь */
|
||||
pub fn push(&mut self, num: T) {
|
||||
// Добавить num после хвостового узла
|
||||
let new_rear = ListNode::new(num);
|
||||
match self.rear.take() {
|
||||
// Если очередь не пуста, добавить этот узел после хвостового узла
|
||||
Some(old_rear) => {
|
||||
old_rear.borrow_mut().next = Some(new_rear.clone());
|
||||
self.rear = Some(new_rear);
|
||||
}
|
||||
// Если очередь пуста, сделать так, чтобы и head, и tail указывали на этот узел
|
||||
None => {
|
||||
self.front = Some(new_rear.clone());
|
||||
self.rear = Some(new_rear);
|
||||
}
|
||||
}
|
||||
self.que_size += 1;
|
||||
}
|
||||
|
||||
/* Извлечь из очереди */
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
/* Доступ к элементу в начале очереди */
|
||||
pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
|
||||
self.front.as_ref()
|
||||
}
|
||||
|
||||
/* Преобразовать связный список в Array и вернуть */
|
||||
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() {
|
||||
/* Инициализация очереди */
|
||||
let mut queue = LinkedListQueue::new();
|
||||
|
||||
/* Добавление элемента в очередь */
|
||||
queue.push(1);
|
||||
queue.push(3);
|
||||
queue.push(2);
|
||||
queue.push(5);
|
||||
queue.push(4);
|
||||
print!("Очередь queue = ");
|
||||
print_util::print_array(&queue.to_array(queue.peek()));
|
||||
|
||||
/* Доступ к элементу в начале очереди */
|
||||
let peek = queue.peek().unwrap().borrow().val;
|
||||
print!("\nПервый элемент peek = {}", peek);
|
||||
|
||||
/* Извлечение элемента из очереди */
|
||||
let pop = queue.pop().unwrap();
|
||||
print!("\nИзвлеченный элемент pop = {}, queue после извлечения = ", pop);
|
||||
print_util::print_array(&queue.to_array(queue.peek()));
|
||||
|
||||
/* Получение длины очереди */
|
||||
let size = queue.size();
|
||||
print!("\nДлина очереди size = {}", size);
|
||||
|
||||
/* Проверка, пуста ли очередь */
|
||||
let is_empty = queue.is_empty();
|
||||
print!("\nПуста ли очередь = {}", 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;
|
||||
|
||||
/* Стек на основе связного списка */
|
||||
#[allow(dead_code)]
|
||||
pub struct LinkedListStack<T> {
|
||||
stack_peek: Option<Rc<RefCell<ListNode<T>>>>, // Использовать головной узел как вершину стека
|
||||
stk_size: usize, // Длина стека
|
||||
}
|
||||
|
||||
impl<T: Copy> LinkedListStack<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
stack_peek: None,
|
||||
stk_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/* Получение длины стека */
|
||||
pub fn size(&self) -> usize {
|
||||
return self.stk_size;
|
||||
}
|
||||
|
||||
/* Проверка, пуст ли стек */
|
||||
pub fn is_empty(&self) -> bool {
|
||||
return self.size() == 0;
|
||||
}
|
||||
|
||||
/* Поместить в стек */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Извлечь из стека */
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
/* Доступ к верхнему элементу стека */
|
||||
pub fn peek(&self) -> Option<&Rc<RefCell<ListNode<T>>>> {
|
||||
self.stack_peek.as_ref()
|
||||
}
|
||||
|
||||
/* Преобразовать List в Array и вернуть */
|
||||
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() {
|
||||
/* Инициализация стека */
|
||||
let mut stack = LinkedListStack::new();
|
||||
|
||||
/* Помещение элемента в стек */
|
||||
stack.push(1);
|
||||
stack.push(3);
|
||||
stack.push(2);
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
print!("Стек stack = ");
|
||||
print_util::print_array(&stack.to_array());
|
||||
|
||||
/* Доступ к верхнему элементу стека */
|
||||
let peek = stack.peek().unwrap().borrow().val;
|
||||
print!("\nВерхний элемент peek = {}", peek);
|
||||
|
||||
/* Извлечение элемента из стека */
|
||||
let pop = stack.pop().unwrap();
|
||||
print!("\nИзвлеченный элемент pop = {}, stack после извлечения = ", pop);
|
||||
print_util::print_array(&stack.to_array());
|
||||
|
||||
/* Получение длины стека */
|
||||
let size = stack.size();
|
||||
print!("\nДлина стека size = {}", size);
|
||||
|
||||
/* Проверка на пустоту */
|
||||
let is_empty = stack.is_empty();
|
||||
print!("\nПуст ли стек = {}", 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() {
|
||||
// Инициализация очереди
|
||||
let mut queue: VecDeque<i32> = VecDeque::new();
|
||||
|
||||
// Добавление элемента в очередь
|
||||
queue.push_back(1);
|
||||
queue.push_back(3);
|
||||
queue.push_back(2);
|
||||
queue.push_back(5);
|
||||
queue.push_back(4);
|
||||
print!("Очередь queue = ");
|
||||
print_util::print_queue(&queue);
|
||||
|
||||
// Доступ к элементу в начале очереди
|
||||
let peek = queue.front().unwrap();
|
||||
println!("\nПервый элемент peek = {peek}");
|
||||
|
||||
// Извлечение элемента из очереди
|
||||
let pop = queue.pop_front().unwrap();
|
||||
print!("Извлеченный элемент pop = {pop}, queue после извлечения = ");
|
||||
print_util::print_queue(&queue);
|
||||
|
||||
// Получение длины очереди
|
||||
let size = queue.len();
|
||||
print!("\nДлина очереди size = {size}");
|
||||
|
||||
// Проверка, пуста ли очередь
|
||||
let is_empty = queue.is_empty();
|
||||
print!("\nПуста ли очередь = {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() {
|
||||
// Инициализировать стек
|
||||
// В Rust рекомендуется использовать Vec как стек
|
||||
let mut stack: Vec<i32> = Vec::new();
|
||||
|
||||
// Помещение элемента в стек
|
||||
stack.push(1);
|
||||
stack.push(3);
|
||||
stack.push(2);
|
||||
stack.push(5);
|
||||
stack.push(4);
|
||||
print!("Стек stack = ");
|
||||
print_util::print_array(&stack);
|
||||
|
||||
// Доступ к верхнему элементу стека
|
||||
let peek = stack.last().unwrap();
|
||||
print!("\nВерхний элемент peek = {peek}");
|
||||
|
||||
// Извлечение элемента из стека
|
||||
let pop = stack.pop().unwrap();
|
||||
print!("\nИзвлеченный элемент pop = {pop}, stack после извлечения = ");
|
||||
print_util::print_array(&stack);
|
||||
|
||||
// Получение длины стека
|
||||
let size = stack.len();
|
||||
print!("\nДлина стека size = {size}");
|
||||
|
||||
// Проверка, пуст ли стек
|
||||
let is_empty = stack.is_empty();
|
||||
print!("\nПуст ли стек = {is_empty}");
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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};
|
||||
|
||||
/* Класс двоичного дерева в массивном представлении */
|
||||
struct ArrayBinaryTree {
|
||||
tree: Vec<Option<i32>>,
|
||||
}
|
||||
|
||||
impl ArrayBinaryTree {
|
||||
/* Конструктор */
|
||||
fn new(arr: Vec<Option<i32>>) -> Self {
|
||||
Self { tree: arr }
|
||||
}
|
||||
|
||||
/* Вместимость списка */
|
||||
fn size(&self) -> i32 {
|
||||
self.tree.len() as i32
|
||||
}
|
||||
|
||||
/* Получить значение узла с индексом i */
|
||||
fn val(&self, i: i32) -> Option<i32> {
|
||||
// Если индекс выходит за границы, вернуть None, обозначающий пустую позицию
|
||||
if i < 0 || i >= self.size() {
|
||||
None
|
||||
} else {
|
||||
self.tree[i as usize]
|
||||
}
|
||||
}
|
||||
|
||||
/* Получить индекс левого дочернего узла узла с индексом i */
|
||||
fn left(&self, i: i32) -> i32 {
|
||||
2 * i + 1
|
||||
}
|
||||
|
||||
/* Получить индекс правого дочернего узла узла с индексом i */
|
||||
fn right(&self, i: i32) -> i32 {
|
||||
2 * i + 2
|
||||
}
|
||||
|
||||
/* Получить индекс родительского узла узла с индексом i */
|
||||
fn parent(&self, i: i32) -> i32 {
|
||||
(i - 1) / 2
|
||||
}
|
||||
|
||||
/* Обход в ширину */
|
||||
fn level_order(&self) -> Vec<i32> {
|
||||
self.tree.iter().filter_map(|&x| x).collect()
|
||||
}
|
||||
|
||||
/* Обход в глубину */
|
||||
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();
|
||||
// Предварительный обход
|
||||
if order == "pre" {
|
||||
res.push(val);
|
||||
}
|
||||
self.dfs(self.left(i), order, res);
|
||||
// Симметричный обход
|
||||
if order == "in" {
|
||||
res.push(val);
|
||||
}
|
||||
self.dfs(self.right(i), order, res);
|
||||
// Обратный обход
|
||||
if order == "post" {
|
||||
res.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Предварительный обход */
|
||||
fn pre_order(&self) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
self.dfs(0, "pre", &mut res);
|
||||
res
|
||||
}
|
||||
|
||||
/* Симметричный обход */
|
||||
fn in_order(&self) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
self.dfs(0, "in", &mut res);
|
||||
res
|
||||
}
|
||||
|
||||
/* Обратный обход */
|
||||
fn post_order(&self) -> Vec<i32> {
|
||||
let mut res = vec![];
|
||||
self.dfs(0, "post", &mut res);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
// Инициализировать двоичное дерево
|
||||
// Здесь используется функция, напрямую строящая двоичное дерево из массива
|
||||
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!("\nИнициализация двоичного дерева\n");
|
||||
println!("Массивное представление двоичного дерева:");
|
||||
println!(
|
||||
"[{}]",
|
||||
arr.iter()
|
||||
.map(|&val| if let Some(val) = val {
|
||||
format!("{val}")
|
||||
} else {
|
||||
"null".to_string()
|
||||
})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
);
|
||||
println!("Связное представление двоичного дерева:");
|
||||
print_util::print_tree(&root);
|
||||
|
||||
// Класс двоичного дерева в массивном представлении
|
||||
let abt = ArrayBinaryTree::new(arr);
|
||||
|
||||
// Доступ к узлу
|
||||
let i = 1;
|
||||
let l = abt.left(i);
|
||||
let r = abt.right(i);
|
||||
let p = abt.parent(i);
|
||||
println!(
|
||||
"\nТекущий индекс узла = {}, значение = {}",\ni,\nif let Some(val) = abt.val(i) {\n format!("{val}")\n} else {\n "null".to_string()\n}
|
||||
);
|
||||
println!(
|
||||
"Индекс левого дочернего узла = {}, значение = {}",
|
||||
l,
|
||||
if let Some(val) = abt.val(l) {
|
||||
format!("{val}")
|
||||
} else {
|
||||
"null".to_string()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
"Индекс правого дочернего узла = {}, значение = {}",
|
||||
r,
|
||||
if let Some(val) = abt.val(r) {
|
||||
format!("{val}")
|
||||
} else {
|
||||
"null".to_string()
|
||||
}
|
||||
);
|
||||
println!(
|
||||
"Индекс родительского узла = {}, значение = {}",
|
||||
p,
|
||||
if let Some(val) = abt.val(p) {
|
||||
format!("{val}")
|
||||
} else {
|
||||
"null".to_string()
|
||||
}
|
||||
);
|
||||
|
||||
// Обходить дерево
|
||||
let mut res = abt.level_order();
|
||||
println!("\nОбход в ширину: {:?}", res);
|
||||
res = abt.pre_order();
|
||||
println!("Предварительный обход: {:?}", res);
|
||||
res = abt.in_order();
|
||||
println!("Симметричный обход: {:?}", res);
|
||||
res = abt.post_order();
|
||||
println!("Обратный обход: {:?}", res);
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 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-дерево */
|
||||
struct AVLTree {
|
||||
root: OptionTreeNodeRc, // Корневой узел
|
||||
}
|
||||
|
||||
impl AVLTree {
|
||||
/* Конструктор */
|
||||
fn new() -> Self {
|
||||
Self { root: None }
|
||||
}
|
||||
|
||||
/* Получить высоту узла */
|
||||
fn height(node: OptionTreeNodeRc) -> i32 {
|
||||
// Высота пустого узла равна -1, высота листового узла равна 0
|
||||
match node {
|
||||
Some(node) => node.borrow().height,
|
||||
None => -1,
|
||||
}
|
||||
}
|
||||
|
||||
/* Обновить высоту узла */
|
||||
fn update_height(node: OptionTreeNodeRc) {
|
||||
if let Some(node) = node {
|
||||
let left = node.borrow().left.clone();
|
||||
let right = node.borrow().right.clone();
|
||||
// Высота узла равна высоте более высокого поддерева + 1
|
||||
node.borrow_mut().height = std::cmp::max(Self::height(left), Self::height(right)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Получить коэффициент баланса */
|
||||
fn balance_factor(node: OptionTreeNodeRc) -> i32 {
|
||||
match node {
|
||||
// Коэффициент баланса пустого узла равен 0
|
||||
None => 0,
|
||||
// Коэффициент баланса узла = высота левого поддерева - высота правого поддерева
|
||||
Some(node) => {
|
||||
Self::height(node.borrow().left.clone()) - Self::height(node.borrow().right.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Операция правого вращения */
|
||||
fn right_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
|
||||
match node {
|
||||
Some(node) => {
|
||||
let child = node.borrow().left.clone().unwrap();
|
||||
let grand_child = child.borrow().right.clone();
|
||||
// Выполнить правое вращение узла node вокруг child
|
||||
child.borrow_mut().right = Some(node.clone());
|
||||
node.borrow_mut().left = grand_child;
|
||||
// Обновить высоту узла
|
||||
Self::update_height(Some(node));
|
||||
Self::update_height(Some(child.clone()));
|
||||
// Вернуть корневой узел поддерева после вращения
|
||||
Some(child)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/* Операция левого вращения */
|
||||
fn left_rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
|
||||
match node {
|
||||
Some(node) => {
|
||||
let child = node.borrow().right.clone().unwrap();
|
||||
let grand_child = child.borrow().left.clone();
|
||||
// Выполнить левое вращение узла node вокруг child
|
||||
child.borrow_mut().left = Some(node.clone());
|
||||
node.borrow_mut().right = grand_child;
|
||||
// Обновить высоту узла
|
||||
Self::update_height(Some(node));
|
||||
Self::update_height(Some(child.clone()));
|
||||
// Вернуть корневой узел поддерева после вращения
|
||||
Some(child)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/* Выполнить вращение, чтобы снова сбалансировать поддерево */
|
||||
fn rotate(node: OptionTreeNodeRc) -> OptionTreeNodeRc {
|
||||
// Получить коэффициент баланса узла node
|
||||
let balance_factor = Self::balance_factor(node.clone());
|
||||
// Левосторонне перекошенное дерево
|
||||
if balance_factor > 1 {
|
||||
let node = node.unwrap();
|
||||
if Self::balance_factor(node.borrow().left.clone()) >= 0 {
|
||||
// Правое вращение
|
||||
Self::right_rotate(Some(node))
|
||||
} else {
|
||||
// Сначала левое вращение, затем правое
|
||||
let left = node.borrow().left.clone();
|
||||
node.borrow_mut().left = Self::left_rotate(left);
|
||||
Self::right_rotate(Some(node))
|
||||
}
|
||||
}
|
||||
// Правосторонне перекошенное дерево
|
||||
else if balance_factor < -1 {
|
||||
let node = node.unwrap();
|
||||
if Self::balance_factor(node.borrow().right.clone()) <= 0 {
|
||||
// Левое вращение
|
||||
Self::left_rotate(Some(node))
|
||||
} else {
|
||||
// Сначала правое вращение, затем левое
|
||||
let right = node.borrow().right.clone();
|
||||
node.borrow_mut().right = Self::right_rotate(right);
|
||||
Self::left_rotate(Some(node))
|
||||
}
|
||||
} else {
|
||||
// Дерево сбалансировано, вращение не требуется, вернуть сразу
|
||||
node
|
||||
}
|
||||
}
|
||||
|
||||
/* Вставка узла */
|
||||
fn insert(&mut self, val: i32) {
|
||||
self.root = Self::insert_helper(self.root.clone(), val);
|
||||
}
|
||||
|
||||
/* Рекурсивная вставка узла (вспомогательный метод) */
|
||||
fn insert_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc {
|
||||
match node {
|
||||
Some(mut node) => {
|
||||
/* 1. Найти позицию вставки и вставить узел */
|
||||
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); // Повторяющийся узел не вставлять, сразу вернуть
|
||||
}
|
||||
}
|
||||
Self::update_height(Some(node.clone())); // Обновить высоту узла
|
||||
|
||||
/* 2. Выполнить вращение, чтобы снова сбалансировать поддерево */
|
||||
node = Self::rotate(Some(node)).unwrap();
|
||||
// Вернуть корневой узел поддерева
|
||||
Some(node)
|
||||
}
|
||||
None => Some(TreeNode::new(val)),
|
||||
}
|
||||
}
|
||||
|
||||
/* Удаление узла */
|
||||
fn remove(&self, val: i32) {
|
||||
Self::remove_helper(self.root.clone(), val);
|
||||
}
|
||||
|
||||
/* Рекурсивное удаление узла (вспомогательный метод) */
|
||||
fn remove_helper(node: OptionTreeNodeRc, val: i32) -> OptionTreeNodeRc {
|
||||
match node {
|
||||
Some(mut node) => {
|
||||
/* 1. Найти узел и удалить его */
|
||||
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 {
|
||||
// Число дочерних узлов = 0, удалить node и сразу вернуть
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
// Число дочерних узлов = 1, удалить node напрямую
|
||||
Some(child) => node = child,
|
||||
}
|
||||
} else {
|
||||
// Число дочерних узлов = 2, удалить следующий по симметричному обходу узел и заменить им текущий узел
|
||||
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())); // Обновить высоту узла
|
||||
|
||||
/* 2. Выполнить вращение, чтобы снова сбалансировать поддерево */
|
||||
node = Self::rotate(Some(node)).unwrap();
|
||||
// Вернуть корневой узел поддерева
|
||||
Some(node)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
/* Поиск узла */
|
||||
fn search(&self, val: i32) -> OptionTreeNodeRc {
|
||||
let mut cur = self.root.clone();
|
||||
// Искать в цикле и выйти после прохода за листовой узел
|
||||
while let Some(current) = cur.clone() {
|
||||
match current.borrow().val.cmp(&val) {
|
||||
// Целевой узел находится в правом поддереве cur
|
||||
Ordering::Less => {
|
||||
cur = current.borrow().right.clone();
|
||||
}
|
||||
// Целевой узел находится в левом поддереве cur
|
||||
Ordering::Greater => {
|
||||
cur = current.borrow().left.clone();
|
||||
}
|
||||
// Найти целевой узел и выйти из цикла
|
||||
Ordering::Equal => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Вернуть целевой узел
|
||||
cur
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
fn test_insert(tree: &mut AVLTree, val: i32) {
|
||||
tree.insert(val);
|
||||
println!("\nПосле вставки узла {} AVL-дерево имеет вид", val);
|
||||
print_util::print_tree(&tree.root.clone().unwrap());
|
||||
}
|
||||
|
||||
fn test_remove(tree: &mut AVLTree, val: i32) {
|
||||
tree.remove(val);
|
||||
println!("\nПосле удаления узла {} AVL-дерево имеет вид", val);
|
||||
print_util::print_tree(&tree.root.clone().unwrap());
|
||||
}
|
||||
|
||||
/* Инициализация пустого AVL-дерева */
|
||||
let mut avl_tree = AVLTree::new();
|
||||
|
||||
/* Вставка узла */
|
||||
// Обратите внимание, как AVL-дерево сохраняет баланс после вставки узла
|
||||
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);
|
||||
|
||||
/* Вставка повторяющегося узла */
|
||||
test_insert(&mut avl_tree, 7);
|
||||
|
||||
/* Удаление узла */
|
||||
// Обратите внимание, как AVL-дерево сохраняет баланс после удаления узла
|
||||
test_remove(&mut avl_tree, 8); // Удаление узла степени 0
|
||||
test_remove(&mut avl_tree, 5); // Удаление узла степени 1
|
||||
test_remove(&mut avl_tree, 4); // Удаление узла степени 2
|
||||
|
||||
/* Поиск узла */
|
||||
let node = avl_tree.search(7);
|
||||
if let Some(node) = node {
|
||||
println!(
|
||||
"\nНайденный объект узла = {:?}, значение узла = {}",\n&*node.borrow(),\nnode.borrow().val
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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>>>;
|
||||
|
||||
/* Двоичное дерево поиска */
|
||||
pub struct BinarySearchTree {
|
||||
root: OptionTreeNodeRc,
|
||||
}
|
||||
|
||||
impl BinarySearchTree {
|
||||
/* Конструктор */
|
||||
pub fn new() -> Self {
|
||||
// Инициализировать пустое дерево
|
||||
Self { root: None }
|
||||
}
|
||||
|
||||
/* Получить корневой узел двоичного дерева */
|
||||
pub fn get_root(&self) -> OptionTreeNodeRc {
|
||||
self.root.clone()
|
||||
}
|
||||
|
||||
/* Поиск узла */
|
||||
pub fn search(&self, num: i32) -> OptionTreeNodeRc {
|
||||
let mut cur = self.root.clone();
|
||||
// Искать в цикле и выйти после прохода за листовой узел
|
||||
while let Some(node) = cur.clone() {
|
||||
match num.cmp(&node.borrow().val) {
|
||||
// Целевой узел находится в правом поддереве cur
|
||||
Ordering::Greater => cur = node.borrow().right.clone(),
|
||||
// Целевой узел находится в левом поддереве cur
|
||||
Ordering::Less => cur = node.borrow().left.clone(),
|
||||
// Найти целевой узел и выйти из цикла
|
||||
Ordering::Equal => break,
|
||||
}
|
||||
}
|
||||
|
||||
// Вернуть целевой узел
|
||||
cur
|
||||
}
|
||||
|
||||
/* Вставка узла */
|
||||
pub fn insert(&mut self, num: i32) {
|
||||
// Если дерево пусто, инициализировать корневой узел
|
||||
if self.root.is_none() {
|
||||
self.root = Some(TreeNode::new(num));
|
||||
return;
|
||||
}
|
||||
let mut cur = self.root.clone();
|
||||
let mut pre = None;
|
||||
// Искать в цикле и выйти после прохода за листовой узел
|
||||
while let Some(node) = cur.clone() {
|
||||
match num.cmp(&node.borrow().val) {
|
||||
// Найти повторяющийся узел и сразу вернуть
|
||||
Ordering::Equal => return,
|
||||
// Позиция вставки находится в правом поддереве cur
|
||||
Ordering::Greater => {
|
||||
pre = cur.clone();
|
||||
cur = node.borrow().right.clone();
|
||||
}
|
||||
// Позиция вставки находится в левом поддереве cur
|
||||
Ordering::Less => {
|
||||
pre = cur.clone();
|
||||
cur = node.borrow().left.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Вставка узла
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Удаление узла */
|
||||
pub fn remove(&mut self, num: i32) {
|
||||
// Если дерево пусто, сразу вернуть
|
||||
if self.root.is_none() {
|
||||
return;
|
||||
}
|
||||
let mut cur = self.root.clone();
|
||||
let mut pre = None;
|
||||
// Искать в цикле и выйти после прохода за листовой узел
|
||||
while let Some(node) = cur.clone() {
|
||||
match num.cmp(&node.borrow().val) {
|
||||
// Найти узел для удаления и выйти из цикла
|
||||
Ordering::Equal => break,
|
||||
// Узел для удаления находится в правом поддереве cur
|
||||
Ordering::Greater => {
|
||||
pre = cur.clone();
|
||||
cur = node.borrow().right.clone();
|
||||
}
|
||||
// Узел для удаления находится в левом поддереве cur
|
||||
Ordering::Less => {
|
||||
pre = cur.clone();
|
||||
cur = node.borrow().left.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Если узел для удаления отсутствует, сразу вернуть
|
||||
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()) {
|
||||
// Число дочерних узлов = 0 или 1
|
||||
(None, None) | (Some(_), None) | (None, Some(_)) => {
|
||||
// Когда число дочерних узлов = 0 / 1, child = nullptr / этот дочерний узел
|
||||
let child = left_child.or(right_child);
|
||||
let pre = pre.unwrap();
|
||||
// Удалить узел 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 {
|
||||
// Если удаляемый узел является корнем, заново назначить корневой узел
|
||||
self.root = child;
|
||||
}
|
||||
}
|
||||
// Число дочерних узлов = 2
|
||||
(Some(_), Some(_)) => {
|
||||
// Получить следующий узел после cur в симметричном обходе
|
||||
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;
|
||||
// Рекурсивно удалить узел tmp
|
||||
self.remove(tmp_val);
|
||||
// Перезаписать cur значением tmp
|
||||
cur.borrow_mut().val = tmp_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Инициализация двоичного дерева поиска */
|
||||
let mut bst = BinarySearchTree::new();
|
||||
// Обратите внимание: разные порядки вставки порождают разные двоичные деревья; данная последовательность может построить совершенное двоичное дерево
|
||||
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!("\nИсходное двоичное дерево\n");
|
||||
print_util::print_tree(bst.get_root().as_ref().unwrap());
|
||||
|
||||
/* Найти узел */
|
||||
let node = bst.search(7);
|
||||
println!(
|
||||
"\nНайденный объект узла = {:?}, значение узла = {}",\nnode.clone().unwrap(),\nnode.clone().unwrap().borrow().val
|
||||
);
|
||||
|
||||
/* Вставка узла */
|
||||
bst.insert(16);
|
||||
println!("\nПосле вставки узла 16 двоичное дерево имеет вид\n");
|
||||
print_util::print_tree(bst.get_root().as_ref().unwrap());
|
||||
|
||||
/* Удаление узла */
|
||||
bst.remove(1);
|
||||
println!("\nПосле удаления узла 1 двоичное дерево имеет вид\n");
|
||||
print_util::print_tree(bst.get_root().as_ref().unwrap());
|
||||
bst.remove(2);
|
||||
println!("\nПосле удаления узла 2 двоичное дерево имеет вид\n");
|
||||
print_util::print_tree(bst.get_root().as_ref().unwrap());
|
||||
bst.remove(4);
|
||||
println!("\nПосле удаления узла 4 двоичное дерево имеет вид\n");
|
||||
print_util::print_tree(bst.get_root().as_ref().unwrap());
|
||||
}
|
||||
@@ -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() {
|
||||
/* Инициализация двоичного дерева */
|
||||
// Инициализация узла
|
||||
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);
|
||||
// Построить связи между узлами (указатели)
|
||||
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!("\nИнициализация двоичного дерева\n");
|
||||
print_util::print_tree(&n1);
|
||||
|
||||
// Вставка и удаление узлов
|
||||
let p = TreeNode::new(0);
|
||||
// Вставить узел P между n1 -> n2
|
||||
p.borrow_mut().left = Some(Rc::clone(&n2));
|
||||
n1.borrow_mut().left = Some(Rc::clone(&p));
|
||||
println!("\nПосле вставки узла P\n");
|
||||
print_util::print_tree(&n1);
|
||||
// Удалить узел P
|
||||
drop(p);
|
||||
n1.borrow_mut().left = Some(Rc::clone(&n2));
|
||||
println!("\nПосле удаления узла 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};
|
||||
|
||||
/* Обход в ширину */
|
||||
fn level_order(root: &Rc<RefCell<TreeNode>>) -> Vec<i32> {
|
||||
// Инициализировать очередь и добавить корневой узел
|
||||
let mut que = VecDeque::new();
|
||||
que.push_back(root.clone());
|
||||
// Инициализировать список для хранения последовательности обхода
|
||||
let mut vec = Vec::new();
|
||||
|
||||
while let Some(node) = que.pop_front() {
|
||||
// Извлечение из очереди
|
||||
vec.push(node.borrow().val); // Сохранить значение узла
|
||||
if let Some(left) = node.borrow().left.as_ref() {
|
||||
que.push_back(left.clone()); // Поместить левый дочерний узел в очередь
|
||||
}
|
||||
if let Some(right) = node.borrow().right.as_ref() {
|
||||
que.push_back(right.clone()); // Поместить правый дочерний узел в очередь
|
||||
};
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
/* Driver Code */
|
||||
fn main() {
|
||||
/* Инициализация двоичного дерева */
|
||||
// Здесь используется функция, напрямую строящая двоичное дерево из массива
|
||||
let root = vec_to_tree(op_vec![1, 2, 3, 4, 5, 6, 7]).unwrap();
|
||||
println!("Инициализация двоичного дерева\n");
|
||||
print_util::print_tree(&root);
|
||||
|
||||
/* Обход в ширину */
|
||||
let vec = level_order(&root);
|
||||
print!("\nПоследовательность печати узлов при обходе в ширину = {:?}", 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;
|
||||
|
||||
/* Предварительный обход */
|
||||
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 {
|
||||
// Порядок обхода: корень -> левое поддерево -> правое поддерево
|
||||
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
|
||||
}
|
||||
|
||||
/* Симметричный обход */
|
||||
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 {
|
||||
// Порядок обхода: левое поддерево -> корень -> правое поддерево
|
||||
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
|
||||
}
|
||||
|
||||
/* Обратный обход */
|
||||
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 {
|
||||
// Порядок обхода: левое поддерево -> правое поддерево -> корень
|
||||
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() {
|
||||
/* Инициализация двоичного дерева */
|
||||
// Здесь используется функция, напрямую строящая двоичное дерево из массива
|
||||
let root = vec_to_tree(op_vec![1, 2, 3, 4, 5, 6, 7]);
|
||||
println!("Инициализация двоичного дерева\n");
|
||||
print_util::print_tree(root.as_ref().unwrap());
|
||||
|
||||
/* Предварительный обход */
|
||||
let vec = pre_order(root.as_ref());
|
||||
println!("\nПоследовательность печати узлов при предварительном обходе = {:?}", vec);
|
||||
|
||||
/* Симметричный обход */
|
||||
let vec = in_order(root.as_ref());
|
||||
println!("\nПоследовательность печати узлов при симметричном обходе = {:?}", vec);
|
||||
|
||||
/* Обратный обход */
|
||||
let vec = post_order(root.as_ref());
|
||||
print!("\nПоследовательность печати узлов при обратном обходе = {:?}", vec);
|
||||
}
|
||||
@@ -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 }))
|
||||
}
|
||||
|
||||
/* Десериализовать массив в связный список */
|
||||
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
|
||||
}
|
||||
|
||||
/* Преобразовать связный список в хеш-таблицу */
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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::*;
|
||||
@@ -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>,
|
||||
}
|
||||
|
||||
/* Вывести массив */
|
||||
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!("]");
|
||||
}
|
||||
}
|
||||
|
||||
/* Вывести хеш-таблицу */
|
||||
pub fn print_hash_map<TKey: Display, TValue: Display>(map: &HashMap<TKey, TValue>) {
|
||||
for (key, value) in map {
|
||||
println!("{key} -> {value}");
|
||||
}
|
||||
}
|
||||
|
||||
/* Вывести очередь (двустороннюю очередь) */
|
||||
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 {", "} );
|
||||
}
|
||||
}
|
||||
|
||||
/* Вывести связный список */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Вывести двоичное дерево */
|
||||
pub fn print_tree(root: &Rc<RefCell<TreeNode>>) {
|
||||
_print_tree(Some(root), None, false);
|
||||
}
|
||||
|
||||
/* Вывести двоичное дерево */
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/* Вывести кучу */
|
||||
pub fn print_heap(heap: Vec<i32>) {
|
||||
println!("Массивное представление кучи: {:?}", heap);
|
||||
println!("Древовидное представление кучи:");
|
||||
if let Some(root) = vec_to_tree(heap.into_iter().map(|val| Some(val)).collect()) {
|
||||
print_tree(&root);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/* Тип узла двоичного дерева */
|
||||
#[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 {
|
||||
/* Конструктор */
|
||||
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)),*
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// Правила кодирования сериализации см.:
|
||||
// https://www.hello-algo.com/chapter_tree/array_representation_of_tree/
|
||||
// Массивное представление двоичного дерева:
|
||||
// [1, 2, 3, 4, None, 6, 7, 8, 9, None, None, 12, None, None, 15]
|
||||
// Связное представление двоичного дерева:
|
||||
// /——— 15
|
||||
// /——— 7
|
||||
// /——— 3
|
||||
// | \——— 6
|
||||
// | \——— 12
|
||||
// ——— 1
|
||||
// \——— 2
|
||||
// | /——— 9
|
||||
// \——— 4
|
||||
// \——— 8
|
||||
|
||||
/* Десериализовать список в двоичное дерево: рекурсия */
|
||||
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)
|
||||
}
|
||||
|
||||
/* Десериализовать список в двоичное дерево */
|
||||
pub fn vec_to_tree(arr: Vec<Option<i32>>) -> Option<Rc<RefCell<TreeNode>>> {
|
||||
vec_to_tree_dfs(&arr, 0)
|
||||
}
|
||||
|
||||
/* Сериализовать двоичное дерево в список: рекурсия */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Сериализовать двоичное дерево в список */
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* File: vertex.rs
|
||||
* Created Time: 2023-07-13
|
||||
* Author: night-cruise (2586447362@qq.com)
|
||||
*/
|
||||
|
||||
/* Тип вершины */
|
||||
#[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 }
|
||||
}
|
||||
}
|
||||
|
||||
/* На вход подается список значений vals, на выходе возвращается список вершин vets */
|
||||
pub fn vals_to_vets(vals: Vec<i32>) -> Vec<Vertex> {
|
||||
vals.into_iter().map(|val| val.into()).collect()
|
||||
}
|
||||
|
||||
/* На вход подается список вершин vets, на выходе возвращается список значений vals */
|
||||
pub fn vets_to_vals(vets: Vec<Vertex>) -> Vec<i32> {
|
||||
vets.into_iter().map(|vet| vet.val).collect()
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod include;
|
||||
Reference in New Issue
Block a user