Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Added move_to_front_encoding implementation #874

Merged
merged 4 commits into from
Mar 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
* [Xor](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/xor.rs)
* Compression
* [Run Length Encoding](https://github.com/TheAlgorithms/Rust/blob/master/src/compression/run_length_encoding.rs)
* [Move-To-Front Encoding](https://github.com/TheAlgorithms/Rust/blob/master/src/compression/move_to_front.rs)
* Conversions
* [Binary To Decimal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/binary_to_decimal.rs)
* [Binary To Hexadecimal](https://github.com/TheAlgorithms/Rust/blob/master/src/conversions/binary_to_hexadecimal.rs)
Expand Down
2 changes: 2 additions & 0 deletions src/compression/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod move_to_front;
mod run_length_encoding;

pub use self::move_to_front::{move_to_front_decode, move_to_front_encode};
pub use self::run_length_encoding::{run_length_decode, run_length_encode};
60 changes: 60 additions & 0 deletions src/compression/move_to_front.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// https://en.wikipedia.org/wiki/Move-to-front_transform

fn blank_char_table() -> Vec<char> {
(0..=255).map(|ch| ch as u8 as char).collect()
}

pub fn move_to_front_encode(text: &str) -> Vec<u8> {
let mut char_table = blank_char_table();
let mut result = Vec::new();

for ch in text.chars() {
if let Some(position) = char_table.iter().position(|&x| x == ch) {
result.push(position as u8);
char_table.remove(position);
char_table.insert(0, ch);
}
}

result
}

pub fn move_to_front_decode(encoded: &[u8]) -> String {
let mut char_table = blank_char_table();
let mut result = String::new();

for &pos in encoded {
let ch = char_table[pos as usize];
result.push(ch);
char_table.remove(pos as usize);
char_table.insert(0, ch);
}

result
}

#[cfg(test)]
mod test {
use super::*;

macro_rules! test_mtf {
($($name:ident: ($text:expr, $encoded:expr),)*) => {
$(
#[test]
fn $name() {
assert_eq!(move_to_front_encode($text), $encoded);
assert_eq!(move_to_front_decode($encoded), $text);
}
)*
}
}

test_mtf! {
empty: ("", &[]),
single_char: ("@", &[64]),
repeated_chars: ("aaba", &[97, 0, 98, 1]),
mixed_chars: ("aZ!", &[97, 91, 35]),
word: ("banana", &[98, 98, 110, 1, 1, 1]),
special_chars: ("\0\n\t", &[0, 10, 10]),
}
}