1
0

Add old works for Algorithms and Data Structeres

This commit is contained in:
2025-12-04 20:46:45 +02:00
parent 6794e9ca96
commit 6c03e1714f
33 changed files with 1416 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
wip

1
2/atsd/README.md Normal file
View File

@@ -0,0 +1 @@
# Algorithms and Data Structures (Алгоритми та Структури Даних)

1
2/atsd/array_list/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

7
2/atsd/array_list/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "array_list"
version = "0.1.0"

View File

@@ -0,0 +1,4 @@
[package]
name = "array_list"
version = "0.1.0"
edition = "2021"

125
2/atsd/array_list/README.md Normal file
View File

@@ -0,0 +1,125 @@
# Array List
Implements a custom dynamic array (similar to a standard Vector) that manually manages memory allocation and resizing. It includes built-in Binary Heap logic to perform in-place Heapsort and priority-queue operations (like deleting the top element). It also features a utility to visualize the array's internal structure as a printed ASCII tree.
Execution result:
```
Data unsorted: [0, 1, 4, 9, 16, 25, 36, 0, 8, 18, 30, 44, 60, 78, 0, 15, 32, 51, 72, 95, 120, 0, 22, 46, 72, 100, 130, 162, 0, 29, 60, 93]
┌ 93
┌ 15
┌ 0
│ └ 32
┌ 9
│ │ ┌ 51
│ └ 8
│ └ 72
┌ 1
│ │ ┌ 95
│ │ ┌ 18
│ │ │ └ 120
│ └ 16
│ │ ┌ 0
│ └ 30
│ └ 22
0
│ ┌ 46
│ ┌ 44
│ │ └ 72
│ ┌ 25
│ │ │ ┌ 100
│ │ └ 60
│ │ └ 130
└ 4
│ ┌ 162
│ ┌ 78
│ │ └ 0
└ 36
│ ┌ 29
└ 0
└ 60
Data ascending: [0, 0, 0, 0, 0, 1, 4, 8, 9, 15, 16, 18, 22, 25, 29, 30, 32, 36, 44, 46, 51, 60, 60, 72, 72, 78, 93, 95, 100, 120, 130, 162]
┌ 162
┌ 30
┌ 8
│ └ 32
┌ 0
│ │ ┌ 36
│ └ 9
│ └ 44
┌ 0
│ │ ┌ 46
│ │ ┌ 15
│ │ │ └ 51
│ └ 0
│ │ ┌ 60
│ └ 16
│ └ 60
0
│ ┌ 72
│ ┌ 18
│ │ └ 72
│ ┌ 1
│ │ │ ┌ 78
│ │ └ 22
│ │ └ 93
└ 0
│ ┌ 95
│ ┌ 25
│ │ └ 100
└ 4
│ ┌ 120
└ 29
└ 130
Data descending: [162, 130, 120, 100, 95, 93, 78, 72, 72, 60, 60, 51, 46, 44, 36, 32, 30, 29, 25, 22, 18, 16, 15, 9, 8, 4, 1, 0, 0, 0, 0, 0]
┌ 0
┌ 32
┌ 72
│ └ 30
┌ 100
│ │ ┌ 29
│ └ 72
│ └ 25
┌ 130
│ │ ┌ 22
│ │ ┌ 60
│ │ │ └ 18
│ └ 95
│ │ ┌ 16
│ └ 60
│ └ 15
162
│ ┌ 9
│ ┌ 51
│ │ └ 8
│ ┌ 93
│ │ │ ┌ 4
│ │ └ 46
│ │ └ 1
└ 120
│ ┌ 0
│ ┌ 44
│ │ └ 0
└ 78
│ ┌ 0
└ 36
└ 0
Data [1, 12, 9, 5, 6, 10]
┌ 5
┌ 12
│ └ 6
1
│ ┌ 10
└ 9
Deleting top: Some(12)
┌ 5
┌ 6
│ └ 1
10
└ 9
Deleting top with one element: None
```

View File

@@ -0,0 +1,202 @@
#[derive(Default)]
struct ArrayList {
length: usize,
allocate: usize,
capacity: usize,
data: Box<[i32]>,
}
impl ArrayList {
const fn len(&self) -> usize {
self.length
}
const fn capacity(&self) -> usize {
self.capacity
}
const fn is_empty(&self) -> bool {
self.length == 0
}
const fn is_full(&self) -> bool {
self.length == self.capacity
}
}
impl ArrayList {
fn alloc(size: usize) -> Box<[i32]> {
vec![0i32; size].into_boxed_slice()
}
fn change_capacity(&mut self, size: usize) {
self.capacity = size;
let old_data = std::mem::replace(&mut self.data, Self::alloc(size));
self.data[..self.length].copy_from_slice(&old_data[..self.length]);
}
pub fn new(allocate: usize) -> Self {
assert!(allocate > 0);
Self {
allocate,
..Default::default()
}
}
pub fn push(&mut self, num: i32) {
if self.is_full() {
self.change_capacity(self.capacity + self.allocate);
}
self.data[self.length] = num;
self.length += 1;
}
pub fn pop(&mut self) -> Option<i32> {
if self.is_empty() {
return None;
}
self.length -= 1;
Some(self.data[self.length])
}
pub fn shrink(&mut self) {
self.change_capacity(self.length);
}
pub fn slice(&self) -> &[i32] {
&self.data[..self.length]
}
fn heapify(&mut self, idx: usize, len: usize, max_heap: bool) {
if idx >= len {
return;
}
let idxs = [idx, 2 * idx + 1, 2 * idx + 2]
.into_iter()
.filter(|&i| i < len);
let swap_idx = if max_heap {
idxs.max_by_key(|&i| self.data[i])
} else {
idxs.min_by_key(|&i| self.data[i])
}
.unwrap();
if swap_idx != idx {
self.data.swap(swap_idx, idx);
self.heapify(swap_idx, len, max_heap);
}
}
fn make_heap(&mut self, max_heap: bool) {
// parent of last element (last_idx-1)/2 or (len/2)-1
for idx in (0..self.length / 2).rev() {
self.heapify(idx, self.length, max_heap);
}
}
pub fn sort(&mut self, ascending: bool) {
self.make_heap(ascending);
for len in (1..self.length).rev() {
self.data.swap(0, len);
self.heapify(0, len, ascending);
}
}
pub fn delete_top(&mut self) -> Option<i32> {
if self.is_empty() {
return None;
}
if self.length == 1 {
return self.pop();
}
self.make_heap(true);
self.length -= 1;
self.data.swap(0, self.length);
self.heapify(0, self.length, true);
Some(self.data[self.length])
}
fn tree_internal(&self, idx: usize, lines: Vec<&str>, dir: i8) {
if 2 * idx + 1 < self.length {
let mut l = lines.clone();
if dir == 1 {
l.pop();
l.push(" ");
}
l.push("");
self.tree_internal(2 * idx + 1, l, 1);
}
let mut l = lines.clone();
l.pop();
l.push(["", "", ""][(dir + 1) as usize]);
println!("{}{}", l.join(" "), self.data[idx]);
if 2 * idx + 2 < self.length {
let mut l = lines;
if dir == -1 {
l.pop();
l.push(" ");
}
l.push("");
self.tree_internal(2 * idx + 2, l, -1);
}
}
pub fn tree(&self) {
self.tree_internal(0, vec![], 0);
}
}
use std::fmt;
impl fmt::Display for ArrayList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", &self.data[..self.length])
}
}
fn main() {
let mut arr = ArrayList::new(10);
for i in 0..32 {
arr.push(i % 7 * i);
}
println!("Data unsorted: {arr}");
arr.tree();
println!();
arr.sort(true);
println!("Data ascending: {arr}");
arr.tree();
println!();
arr.sort(false);
println!("Data descending: {arr}");
arr.tree();
println!();
let mut arr = ArrayList::new(10);
for i in [1, 12, 9, 5, 6, 10] {
arr.push(i);
}
println!();
println!("Data {arr}");
arr.tree();
println!("Deleting top: {:?}", arr.delete_top());
arr.tree();
println!();
println!(
"Deleting top with one element: {:?}",
ArrayList::new(5).delete_top()
);
}

1
2/atsd/avl/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

7
2/atsd/avl/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "avl"
version = "0.1.0"

4
2/atsd/avl/Cargo.toml Normal file
View File

@@ -0,0 +1,4 @@
[package]
name = "avl"
version = "0.1.0"
edition = "2021"

55
2/atsd/avl/README.md Normal file
View File

@@ -0,0 +1,55 @@
# AVL Tree
Implements an AVL Tree, which is a self-balancing Binary Search Tree (BST) that ensures logarithmic time complexity for operations. It automatically maintains balance by tracking node heights and performing rotations (left and right) whenever an insertion or deletion causes the tree to become skewed.
The implementation includes standard operations like search, min/max finding, and removal, along with a recursive utility to visualize the tree structure in the console.
For this code:
```rs
Node::from_iter(-20..=20).tree();
```
The resulting tree looks like:
```
┌ 20
┌ 19
│ └ 18
┌ 17
│ └ 16
┌ 15
│ │ ┌ 14
│ └ 13
│ └ 12
┌ 11
│ │ ┌ 10
│ │ ┌ 9
│ │ │ └ 8
│ │ ┌ 7
│ │ │ │ ┌ 6
│ │ │ └ 5
│ │ │ └ 4
│ └ 3
│ │ ┌ 2
│ │ ┌ 1
│ │ │ └ 0
│ └ -1
│ │ ┌ -2
│ └ -3
│ └ -4
-5
│ ┌ -6
│ ┌ -7
│ │ └ -8
│ ┌ -9
│ │ │ ┌ -10
│ │ └ -11
│ │ └ -12
└ -13
│ ┌ -14
│ ┌ -15
│ │ └ -16
└ -17
│ ┌ -18
└ -19
└ -20
```

263
2/atsd/avl/src/main.rs Normal file
View File

@@ -0,0 +1,263 @@
// #![allow(unused)]
use std::cmp::Ordering;
#[derive(Clone, Default)]
struct Node {
value: i32,
height: usize,
left: Option<Box<Self>>,
right: Option<Box<Self>>,
}
// internal
impl Node {
fn height(node: &Option<Box<Self>>) -> usize {
match node {
Some(node) => 1 + node.height,
None => 0,
}
}
fn update_height(&mut self) {
self.height = std::cmp::max(Node::height(&self.left), Node::height(&self.right));
}
fn balance_factor(&self) -> isize {
Self::height(&self.left) as isize - Self::height(&self.right) as isize
}
fn right_rotate(&mut self) {
let mut new_root = *self.left.take().unwrap();
self.left = new_root.right.take();
self.update_height();
self.right = Some(Box::new(std::mem::replace(self, new_root)));
self.update_height();
}
fn left_rotate(&mut self) {
let mut new_root = *self.right.take().unwrap();
self.right = new_root.left.take();
self.update_height();
self.left = Some(Box::new(std::mem::replace(self, new_root)));
self.update_height();
}
fn rebalance(&mut self) {
let balance_factor = self.balance_factor();
if balance_factor > 1 {
let node = self.left.as_mut().unwrap();
if node.balance_factor() < 0 {
// skewed to the right
node.left_rotate();
}
self.right_rotate();
}
if balance_factor < -1 {
let node = self.right.as_mut().unwrap();
if node.balance_factor() > 0 {
// skewed to the left
node.right_rotate();
}
self.left_rotate();
}
}
fn tree_internal(&self, lines: Vec<&str>, dir: i8) {
if let Some(ref node) = self.right {
let mut l = lines.clone();
if dir == 1 {
l.pop();
l.push(" ");
}
l.push("");
node.tree_internal(l, 1);
}
let mut l = lines.clone();
l.pop();
l.push(["", "", ""][(dir + 1) as usize]);
let dbg_info = ""; // format!(" ({})", self.height);
println!("{}{}{}", l.join(" "), self.value, dbg_info);
if let Some(ref node) = self.left {
let mut l = lines;
if dir == -1 {
l.pop();
l.push(" ");
}
l.push("");
node.tree_internal(l, -1);
}
}
}
// public
impl Node {
pub fn new(value: i32) -> Self {
Self {
value,
..Default::default()
}
}
pub fn from_vec(values: Vec<i32>) -> Self {
let mut node = Self::new(values[0]);
for value in values.into_iter().skip(1) {
node.add(value);
}
node
}
pub fn add(&mut self, val: i32) {
match (val.cmp(&self.value), &mut self.left, &mut self.right) {
(Ordering::Less, opt, _) | (Ordering::Greater, _, opt) => match opt {
Some(node) => node.add(val),
None => *opt = Some(Box::new(Self::new(val))),
},
_ => return,
};
self.update_height();
self.rebalance();
}
pub fn del(mut self, val: i32) -> Option<Box<Self>> {
match (val.cmp(&self.value), &mut self.left, &mut self.right) {
(Ordering::Less, opt, _) | (Ordering::Greater, _, opt) => {
if opt.is_some() {
*opt = opt.take().unwrap().del(val);
}
}
(Ordering::Equal, _, Some(node)) => {
self.value = node.min();
self.right = self.right.take().unwrap().del(self.value);
}
(Ordering::Equal, Some(_), None) => return self.left,
(Ordering::Equal, None, None) => return None,
};
self.update_height();
self.rebalance();
Some(Box::new(self))
}
pub fn has(&self, val: i32) -> bool {
match (val.cmp(&self.value), &self.left, &self.right) {
(Ordering::Less, Some(n), _) | (Ordering::Greater, _, Some(n)) => n.has(val),
(Ordering::Equal, ..) => true,
_ => false,
}
}
pub fn min(&self) -> i32 {
match self.left {
Some(ref node) => node.min(),
None => self.value,
}
}
pub fn max(&self) -> i32 {
match self.right {
Some(ref node) => node.max(),
None => self.value,
}
}
pub fn tree(&self) {
self.tree_internal(vec![], 0);
}
pub fn clone_node(&self) -> Self {
Self {
value: self.value,
height: self.height,
left: self.left.as_ref().map(|node| Box::new(node.clone_node())),
right: self.right.as_ref().map(|node| Box::new(node.clone_node())),
}
}
}
use std::fmt;
impl fmt::Display for Node {
// inorder
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(ref node) = self.left {
write!(f, "{node}")?;
}
write!(f, "{} ", self.value)?;
if let Some(ref node) = self.right {
write!(f, "{node}")?;
}
Ok(())
}
}
impl FromIterator<i32> for Node {
fn from_iter<I: IntoIterator<Item = i32>>(iter: I) -> Self {
let mut iter = iter.into_iter();
let mut node = Node::new(iter.next().unwrap());
for value in iter {
node.add(value);
}
node
}
}
fn main() {
let mut avl = Node::from_vec(vec![20, 4]);
avl.add(15);
avl.tree();
println!();
let mut avl = Node::from_vec(vec![20, 4, 26, 3, 9]);
avl.add(15);
avl.tree();
println!();
let mut avl = Node::from_vec(vec![20, 4, 26, 3, 9, 21, 30, 2, 7, 11]);
avl.add(15);
avl.tree();
println!();
println!();
let mut avl = Node::from_vec(vec![20, 4]);
avl.add(8);
avl.tree();
println!();
let mut avl = Node::from_vec(vec![20, 4, 26, 3, 9]);
avl.add(8);
avl.tree();
println!();
let mut avl = Node::from_vec(vec![20, 4, 26, 3, 9, 21, 30, 2, 7, 11]);
avl.add(8);
avl.tree();
println!();
println!();
let avl = Node::from_vec(vec![2, 1, 4, 3, 5]);
let avl = avl.del(1).unwrap();
avl.tree();
println!();
let avl = Node::from_vec(vec![6, 2, 9, 1, 4, 8, 11, 3, 5, 7, 10, 12, 13]);
let avl = avl.del(1).unwrap();
avl.tree();
println!();
let avl = Node::from_vec(vec![5, 2, 8, 1, 3, 7, 10, 4, 6, 11, 12]);
let avl = avl.del(1).unwrap();
avl.tree();
println!("{}", avl.has(1));
println!("{}", avl.has(7));
println!("{}", avl.min());
println!("{}", avl.max());
let mut avl2 = avl.clone();
avl2.add(42);
avl2.tree();
println!();
println!("{avl}");
println!("{avl2}");
// Node::from_iter(-1000..=1000).tree();
}

1
2/atsd/exam/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

7
2/atsd/exam/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "exam"
version = "0.1.0"

4
2/atsd/exam/Cargo.toml Normal file
View File

@@ -0,0 +1,4 @@
[package]
name = "exam"
version = "0.1.0"
edition = "2021"

7
2/atsd/exam/README.md Normal file
View File

@@ -0,0 +1,7 @@
# Exam
> Algorithm for replacing elements of a one-dimensional list. Implement in pseudocode or your favorite programming language.
Cooked this bad boy during the exam.

28
2/atsd/exam/src/main.rs Normal file
View File

@@ -0,0 +1,28 @@
fn replace<T: Clone + PartialEq>(list: &mut [T], find: &T, with: &T, all: bool) {
for element in list.iter_mut() {
if element == find {
*element = with.clone();
if !all {
return;
}
}
}
}
fn main() {
let mut list: Vec<_> = (0..10).map(|x| x % 7).collect();
println!("{list:?}");
let find = 2;
let with = 42;
replace(&mut list, &find, &with, false);
println!("{list:?}");
replace(&mut list, &find, &with, true);
println!("{list:?}");
let mut list = [1, 2, 3, 4, 1, 3, 1, 0, 4];
replace(&mut list, &1, &9, true);
println!("{list:?}");
}

1
2/atsd/graph/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

7
2/atsd/graph/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "graph"
version = "0.1.0"

4
2/atsd/graph/Cargo.toml Normal file
View File

@@ -0,0 +1,4 @@
[package]
name = "graph"
version = "0.1.0"
edition = "2021"

67
2/atsd/graph/README.md Normal file
View File

@@ -0,0 +1,67 @@
# Graph
Implements a weighted, undirected graph with a minimal CLI to build it. Algorithms like Dijkstra's Shortest Path and Kruskal's Minimum Spanning Tree (MST) are available.
Execution result:
```
Exit - 'q' or 'x'
Print the graph - 'p'
Calculate dijkstra to each vertex - 'd vertex'
Remove an edge - 'vertex1 vertex2'
Add an edge - 'vertex1 vertex2 distance'
1 2 6
Added 1 - 2, 6
2 4 5
Added 2 - 4, 5
4 5 22
Added 4 - 5, 22
5 7 10
Added 5 - 7, 10
7 6 12
Added 7 - 6, 12
6 1 15
Added 6 - 1, 15
3 2 11
Added 3 - 2, 11
3 4 17
Added 3 - 4, 17
3 6 25
Added 3 - 6, 25
3 7 12
Added 3 - 7, 12
3 7
Removed 3 - 7
3 7 9
Added 3 - 7, 9
p
1 - 2, 6
1 - 6, 15
2 - 3, 11
2 - 4, 5
3 - 4, 17
3 - 6, 25
3 - 7, 9
4 - 5, 22
5 - 7, 10
6 - 7, 12
d 1
{1: None, 2: Some((1, 6)), 3: Some((2, 17)), 4: Some((2, 11)), 5: Some((4, 33)), 6: Some((1, 15)), 7: Some((3, 26))}
q
1 - 2, 6
1 - 6, 15
2 - 3, 11
2 - 4, 5
3 - 4, 17
3 - 6, 25
3 - 7, 9
4 - 5, 22
5 - 7, 10
6 - 7, 12
1 - 2, 6
2 - 3, 11
2 - 4, 5
3 - 7, 9
5 - 7, 10
6 - 7, 12
```

170
2/atsd/graph/src/main.rs Normal file
View File

@@ -0,0 +1,170 @@
use std::{
collections::{BTreeMap, BTreeSet},
io,
};
#[derive(Default)]
struct Graph {
vertices: BTreeMap<usize, BTreeMap<usize, u32>>,
}
impl Graph {
fn rem_edge(&mut self, v1: usize, v2: usize) {
self.vertices.entry(v1).and_modify(|m| {
m.remove(&v2);
});
self.vertices.entry(v2).and_modify(|m| {
m.remove(&v1);
});
}
fn add_edge(&mut self, v1: usize, v2: usize, distance: u32) {
self.vertices.entry(v1).or_default().insert(v2, distance);
self.vertices.entry(v2).or_default().insert(v1, distance);
}
pub fn new() -> Self {
let mut graph = Self::default();
println!(
"Exit - 'q' or 'x'
Print the graph - 'p'
Calculate dijkstra to each vertex - 'd vertex'
Remove an edge - 'vertex1 vertex2'
Add an edge - 'vertex1 vertex2 distance'"
);
loop {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let args: Vec<&str> = input.split_whitespace().collect();
match args.len() {
0 => continue,
1 => match args[0] {
"q" | "x" => break,
"p" => graph.print(),
_ => println!("Can't parse {input}"),
},
2 => {
if args[0] == "d" {
println!("{:?}", graph.dijkstra(args[1].parse().unwrap()));
} else {
graph.rem_edge(args[0].parse().unwrap(), args[1].parse().unwrap());
println!("Removed {} - {}", args[0], args[1]);
}
}
3 => {
graph.add_edge(
args[0].parse().unwrap(),
args[1].parse().unwrap(),
args[2].parse().unwrap(),
);
println!("Added {} - {}, {}", args[0], args[1], args[2]);
}
_ => println!("Can't parse {input}"),
}
}
graph
}
pub fn print(&self) {
let mut viewed = BTreeSet::new();
for (v1, vertices) in &self.vertices {
for (v2, distance) in vertices {
if viewed.contains(&(v1, v2)) || viewed.contains(&(v2, v1)) {
continue;
}
println!("{v1} - {v2}, {distance}");
viewed.insert((v1, v2));
}
}
}
// find a representative for a given element
fn find_repr(reprs: &BTreeMap<usize, usize>, element: usize) -> usize {
if reprs[&element] == element {
return element;
}
Self::find_repr(reprs, reprs[&element])
}
pub fn kruskal(&self) -> Self {
let mut kruskal_graph = Self::default();
let mut edges = BTreeSet::new();
let mut reprs = BTreeMap::new();
for (v1, vertices) in &self.vertices {
for (v2, distance) in vertices {
if !edges.contains(&(*v2, *v1, *distance)) {
edges.insert((*v1, *v2, *distance));
}
}
reprs.insert(*v1, *v1);
}
let mut edges: Vec<_> = edges.into_iter().collect();
edges.sort_by_key(|k| k.2);
let mut count = 0;
for (v1, v2, dist) in edges {
if count + 1 >= self.vertices.len() {
break;
}
let parent1 = Self::find_repr(&reprs, v1);
let parent2 = Self::find_repr(&reprs, v2);
if parent1 != parent2 {
count += 1;
kruskal_graph.add_edge(v1, v2, dist);
reprs.insert(parent2, parent1);
}
}
kruskal_graph
}
pub fn dijkstra(&self, start: usize) -> BTreeMap<usize, Option<(usize, u32)>> {
let mut visited = BTreeMap::new(); // map of vertices and predecessor with distance
let mut fifo = BTreeMap::new(); // first in first out buffer of vertex and distance
visited.insert(start, None); // doesn't have a predecessor
// adding vertices from start
for (vertex, distance) in &self.vertices[&start] {
visited.insert(*vertex, Some((start, *distance)));
fifo.insert(*vertex, *distance);
}
while let Some((vertex, distance)) = fifo.pop_first() {
for (next, next_distance) in &self.vertices[&vertex] {
let new_distance = distance + next_distance;
match visited.get(next) {
// skip if new distance >= current distance for vertex
Some(Some((_, current_distance))) if new_distance >= *current_distance => {}
// vertex is a start
Some(None) => {}
// new distance is shorter or next was not in distances
_ => {
visited.insert(*next, Some((vertex, new_distance)));
fifo.insert(*next, new_distance);
}
}
}
}
visited
}
}
fn main() {
let graph = Graph::new();
graph.print();
println!();
graph.kruskal().print();
}

1
2/atsd/sorted_linked_list/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

7
2/atsd/sorted_linked_list/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "sorted_linked_list"
version = "0.1.0"

View File

@@ -0,0 +1,4 @@
[package]
name = "sorted_linked_list"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,19 @@
# Sorted Linked List
> [!NOTE]
> This one implements tests, so `cargo test`
This code implements a **generic**, sorted Singly Linked List that relies on Rust's `Rc` and `RefCell` smart pointers for shared ownership and interior mutability. Unlike a standard push-append list, the `add` method automatically inserts new elements into their correct sorted position based on their value, ensuring the list remains ordered at all times. It is fully unit-tested and supports operations like removing specific values, popping by index, and deep equality checks.
Test results:
```sh
running 8 tests
test tests::add ... ok
test tests::custom_type ... ok
test tests::equal ... ok
test tests::get ... ok
test tests::pop ... ok
test tests::print ... ok
test tests::remove ... ok
test tests::remove_all ... ok
```

View File

@@ -0,0 +1,288 @@
use std::cell::RefCell;
use std::rc::Rc;
pub use List::Nil;
pub use List::Node;
#[derive(PartialEq, Debug)]
pub enum List<T> {
Nil,
Node(T, Rc<RefCell<List<T>>>),
}
impl<T> List<T> {
pub fn new(val: T, next: Self) -> Self {
Node(val, Rc::new(RefCell::new(next)))
}
}
impl<T: Clone> List<T> {
pub fn unref(node: &RefCell<Self>) -> Self {
if let Node(val, next) = &*node.borrow() {
return Node(val.clone(), Rc::clone(next));
}
Nil
}
pub fn unpack(node: &RefCell<Self>) -> Option<(T, Rc<RefCell<Self>>)> {
if let Node(val, next) = &*node.borrow() {
return Some((val.clone(), Rc::clone(next)));
}
None
}
}
impl<T: Clone + std::fmt::Display> List<T> {
pub fn print(&self) {
print!("[");
if let Node(val, next) = self {
print!("{}", val);
let mut ptr = Rc::clone(next);
while let Some((val, next)) = List::unpack(&ptr) {
print!(", {}", val);
ptr = next;
}
}
println!("]");
}
}
impl<T: Clone + PartialOrd> List<T> {
pub fn add(self, new_val: T) -> Self {
let head = Rc::new(RefCell::new(self));
let mut ptr = Rc::clone(&head);
while let Some((val, next)) = List::unpack(&ptr) {
if val < new_val {
ptr = next;
continue;
}
*ptr.borrow_mut() = List::new(new_val, Node(val, next));
return Self::unref(&head);
}
if Self::unref(&ptr) == Nil {
*ptr.borrow_mut() = List::new(new_val, Nil);
}
Self::unref(&head)
}
pub fn remove(self, rem_val: T, all: bool) -> Self {
let head = Rc::new(RefCell::new(self));
let mut ptr = Rc::clone(&head);
while let Some((val, next)) = List::unpack(&ptr) {
if val > rem_val {
break;
}
if val != rem_val {
ptr = next;
continue;
}
*ptr.borrow_mut() = List::unref(&next);
if !all {
break;
}
}
Self::unref(&head)
}
pub fn pop(&mut self, index: usize) -> Option<T> {
if let Node(val, next) = self {
if index == 0 {
let res = val.clone();
*self = Self::unref(next);
return Some(res);
}
let mut idx = 1;
let mut ptr = Rc::clone(next);
while let Some((val, next)) = List::unpack(&ptr) {
if idx < index {
idx += 1;
ptr = next;
continue;
}
*ptr.borrow_mut() = List::unref(&next);
return Some(val);
}
}
None
}
pub fn get(&self, index: usize) -> Option<T> {
if let Node(val, next) = self {
if index == 0 {
return Some(val.clone());
}
let mut idx = 0;
let mut ptr = Rc::clone(next);
while let Some((val, next)) = List::unpack(&ptr) {
idx += 1;
ptr = next;
if idx == index {
return Some(val);
}
}
}
None
}
}
impl<T> List<T>
where
T: Clone + std::fmt::Display,
{
pub fn equal(&self, other: &Self) -> bool {
let mut s1 = "[".to_string();
if let Node(val, next) = self {
s1 += &val.to_string();
let mut ptr = Rc::clone(next);
while let Some((val, next)) = List::unpack(&ptr) {
s1 += &format!(", {val}");
ptr = next;
}
}
s1 += &"]".to_string();
let mut s2 = "[".to_string();
if let Node(val, next) = other {
s2 += &val.to_string();
let mut ptr = Rc::clone(next);
while let Some((val, next)) = List::unpack(&ptr) {
s2 += &format!(", {val}");
ptr = next;
}
}
s2 += &"]".to_string();
println!("{s1}");
println!("{s2}");
s1 == s2
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn equal() {
let list1 = Nil.add(1).add(3).add(2).add(5).add(42).add(7);
let list2 = Nil.add(1).add(2).add(3).add(7).add(42).add(5);
let list3 = Nil.add(3).add(0);
assert!(list1.equal(&list2));
println!();
assert!(!list1.equal(&list3));
println!();
assert!(!list1.equal(&Nil));
}
#[test]
fn print() {
let list = List::new(3, Nil).add(1).add(5).add(2).add(4);
list.print();
}
#[test]
fn get() {
let list = List::new(1, List::new(2, List::new(4, Nil)));
assert_eq!(list.get(2), Some(4));
assert_eq!(list.get(0), Some(1));
assert_eq!(list.get(1), Some(2));
assert_eq!(list.get(10), None);
}
#[test]
fn add() {
let mut list = List::new(2, Nil);
let mut desired = List::new(1, List::new(2, List::new(4, Nil)));
list = list.add(3).add(1).add(2).add(4);
desired = desired.add(3).add(2);
assert_eq!(list, desired);
}
#[test]
fn pop() {
let mut list = Nil.add(2).add(2).add(4).add(3).add(1);
assert_eq!(list.pop(0), Some(1));
assert_eq!(list, Nil.add(2).add(2).add(4).add(3));
assert_eq!(list.pop(2), Some(3));
assert_eq!(list, Nil.add(2).add(2).add(4));
assert_eq!(list.pop(100), None);
}
#[test]
fn remove() {
let mut list = Nil.add(2).add(2).add(4).add(3).add(1);
let desired = List::new(2, List::new(4, Nil));
list = list.remove(2, false).remove(3, false).remove(1, false);
assert_eq!(list, desired);
}
#[test]
fn remove_all() {
let mut list = Nil.add(2).add(4).add(3).add(1);
let desired = List::new(4, Nil);
list = list.remove(2, true).remove(3, true).remove(1, true);
assert_eq!(list, desired);
}
#[test]
fn custom_type() {
#[derive(Debug, Clone, PartialEq)]
struct MyObj {
id: u8,
name: String,
}
impl MyObj {
fn new(id: u8, name: &str) -> Self {
let name = name.into();
MyObj { id, name }
}
}
impl PartialOrd for MyObj {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(other.id.cmp(&self.id))
}
}
let mut list = List::new(
MyObj::new(1, "Alice"),
List::new(MyObj::new(3, "Bob"), List::new(MyObj::new(5, "Jane"), Nil)),
)
.add(MyObj::new(2, "Tom"))
.add(MyObj::new(1, "Mike"))
.add(MyObj::new(4, "Kelvin"))
.remove(MyObj::new(5, "Jane"), false)
.remove(MyObj::new(1, "Mike"), true)
.remove(MyObj::new(10, "Mike"), true);
assert_eq!(list.pop(10), None);
assert_eq!(list.pop(0), Some(MyObj::new(4, "Kelvin")));
}
}

View File

@@ -0,0 +1,19 @@
use sorted_linked_list::*;
// Write a method ListEqual() to test if the calling List L1 and the argument
// linked lists L2 are equal (i.e., have the same values in the same order).
// Print both L1 and L2.
fn main() {
let list1 = Nil.add(1).add(3).add(2).add(5).add(42).add(7);
let list2 = Nil.add(1).add(2).add(3).add(7).add(42).add(5);
let list3 = List::new(1, List::new(2, List::new(3, Nil)));
assert!(list1.equal(&list2));
println!();
assert!(!list1.equal(&list3));
println!();
assert!(!list1.equal(&Nil));
println!();
assert!(Nil::<i32>.equal(&Nil));
}

View File

@@ -0,0 +1 @@
/target

7
2/atsd/unsorted_linked_list/Cargo.lock generated Normal file
View File

@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "unsorted_linked_list"
version = "0.1.0"

View File

@@ -0,0 +1,4 @@
[package]
name = "unsorted_linked_list"
version = "0.1.0"
edition = "2021"

View File

@@ -0,0 +1,11 @@
# Unsorted Linked List
implements a basic Singly Linked List that supports appending elements to the end and printing the contents. It features a Bubble Sort algorithm that sorts the list by swapping the integer values stored in the nodes, rather than rewiring the next pointers.
Execution result:
```
List: [42, 1, 37, 69, 9, 96, 12, 36]
Sorted: [1, 9, 12, 36, 37, 42, 69, 96]
Add 36: [1, 9, 12, 36, 37, 42, 69, 96, 36]
Sorted: [1, 9, 12, 36, 36, 37, 42, 69, 96]
```

View File

@@ -0,0 +1,88 @@
struct List {
val: i32,
next: Option<Box<List>>,
}
impl List {
pub const fn new(val: i32) -> Self {
Self { val, next: None }
}
pub fn print(&self) {
let mut ptr = self;
print!("[{}", ptr.val);
while let Some(ref next) = ptr.next {
ptr = next;
print!(", {}", ptr.val);
}
println!("]");
}
pub fn add(&mut self, val: i32) {
let mut ptr = self;
while let Some(ref mut next) = ptr.next {
ptr = next;
}
ptr.next = Some(Box::new(Self::new(val)));
}
pub fn bubblesort(&mut self) {
let mut len = 1; // there is already 1 element in the list
let mut sorted = false;
let mut ptr = &mut *self;
// find the length
while let Some(next) = &mut ptr.next {
if ptr.val > next.val {
std::mem::swap(&mut ptr.val, &mut next.val);
}
len += 1;
ptr = next;
}
while !sorted {
sorted = true;
ptr = &mut *self;
// len-2 because looped 1 time while getting len, and checking next element from current
for _ in 0..len - 2 {
let next = ptr.next.as_mut().unwrap();
if ptr.val > next.val {
std::mem::swap(&mut ptr.val, &mut next.val);
sorted = false;
}
ptr = next;
}
len -= 1;
}
}
}
fn main() {
let mut list = List::new(42);
list.add(1);
list.add(37);
list.add(69);
list.add(9);
list.add(96);
list.add(12);
list.add(36);
print!("List: ");
list.print();
list.bubblesort();
print!("Sorted: ");
list.print();
list.add(36);
print!("Add 36: ");
list.print();
list.bubblesort();
print!("Sorted: ");
list.print();
}