Add old works for Algorithms and Data Structeres
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
wip
|
||||
1
2/atsd/README.md
Normal file
1
2/atsd/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# Algorithms and Data Structures (Алгоритми та Структури Даних)
|
||||
1
2/atsd/array_list/.gitignore
vendored
Normal file
1
2/atsd/array_list/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
2/atsd/array_list/Cargo.lock
generated
Normal file
7
2/atsd/array_list/Cargo.lock
generated
Normal 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"
|
||||
4
2/atsd/array_list/Cargo.toml
Normal file
4
2/atsd/array_list/Cargo.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "array_list"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
125
2/atsd/array_list/README.md
Normal file
125
2/atsd/array_list/README.md
Normal 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
|
||||
```
|
||||
202
2/atsd/array_list/src/main.rs
Normal file
202
2/atsd/array_list/src/main.rs
Normal 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
1
2/atsd/avl/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
2/atsd/avl/Cargo.lock
generated
Normal file
7
2/atsd/avl/Cargo.lock
generated
Normal 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
4
2/atsd/avl/Cargo.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "avl"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
55
2/atsd/avl/README.md
Normal file
55
2/atsd/avl/README.md
Normal 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
263
2/atsd/avl/src/main.rs
Normal 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
1
2/atsd/exam/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
2/atsd/exam/Cargo.lock
generated
Normal file
7
2/atsd/exam/Cargo.lock
generated
Normal 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
4
2/atsd/exam/Cargo.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "exam"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
7
2/atsd/exam/README.md
Normal file
7
2/atsd/exam/README.md
Normal 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
28
2/atsd/exam/src/main.rs
Normal 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
1
2/atsd/graph/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
2/atsd/graph/Cargo.lock
generated
Normal file
7
2/atsd/graph/Cargo.lock
generated
Normal 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
4
2/atsd/graph/Cargo.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "graph"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
67
2/atsd/graph/README.md
Normal file
67
2/atsd/graph/README.md
Normal 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
170
2/atsd/graph/src/main.rs
Normal 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
1
2/atsd/sorted_linked_list/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
2/atsd/sorted_linked_list/Cargo.lock
generated
Normal file
7
2/atsd/sorted_linked_list/Cargo.lock
generated
Normal 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"
|
||||
4
2/atsd/sorted_linked_list/Cargo.toml
Normal file
4
2/atsd/sorted_linked_list/Cargo.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "sorted_linked_list"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
19
2/atsd/sorted_linked_list/README.md
Normal file
19
2/atsd/sorted_linked_list/README.md
Normal 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
|
||||
```
|
||||
288
2/atsd/sorted_linked_list/src/lib.rs
Normal file
288
2/atsd/sorted_linked_list/src/lib.rs
Normal 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")));
|
||||
}
|
||||
}
|
||||
19
2/atsd/sorted_linked_list/src/main.rs
Normal file
19
2/atsd/sorted_linked_list/src/main.rs
Normal 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));
|
||||
}
|
||||
1
2/atsd/unsorted_linked_list/.gitignore
vendored
Normal file
1
2/atsd/unsorted_linked_list/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
7
2/atsd/unsorted_linked_list/Cargo.lock
generated
Normal file
7
2/atsd/unsorted_linked_list/Cargo.lock
generated
Normal 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"
|
||||
4
2/atsd/unsorted_linked_list/Cargo.toml
Normal file
4
2/atsd/unsorted_linked_list/Cargo.toml
Normal file
@@ -0,0 +1,4 @@
|
||||
[package]
|
||||
name = "unsorted_linked_list"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
11
2/atsd/unsorted_linked_list/README.md
Normal file
11
2/atsd/unsorted_linked_list/README.md
Normal 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]
|
||||
```
|
||||
88
2/atsd/unsorted_linked_list/src/main.rs
Normal file
88
2/atsd/unsorted_linked_list/src/main.rs
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user