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:
Yudong Jin
2026-03-28 04:24:07 +08:00
committed by GitHub
parent 2ca570cc33
commit 772183705e
1958 changed files with 108186 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
target/
Cargo.lock
+413
View File
@@ -0,0 +1,413 @@
[package]
name = "hello-algo-rust"
version = "0.1.0"
edition = "2021"
publish = false
# Run Command: cargo run --bin time_complexity
[[bin]]
name = "time_complexity"
path = "chapter_computational_complexity/time_complexity.rs"
# Run Command: cargo run --bin worst_best_time_complexity
[[bin]]
name = "worst_best_time_complexity"
path = "chapter_computational_complexity/worst_best_time_complexity.rs"
# Run Command: cargo run --bin space_complexity
[[bin]]
name = "space_complexity"
path = "chapter_computational_complexity/space_complexity.rs"
# Run Command: cargo run --bin iteration
[[bin]]
name = "iteration"
path = "chapter_computational_complexity/iteration.rs"
# Run Command: cargo run --bin recursion
[[bin]]
name = "recursion"
path = "chapter_computational_complexity/recursion.rs"
# Run Command: cargo run --bin two_sum
[[bin]]
name = "two_sum"
path = "chapter_searching/two_sum.rs"
# Run Command: cargo run --bin array
[[bin]]
name = "array"
path = "chapter_array_and_linkedlist/array.rs"
# Run Command: cargo run --bin linked_list
[[bin]]
name = "linked_list"
path = "chapter_array_and_linkedlist/linked_list.rs"
# Run Command: cargo run --bin list
[[bin]]
name = "list"
path = "chapter_array_and_linkedlist/list.rs"
# Run Command: cargo run --bin my_list
[[bin]]
name = "my_list"
path = "chapter_array_and_linkedlist/my_list.rs"
# Run Command: cargo run --bin stack
[[bin]]
name = "stack"
path = "chapter_stack_and_queue/stack.rs"
# Run Command: cargo run --bin linkedlist_stack
[[bin]]
name = "linkedlist_stack"
path = "chapter_stack_and_queue/linkedlist_stack.rs"
# Run Command: cargo run --bin queue
[[bin]]
name = "queue"
path = "chapter_stack_and_queue/queue.rs"
# Run Command: cargo run --bin linkedlist_queue
[[bin]]
name = "linkedlist_queue"
path = "chapter_stack_and_queue/linkedlist_queue.rs"
# Run Command: cargo run --bin deque
[[bin]]
name = "deque"
path = "chapter_stack_and_queue/deque.rs"
# Run Command: cargo run --bin array_deque
[[bin]]
name = "array_deque"
path = "chapter_stack_and_queue/array_deque.rs"
# Run Command: cargo run --bin linkedlist_deque
[[bin]]
name = "linkedlist_deque"
path = "chapter_stack_and_queue/linkedlist_deque.rs"
# Run Command: cargo run --bin simple_hash
[[bin]]
name = "simple_hash"
path = "chapter_hashing/simple_hash.rs"
# Run Command: cargo run --bin hash_map
[[bin]]
name = "hash_map"
path = "chapter_hashing/hash_map.rs"
# Run Command: cargo run --bin array_hash_map
[[bin]]
name = "array_hash_map"
path = "chapter_hashing/array_hash_map.rs"
# Run Command: cargo run --bin build_in_hash
[[bin]]
name = "build_in_hash"
path = "chapter_hashing/build_in_hash.rs"
# Run Command: cargo run --bin hash_map_chaining
[[bin]]
name = "hash_map_chaining"
path = "chapter_hashing/hash_map_chaining.rs"
# Run Command: cargo run --bin hash_map_open_addressing
[[bin]]
name = "hash_map_open_addressing"
path = "chapter_hashing/hash_map_open_addressing.rs"
# Run Command: cargo run --bin binary_search
[[bin]]
name = "binary_search"
path = "chapter_searching/binary_search.rs"
# Run Command: cargo run --bin binary_search_edge
[[bin]]
name = "binary_search_edge"
path = "chapter_searching/binary_search_edge.rs"
# Run Command: cargo run --bin binary_search_insertion
[[bin]]
name = "binary_search_insertion"
path = "chapter_searching/binary_search_insertion.rs"
# Run Command: cargo run --bin bubble_sort
[[bin]]
name = "bubble_sort"
path = "chapter_sorting/bubble_sort.rs"
# Run Command: cargo run --bin insertion_sort
[[bin]]
name = "insertion_sort"
path = "chapter_sorting/insertion_sort.rs"
# Run Command: cargo run --bin quick_sort
[[bin]]
name = "quick_sort"
path = "chapter_sorting/quick_sort.rs"
# Run Command: cargo run --bin merge_sort
[[bin]]
name = "merge_sort"
path = "chapter_sorting/merge_sort.rs"
# Run Command: cargo run --bin selection_sort
[[bin]]
name = "selection_sort"
path = "chapter_sorting/selection_sort.rs"
# Run Command: cargo run --bin bucket_sort
[[bin]]
name = "bucket_sort"
path = "chapter_sorting/bucket_sort.rs"
# Run Command: cargo run --bin heap_sort
[[bin]]
name = "heap_sort"
path = "chapter_sorting/heap_sort.rs"
# Run Command: cargo run --bin counting_sort
[[bin]]
name = "counting_sort"
path = "chapter_sorting/counting_sort.rs"
# Run Command: cargo run --bin radix_sort
[[bin]]
name = "radix_sort"
path = "chapter_sorting/radix_sort.rs"
# Run Command: cargo run --bin array_stack
[[bin]]
name = "array_stack"
path = "chapter_stack_and_queue/array_stack.rs"
# Run Command: cargo run --bin array_queue
[[bin]]
name = "array_queue"
path = "chapter_stack_and_queue/array_queue.rs"
# Run Command: cargo run --bin array_binary_tree
[[bin]]
name = "array_binary_tree"
path = "chapter_tree/array_binary_tree.rs"
# Run Command: cargo run --bin avl_tree
[[bin]]
name = "avl_tree"
path = "chapter_tree/avl_tree.rs"
# Run Command: cargo run --bin binary_search_tree
[[bin]]
name = "binary_search_tree"
path = "chapter_tree/binary_search_tree.rs"
# Run Command: cargo run --bin binary_tree_bfs
[[bin]]
name = "binary_tree_bfs"
path = "chapter_tree/binary_tree_bfs.rs"
# Run Command: cargo run --bin binary_tree_dfs
[[bin]]
name = "binary_tree_dfs"
path = "chapter_tree/binary_tree_dfs.rs"
# Run Command: cargo run --bin binary_tree
[[bin]]
name = "binary_tree"
path = "chapter_tree/binary_tree.rs"
# Run Command: cargo run --bin heap
[[bin]]
name = "heap"
path = "chapter_heap/heap.rs"
# Run Command: cargo run --bin my_heap
[[bin]]
name = "my_heap"
path = "chapter_heap/my_heap.rs"
# Run Command: cargo run --bin top_k
[[bin]]
name = "top_k"
path = "chapter_heap/top_k.rs"
# Run Command: cargo run --bin graph_adjacency_list
[[bin]]
name = "graph_adjacency_list"
path = "chapter_graph/graph_adjacency_list.rs"
# Run Command: cargo run --bin graph_adjacency_matrix
[[bin]]
name = "graph_adjacency_matrix"
path = "chapter_graph/graph_adjacency_matrix.rs"
# Run Command: cargo run --bin graph_bfs
[[bin]]
name = "graph_bfs"
path = "chapter_graph/graph_bfs.rs"
# Run Command: cargo run --bin graph_dfs
[[bin]]
name = "graph_dfs"
path = "chapter_graph/graph_dfs.rs"
# Run Command: cargo run --bin linear_search
[[bin]]
name = "linear_search"
path = "chapter_searching/linear_search.rs"
# Run Command: cargo run --bin hashing_search
[[bin]]
name = "hashing_search"
path = "chapter_searching/hashing_search.rs"
# Run Command: cargo run --bin climbing_stairs_dfs
[[bin]]
name = "climbing_stairs_dfs"
path = "chapter_dynamic_programming/climbing_stairs_dfs.rs"
# Run Command: cargo run --bin climbing_stairs_dfs_mem
[[bin]]
name = "climbing_stairs_dfs_mem"
path = "chapter_dynamic_programming/climbing_stairs_dfs_mem.rs"
# Run Command: cargo run --bin climbing_stairs_dp
[[bin]]
name = "climbing_stairs_dp"
path = "chapter_dynamic_programming/climbing_stairs_dp.rs"
# Run Command: cargo run --bin min_cost_climbing_stairs_dp
[[bin]]
name = "min_cost_climbing_stairs_dp"
path = "chapter_dynamic_programming/min_cost_climbing_stairs_dp.rs"
# Run Command: cargo run --bin climbing_stairs_constraint_dp
[[bin]]
name = "climbing_stairs_constraint_dp"
path = "chapter_dynamic_programming/climbing_stairs_constraint_dp.rs"
# Run Command: cargo run --bin climbing_stairs_backtrack
[[bin]]
name = "climbing_stairs_backtrack"
path = "chapter_dynamic_programming/climbing_stairs_backtrack.rs"
# Run Command: cargo run --bin subset_sum_i_naive
[[bin]]
name = "subset_sum_i_naive"
path = "chapter_backtracking/subset_sum_i_naive.rs"
# Run Command: cargo run --bin subset_sum_i
[[bin]]
name = "subset_sum_i"
path = "chapter_backtracking/subset_sum_i.rs"
# Run Command: cargo run --bin subset_sum_ii
[[bin]]
name = "subset_sum_ii"
path = "chapter_backtracking/subset_sum_ii.rs"
# Run Command: cargo run --bin coin_change
[[bin]]
name = "coin_change"
path = "chapter_dynamic_programming/coin_change.rs"
# Run Command: cargo run --bin coin_change_ii
[[bin]]
name = "coin_change_ii"
path = "chapter_dynamic_programming/coin_change_ii.rs"
# Run Command: cargo run --bin unbounded_knapsack
[[bin]]
name = "unbounded_knapsack"
path = "chapter_dynamic_programming/unbounded_knapsack.rs"
# Run Command: cargo run --bin knapsack
[[bin]]
name = "knapsack"
path = "chapter_dynamic_programming/knapsack.rs"
# Run Command: cargo run --bin min_path_sum
[[bin]]
name = "min_path_sum"
path = "chapter_dynamic_programming/min_path_sum.rs"
# Run Command: cargo run --bin edit_distance
[[bin]]
name = "edit_distance"
path = "chapter_dynamic_programming/edit_distance.rs"
# Run Command: cargo run --bin n_queens
[[bin]]
name = "n_queens"
path = "chapter_backtracking/n_queens.rs"
# Run Command: cargo run --bin permutations_i
[[bin]]
name = "permutations_i"
path = "chapter_backtracking/permutations_i.rs"
# Run Command: cargo run --bin permutations_ii
[[bin]]
name = "permutations_ii"
path = "chapter_backtracking/permutations_ii.rs"
# Run Command: cargo run --bin preorder_traversal_i_compact
[[bin]]
name = "preorder_traversal_i_compact"
path = "chapter_backtracking/preorder_traversal_i_compact.rs"
# Run Command: cargo run --bin preorder_traversal_ii_compact
[[bin]]
name = "preorder_traversal_ii_compact"
path = "chapter_backtracking/preorder_traversal_ii_compact.rs"
# Run Command: cargo run --bin preorder_traversal_iii_compact
[[bin]]
name = "preorder_traversal_iii_compact"
path = "chapter_backtracking/preorder_traversal_iii_compact.rs"
# Run Command: cargo run --bin preorder_traversal_iii_template
[[bin]]
name = "preorder_traversal_iii_template"
path = "chapter_backtracking/preorder_traversal_iii_template.rs"
# Run Command: cargo run --bin binary_search_recur
[[bin]]
name = "binary_search_recur"
path = "chapter_divide_and_conquer/binary_search_recur.rs"
# Run Command: cargo run --bin hanota
[[bin]]
name = "hanota"
path = "chapter_divide_and_conquer/hanota.rs"
# Run Command: cargo run --bin build_tree
[[bin]]
name = "build_tree"
path = "chapter_divide_and_conquer/build_tree.rs"
# Run Command: cargo run --bin coin_change_greedy
[[bin]]
name = "coin_change_greedy"
path = "chapter_greedy/coin_change_greedy.rs"
# Run Command: cargo run --bin fractional_knapsack
[[bin]]
name = "fractional_knapsack"
path = "chapter_greedy/fractional_knapsack.rs"
# Run Command: cargo run --bin max_capacity
[[bin]]
name = "max_capacity"
path = "chapter_greedy/max_capacity.rs"
# Run Command: cargo run --bin max_product_cutting
[[bin]]
name = "max_product_cutting"
path = "chapter_greedy/max_product_cutting.rs"
[dependencies]
rand = "0.8.5"
@@ -0,0 +1,111 @@
/*
* File: array.rs
* Created Time: 2023-01-15
* Author: xBLACICEx (xBLACKICEx@outlook.com), codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
use rand::Rng;
/* Случайный доступ к элементу */
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();
}
+69
View File
@@ -0,0 +1,69 @@
/*
* File: graph_bfs.rs
* Created Time: 2023-07-12
* Author: night-cruise (2586447362@qq.com)
*/
mod graph_adjacency_list;
use graph_adjacency_list::GraphAdjList;
use graph_adjacency_list::{vals_to_vets, vets_to_vals, Vertex};
use std::collections::{HashSet, VecDeque};
/* Обход в ширину */
// Использовать список смежности для представления графа, чтобы получить все смежные вершины заданной вершины
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));
}
+61
View File
@@ -0,0 +1,61 @@
/*
* File: graph_dfs.rs
* Created Time: 2023-07-12
* Author: night-cruise (2586447362@qq.com)
*/
mod graph_adjacency_list;
use graph_adjacency_list::GraphAdjList;
use graph_adjacency_list::{vals_to_vets, vets_to_vals, Vertex};
use std::collections::HashSet;
/* Вспомогательная функция обхода в глубину */
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);
}
+48
View File
@@ -0,0 +1,48 @@
/*
* File: hash_map.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::print_util;
use std::collections::HashMap;
/* Driver Code */
pub fn main() {
// Инициализация хеш-таблицы
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}");
}
+71
View File
@@ -0,0 +1,71 @@
/*
* File: heap.rs
* Created Time: 2023-07-16
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
use std::{cmp::Reverse, collections::BinaryHeap};
fn test_push_max(heap: &mut BinaryHeap<i32>, val: i32) {
heap.push(val); // Добавление элемента в кучу
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());
}
+165
View File
@@ -0,0 +1,165 @@
/*
* File: my_heap.rs
* Created Time: 2023-07-16
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
/* Максимальная куча */
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);
}
+39
View File
@@ -0,0 +1,39 @@
/*
* File: top_k.rs
* Created Time: 2023-07-16
* Author: night-cruise (2586447362@qq.com)
*/
use hello_algo_rust::include::print_util;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
/* Найти 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);
}
+148
View File
@@ -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);
}
+295
View File
@@ -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());
}
+38
View File
@@ -0,0 +1,38 @@
/**
* File: binary_tree.rs
* Created Time: 2023-02-27
* Author: xBLACKICEx (xBLACKICE@outlook.com)
*/
use std::rc::Rc;
use hello_algo_rust::include::{print_util, TreeNode};
/* Driver Code */
fn main() {
/* Инициализация двоичного дерева */
// Инициализация узла
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);
}
+57
View File
@@ -0,0 +1,57 @@
/*
* File: list_node.rs
* Created Time: 2023-03-05
* Author: codingonion (coderonion@gmail.com), rongyi (hiarongyi@gmail.com)
*/
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Debug)]
pub struct ListNode<T> {
pub val: T,
pub next: Option<Rc<RefCell<ListNode<T>>>>,
}
impl<T> ListNode<T> {
pub fn new(val: T) -> Rc<RefCell<ListNode<T>>> {
Rc::new(RefCell::new(ListNode { val, next: None }))
}
/* Десериализовать массив в связный список */
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
}
}
+16
View File
@@ -0,0 +1,16 @@
/*
* File: include.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICE@outlook.com)
*/
pub mod list_node;
pub mod print_util;
pub mod tree_node;
pub mod vertex;
// rexport to include
pub use list_node::*;
pub use print_util::*;
pub use tree_node::*;
pub use vertex::*;
+103
View File
@@ -0,0 +1,103 @@
/*
* File: print_util.rs
* Created Time: 2023-02-05
* Author: codingonion (coderonion@gmail.com), xBLACKICEx (xBLACKICEx@outlook.com)
*/
use std::cell::{Cell, RefCell};
use std::fmt::Display;
use std::collections::{HashMap, VecDeque};
use std::rc::Rc;
use super::list_node::ListNode;
use super::tree_node::{TreeNode, vec_to_tree};
struct Trunk<'a, 'b> {
prev: Option<&'a Trunk<'a, 'b>>,
str: Cell<&'b str>,
}
/* Вывести массив */
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);
}
}
+92
View File
@@ -0,0 +1,92 @@
/*
* File: tree_node.rs
* Created Time: 2023-02-27
* Author: xBLACKICEx (xBLACKICE@outlook.com), night-cruise (2586447362@qq.com)
*/
use std::cell::RefCell;
use std::rc::Rc;
/* Тип узла двоичного дерева */
#[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
}
+27
View File
@@ -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()
}
+1
View File
@@ -0,0 +1 @@
pub mod include;