From 65fe3e800b3fae423e93ee36effaee5adabb218c Mon Sep 17 00:00:00 2001 From: ridethepig Date: Thu, 23 Feb 2023 07:31:06 +0000 Subject: [PATCH] rdiif --- week2/ownership.txt | 11 +++++-- week2/rdiff/src/grid.rs | 19 +++++++---- week2/rdiff/src/main.rs | 73 +++++++++++++++++++++++++++++++++-------- 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/week2/ownership.txt b/week2/ownership.txt index e40b247..f6c8d65 100644 --- a/week2/ownership.txt +++ b/week2/ownership.txt @@ -9,8 +9,9 @@ fn main() { println!("{}", ref3.to_uppercase()); } ``` - - +Answer: + This code won't compile. Reference to mutable variable 's' is used later, so it shouldn't change before all borrows are returned to 's'. + If the 'println' is set above assignment of 's', it should be ok. Example 2: ``` @@ -20,6 +21,8 @@ fn drip_drop() -> &String { } ``` +Answer: + This code won't compile. It returns a reference, but when the function leaves, the owner will be dropped, the refernece becomes dangling, this is unacceptable. Example 3: @@ -32,3 +35,7 @@ fn main() { println!("{}", s2); } ``` + +Answer: + The ownership is transfered to `v` after push, that's good. + However, `let s2 = v[0]` requires for a ownership move(or Copy trait which String doesnt have), but 'Index operator []' returns a reference(&self::Output), so it couldn't been moved. diff --git a/week2/rdiff/src/grid.rs b/week2/rdiff/src/grid.rs index 5ed22a5..5416361 100644 --- a/week2/rdiff/src/grid.rs +++ b/week2/rdiff/src/grid.rs @@ -30,18 +30,25 @@ impl Grid { /// but others argue that makes code needlessly complex. Here, we decided to return Option to /// give you more practice with Option :) and because this similar library returns Option: /// https://docs.rs/array2d/0.2.1/array2d/struct.Array2D.html - #[allow(unused)] // TODO: delete this line when you implement this function pub fn get(&self, row: usize, col: usize) -> Option { - unimplemented!(); - // Be sure to delete the #[allow(unused)] line above + if row >= self.num_rows || col >= self.num_cols { + None + } + else { + Some(self.elems[row * self.num_cols + col]) + } } /// Sets the element at the specified location to the specified value. If the location is out /// of bounds, returns Err with an error message. - #[allow(unused)] // TODO: delete this line when you implement this function pub fn set(&mut self, row: usize, col: usize, val: usize) -> Result<(), &'static str> { - unimplemented!(); - // Be sure to delete the #[allow(unused)] line above + if row >= self.num_rows || col >= self.num_cols { + Err("Outof Boundry") + } + else { + self.elems[row * self.num_cols + col] = val; + Ok(()) + } } /// Prints a visual representation of the grid. You can use this for debugging. diff --git a/week2/rdiff/src/main.rs b/week2/rdiff/src/main.rs index 019c83c..4ce209f 100644 --- a/week2/rdiff/src/main.rs +++ b/week2/rdiff/src/main.rs @@ -7,30 +7,74 @@ use std::process; pub mod grid; /// Reads the file at the supplied path, and returns a vector of strings. -#[allow(unused)] // TODO: delete this line when you implement this function fn read_file_lines(filename: &String) -> Result, io::Error> { - unimplemented!(); - // Be sure to delete the #[allow(unused)] line above + let file = File::open(filename)?; + let mut lines = Vec::new(); + for line in io::BufReader::new(file).lines() { + lines.push(line.unwrap()); + } + Ok(lines) +} + +fn max(a: T, b: T) -> T { + if a > b { + a + } else { + b + } } -#[allow(unused)] // TODO: delete this line when you implement this function fn lcs(seq1: &Vec, seq2: &Vec) -> Grid { // Note: Feel free to use unwrap() in this code, as long as you're basically certain it'll // never happen. Conceptually, unwrap() is justified here, because there's not really any error // condition you're watching out for (i.e. as long as your code is written correctly, nothing // external can go wrong that we would want to handle in higher-level functions). The unwrap() // calls act like having asserts in C code, i.e. as guards against programming error. - unimplemented!(); - // Be sure to delete the #[allow(unused)] line above + let m = seq1.len(); + let n = seq2.len(); + let mut dp = Grid::new(m + 1, n + 1); + for i in 0..m + 1 { + dp.set(i, 0, 0).unwrap(); + } + for j in 0..n + 1 { + dp.set(0, j, 0).unwrap(); + } + for i in 0..m { + for j in 0..n { + if seq1[i] == seq2[j] { + dp.set(i + 1, j + 1, dp.get(i, j).unwrap() + 1).unwrap(); + } else { + dp.set( + i + 1, + j + 1, + max(dp.get(i + 1, j).unwrap(), dp.get(i, j + 1).unwrap()), + ) + .unwrap(); + } + } + } + dp } -#[allow(unused)] // TODO: delete this line when you implement this function fn print_diff(lcs_table: &Grid, lines1: &Vec, lines2: &Vec, i: usize, j: usize) { - unimplemented!(); - // Be sure to delete the #[allow(unused)] line above + if i > 0 && j > 0 && lines1[i - 1] == lines2[j - 1] { + // found the same line + print_diff(lcs_table, lines1, lines2, i - 1, j - 1); + println!(" {}", lines1[i - 1]) + } else if j > 0 + && (i == 0 || lcs_table.get(i, j - 1).unwrap() >= lcs_table.get(i -1, j).unwrap()) + { + // walk back along lines2, because it is a string out of LCS. + print_diff(lcs_table, lines1, lines2, i, j - 1); + println!("> {}", lines2[j - 1]) + } else if i > 0 + && (j == 0 || lcs_table.get(i, j - 1).unwrap() < lcs_table.get(i - 1, j).unwrap()) + { + print_diff(lcs_table, lines1, lines2, i - 1, j); + println!("< {}", lines1[i - 1]) + } } -#[allow(unused)] // TODO: delete this line when you implement this function fn main() { let args: Vec = env::args().collect(); if args.len() < 3 { @@ -39,9 +83,12 @@ fn main() { } let filename1 = &args[1]; let filename2 = &args[2]; - - unimplemented!(); - // Be sure to delete the #[allow(unused)] line above + let content1 = + read_file_lines(filename1).expect(format!("Cannot read file {}", filename1).as_str()); + let content2 = + read_file_lines(filename2).expect(format!("Cannot read file {}", filename2).as_str()); + let lsc_grid = lcs(&content1, &content2); + print_diff(&lsc_grid, &content1, &content2, content1.len(), content2.len()); } #[cfg(test)]