Guest User

Untitled

a guest
Mar 9th, 2023
12
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 5.37 KB | None | 0 0
  1. use std::io;
  2. use std::fs;
  3. use std::path::Path;
  4. // This is a unique algorithm for compression that uses a combination of Huffman coding and run-length encoding.
  5. use std::collections::HashMap;
  6. use std::collections::BinaryHeap;
  7. #[derive(Eq, Ord, PartialEq, PartialOrd)]
  8. // This is the Huffman tree node.
  9. struct Node {
  10.     character: char,
  11.     frequency: usize,
  12.     left: Option<Box<Node>>,
  13.     right: Option<Box<Node>>,
  14. }
  15. // This function takes a string and returns a HashMap of characters and their frequencies.
  16. fn get_frequencies(input: &str) -> HashMap<char, usize> {
  17.     let mut frequencies = HashMap::new();
  18.     for c in input.chars() {
  19.         let count = frequencies.entry(c).or_insert(0);
  20.         *count += 1;
  21.     }
  22.     frequencies
  23. }
  24. // This function takes a HashMap of characters and their frequencies and returns a Huffman tree.
  25. fn build_huffman_tree(frequencies: &HashMap<char, usize>) -> Node {
  26.     let mut nodes: BinaryHeap<Node> = frequencies
  27.         .iter()
  28.         .map(|(&c, &f)| Node {
  29.             character: c,
  30.             frequency: f,
  31.             left: None,
  32.             right: None,
  33.         })
  34.         .collect();
  35.     while nodes.len() > 1 {
  36.         let min1 = nodes.pop().expect("Error: pop() method does not exist for BinaryHeap<Node>");
  37.         let min2 = nodes.pop().expect("Error: pop() method does not exist for BinaryHeap<Node>");
  38.         let frequency = min1.frequency + min2.frequency;
  39.         let node = Node {
  40.             left: Some(Box::new(min1)),
  41.             right: Some(Box::new(min2)),
  42.             frequency,
  43.             character: '\0',
  44.         };
  45.         nodes.push(node);
  46.     }
  47.     nodes.into_iter().next().unwrap()
  48. }
  49. // This function takes a Huffman tree and returns a HashMap of characters and their codes.
  50. fn get_codes(node: &Node) -> HashMap<char, String> {
  51.     let mut codes = HashMap::new();
  52.     let mut code = String::new();
  53.     get_codes_recursive(node, &mut codes, &mut code);
  54.     codes
  55. }
  56. fn get_codes_recursive(node: &Node, codes: &mut HashMap<char, String>, code: &mut String) {
  57.     match node {
  58.         Node {
  59.             character,
  60.             left: None,
  61.             right: None,
  62.             ..
  63.         } => {
  64.             codes.insert(*character, code.clone());
  65.         }
  66.         Node {
  67.             left,
  68.             right,
  69.             ..
  70.         } => {
  71.             code.push('0');
  72.             get_codes_recursive(left.as_ref().unwrap(), codes, code);
  73.             code.pop();
  74.  
  75.             code.push('1');
  76.             get_codes_recursive(right.as_ref().unwrap(), codes, code);
  77.             code.pop();
  78.         }
  79.     }
  80. }
  81. // This function takes a string and returns a run-length encoded string.
  82. fn run_length_encode(input: &str) -> String {
  83.     let mut output = String::new();
  84.     let mut current_char = '\0';
  85.     let mut current_count = 0;
  86.     for c in input.chars() {
  87.         if c == current_char {
  88.             current_count += 1;
  89.         } else {
  90.             if current_count > 0 {
  91.                 output.push_str(&format!("{}{}", current_count, current_char));
  92.             }
  93.             current_char = c;
  94.             current_count = 1;
  95.         }
  96.     }
  97.     if current_count > 0 {
  98.         output.push_str(&format!("{}{}", current_count, current_char));
  99.     }
  100.     output
  101. }
  102. // This function takes a string and returns a compressed string using the LZW algorithm.
  103. fn lzw_compress(input: &str) -> String {
  104.     let mut output = String::new();
  105.     let mut dictionary = HashMap::new();
  106.     let mut current_string = String::new();
  107.     let mut next_code = 0;
  108.     for c in input.chars() {
  109.         let mut string = current_string.clone();
  110.         string.push(c);
  111.         if dictionary.contains_key(&string) {
  112.             current_string = string;
  113.         } else {
  114.             output.push_str(&format!("{}", dictionary.get(&current_string).unwrap()));
  115.             dictionary.insert(string, next_code);
  116.             next_code += 1;
  117.             current_string = c.to_string();
  118.         }
  119.     }
  120.     output.push_str(&format!("{}", dictionary.get(&current_string).unwrap()));
  121.     output
  122. }
  123.  
  124. // This function takes a string and returns a compressed string.
  125. fn compress(input: &str) -> String {
  126.     let frequencies = get_frequencies(input);
  127.     let tree = build_huffman_tree(&frequencies);
  128.     let codes = get_codes(&tree);
  129.     let encoded = input
  130.         .chars()
  131.         .map(|c| codes.get(&c).unwrap().to_string())
  132.         .collect::<Vec<String>>()
  133.         .join("");
  134.     let lzw_encoded = lzw_compress(&encoded);
  135.     let run_length_encoded = run_length_encode(&lzw_encoded);
  136.     run_length_encoded
  137. }
  138.  
  139. fn main() {
  140.     println!("Welcome to the Compression Program!");
  141.     println!("Please enter the path of the file you would like to compress:");
  142.     let mut input_path = String::new();
  143.     io::stdin().read_line(&mut input_path).expect("Failed to read line");
  144.     let input_path = input_path.trim();
  145.     println!("Please enter the path of the output file:");
  146.     let mut output_path = String::new();
  147.     io::stdin().read_line(&mut output_path).expect("Failed to read line");
  148.     let output_path = output_path.trim();
  149.     let input_data = fs::read_to_string(input_path).expect("Failed to read file");
  150.     let compressed_data = compress(&input_data);
  151.     let output_file = Path::new(&output_path);
  152.     fs::write(output_file, compressed_data).expect("Failed to write file");
  153.  
  154.     println!("Compression complete!");
  155. }
Advertisement
Add Comment
Please, Sign In to add comment