From bb695089bf3a6894743f138ae377c839f06ea69d Mon Sep 17 00:00:00 2001 From: Ythan Zhang Date: Sat, 30 Mar 2024 12:29:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20=E5=86=92=E6=B3=A1?= =?UTF-8?q?=E6=8E=92=E5=BA=8F=E3=80=81=E9=80=89=E6=8B=A9=E6=8E=92=E5=BA=8F?= =?UTF-8?q?=E3=80=81=E6=8F=92=E5=85=A5=E6=8E=92=E5=BA=8F=E3=80=81=E5=BD=92?= =?UTF-8?q?=E5=B9=B6=E6=8E=92=E5=BA=8F=E3=80=81=E5=BF=AB=E9=80=9F=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=20=E7=9A=84Rust=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + 1.bubbleSort.md | 20 +++ 2.selectionSort.md | 17 +++ 3.insertionSort.md | 16 +++ 5.mergeSort.md | 141 ++++++++++++++++++++ 6.quickSort.md | 32 ++++- src/rust/Cargo.lock | 75 +++++++++++ src/rust/Cargo.toml | 10 ++ src/rust/src/main.rs | 311 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 623 insertions(+), 1 deletion(-) create mode 100644 src/rust/Cargo.lock create mode 100644 src/rust/Cargo.toml create mode 100644 src/rust/src/main.rs diff --git a/.gitignore b/.gitignore index f6cbc5f..e71fbee 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ _book *.iml src/javaSortTest/target/ + +src/rust/target/ diff --git a/1.bubbleSort.md b/1.bubbleSort.md index 78c3b83..824b659 100644 --- a/1.bubbleSort.md +++ b/1.bubbleSort.md @@ -129,3 +129,23 @@ function bubbleSort($arr) return $arr; } ``` + +## 10. Rust 代码实现 + +```rust +fn bubble_sort(slice: &mut [T]) { + for i in 1..=slice.len() { + for j in 0..(slice.len() - i) { + match slice[j].cmp(&slice[j + 1]) { + Ordering::Less | Ordering::Equal => { + // Do nothing + } + Ordering::Greater => { + slice.swap(j, j + 1); + } + } + } + } +} +``` + \ No newline at end of file diff --git a/2.selectionSort.md b/2.selectionSort.md index 103830e..8d3badf 100644 --- a/2.selectionSort.md +++ b/2.selectionSort.md @@ -126,3 +126,20 @@ function selectionSort($arr) return $arr; } ``` + +## 8. Rust 代码实现 + +```rust +fn selection_sort(slice: &mut [T]) { + for i in 0..slice.len() { + let mut selected = i; + for j in (i + 1)..slice.len() { + if slice[j] < slice[selected] { + selected = j; + } + } + + slice.swap(i, selected); + } +} +``` diff --git a/3.insertionSort.md b/3.insertionSort.md index c828cb3..41a8672 100644 --- a/3.insertionSort.md +++ b/3.insertionSort.md @@ -118,3 +118,19 @@ function insertionSort($arr) return $arr; } ``` + +## 8. Rust 代码实现 + +```rust +fn insertion_sort(slice: &mut [T]) { + for i in 1..slice.len() { + for j in (1..=i).rev() { + if slice[j] < slice[j - 1] { + slice.swap(j, j - 1); + } else { + break; + } + } + } +} +``` diff --git a/5.mergeSort.md b/5.mergeSort.md index c030d8f..60996e7 100644 --- a/5.mergeSort.md +++ b/5.mergeSort.md @@ -260,3 +260,144 @@ void mergeSort(vector& arr, int l, int r) { // sort the range [l, r) in arr merge(arr, l, mid, r); } ``` + +## 10. Rust 代码实现 + +```rust +/// 实现 1: +/// Safe Rust 实现,需要大量浅复制(move),但不需要深拷贝,对primitive type排序较慢,但对没有 Copy Trait 的类型较快 +fn merge_sort(mut v: Vec) -> Vec { + if v.len() < 2 { + return v; + } + + // Split the right half and sort them first + let mut right = merge_sort(v.split_off(v.len() / 2)); + let mut left = merge_sort(v); + + let mut result = Vec::new(); + + // 反向merge,因为 `Vec::remove(0)` 的复杂度是 `O(n)` 而且需要大量复制 + while !left.is_empty() && !right.is_empty() { + if left.last().unwrap() > right.last().unwrap() { + result.push(left.pop().unwrap()); + } else { + result.push(right.pop().unwrap()); + } + } + result.extend(left.into_iter().rev()); + result.extend(right.into_iter().rev()); + result.reverse(); + + result +} + + +/// 实现 2: +/// Safe Rust 实现,使用相对更少的复制,但需要更多的深拷贝。Primitive type排序速度更快,需要深拷贝的类型速度更慢 +fn merge_sort2(v: &mut [T]) { + if v.len() < 2 { + return; + } + + let mid_idx = v.len() / 2; + + merge_sort2(&mut v[..mid_idx]); + merge_sort2(&mut v[mid_idx..]); + + let mut temporary = Vec::with_capacity(v.len()); + + let mut l = 0; + let mut r = mid_idx; + + while l < mid_idx && r < v.len() { + if v[l] < v[r] { + temporary.push(v[l].clone()); + l += 1; + } else { + temporary.push(v[r].clone()); + r += 1; + } + } + temporary.extend(v[l..mid_idx].iter().cloned()); + temporary.extend(v[r..].iter().cloned()); + + for (item, dest) in temporary.into_iter().zip(v.iter_mut()) { + *dest = item; + } +} + + +/// 实现 3: +/// Unsafe Rust 实现,类似实现2,但使用 unsafe 避免了深拷贝,性能优于实现1与实现2 +fn merge_sort3(v: &mut [T]) { + if v.len() < 2 { + return; + } + + // 可以在遇到较短的数组时使用插入排序,性能较佳。但即使不使用插入排序,此实现性能依然优于实现1与实现2 + if v.len() < 32 { + insertion_sort(v); + return; + } + + let mid_idx = v.len() / 2; + + merge_sort3(&mut v[..mid_idx]); + merge_sort3(&mut v[mid_idx..]); + + let alloc_array = |size: usize| -> *mut T { + // 等同于C中: `(T*)malloc(sizeof(T) * size)` + unsafe { + std::alloc::alloc( + std::alloc::Layout::array::(size).unwrap_unchecked(), + ) as *mut T + } + }; + let dealloc_array = |ptr: *mut T, size: usize| unsafe { + // 等同于C中: `free(ptr)` + std::alloc::dealloc( + ptr as *mut u8, + std::alloc::Layout::array::(size).unwrap_unchecked(), + ) + }; + + let temporary = alloc_array(v.len()); + let mut used_len = 0; + + let mut l = 0; + let mut r = mid_idx; + + unsafe { + while l < mid_idx && r < v.len() { + if v[l] < v[r] { + temporary + .add(used_len) + .copy_from_nonoverlapping(v.as_ptr().add(l), 1); + l += 1; + } else { + temporary + .add(used_len) + .copy_from_nonoverlapping(v.as_ptr().add(r), 1); + r += 1; + } + used_len += 1; + } + + let left_remain = mid_idx - l; + temporary + .add(used_len) + .copy_from_nonoverlapping(v.as_ptr().add(l), left_remain); + used_len += left_remain; + + let right_remain = v.len() - r; + temporary + .add(used_len) + .copy_from_nonoverlapping(v.as_ptr().add(r), right_remain); + + v.as_mut_ptr().copy_from_nonoverlapping(temporary, v.len()); + } + + dealloc_array(temporary, v.len()); +} +``` diff --git a/6.quickSort.md b/6.quickSort.md index 28ad477..3ec2e26 100644 --- a/6.quickSort.md +++ b/6.quickSort.md @@ -156,7 +156,7 @@ func swap(arr []int, i, j int) { ## 6. C++版 -```C++ +```cpp //严蔚敏《数据结构》标准分割函数 Paritition1(int A[], int low, int high) { int pivot = A[low]; @@ -253,3 +253,33 @@ function quickSort($arr) return array_merge($leftArray, $rightArray); } ``` + +## 9. Rust 代码实现 + +```rust +fn quick_sort(slice: &mut [T]) { + const PIVOT: usize = 0; + + match slice.len().cmp(&2) { + Ordering::Less => {} + Ordering::Equal => { + if slice[0] > slice[1] { + slice.swap(0, 1); + } + } + Ordering::Greater => { + let mut swap_point = 0; + for i in 1..slice.len() { + if slice[i] < slice[PIVOT] { + swap_point += 1; + slice.swap(swap_point, i); + } + } + slice.swap(PIVOT, swap_point); + + quick_sort(&mut slice[..swap_point]); + quick_sort(&mut slice[(swap_point + 1)..]); + } + } +} +``` diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock new file mode 100644 index 0000000..397f238 --- /dev/null +++ b/src/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml new file mode 100644 index 0000000..f53ffc8 --- /dev/null +++ b/src/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +rand = "0.8" diff --git a/src/rust/src/main.rs b/src/rust/src/main.rs new file mode 100644 index 0000000..9d68c8b --- /dev/null +++ b/src/rust/src/main.rs @@ -0,0 +1,311 @@ +use std::cmp::Ordering; +use rand::Rng; + + +fn main() { + let mut rng = rand::thread_rng(); + + const ARRAY_LENGTH: usize = 10000; + let mut generate_random_sequence_i32 = || { + (0..ARRAY_LENGTH) + .map(|_| rng.gen_range(0..i32::MAX)) + .collect::>() + }; + + let mut tests = + (0..10).map(|_| generate_random_sequence_i32()).collect::>(); + + let mut sorted_bubble = tests.clone(); + println!( + "bubble sort took: {:?}", + timed_sort(&mut sorted_bubble, bubble_sort) + ); + + let mut sorted_select = tests.clone(); + println!( + "selection sort took: {:?}", + timed_sort(&mut sorted_select, selection_sort) + ); + + let mut sorted_insertion = tests.clone(); + println!( + "insertion sort took: {:?}", + timed_sort(&mut sorted_insertion, insertion_sort) + ); + + let (sorted_merge, merge_sort_time) = + timed_sort2(tests.clone(), merge_sort); + println!("merge sort took: {:?}", merge_sort_time); + + let mut sorted_merge2 = tests.clone(); + println!( + "merge sort2 took: {:?}", + timed_sort(&mut sorted_merge2, merge_sort2) + ); + + let mut sorted_merge3 = tests.clone(); + println!( + "merge sort3 took: {:?}", + timed_sort(&mut sorted_merge3, merge_sort3) + ); + + let mut sorted_quick = tests.clone(); + println!( + "quick sort took: {:?}", + timed_sort(&mut sorted_quick, quick_sort) + ); + + fn rust_sort(v: &mut [impl Ord]) { + v.sort(); + } + println!( + "inbuilt merge sort took: {:?}", + timed_sort(&mut tests, rust_sort) + ); + + assert_eq!(sorted_bubble, tests); + assert_eq!(sorted_select, tests); + assert_eq!(sorted_insertion, tests); + assert_eq!(sorted_merge, tests); + assert_eq!(sorted_merge2, tests); + assert_eq!(sorted_merge3, tests); + assert_eq!(sorted_quick, tests); +} + + +fn bubble_sort(slice: &mut [T]) { + for i in 1..=slice.len() { + for j in 0..(slice.len() - i) { + match slice[j].cmp(&slice[j + 1]) { + Ordering::Less | Ordering::Equal => { + // Do nothing + } + Ordering::Greater => { + slice.swap(j, j + 1); + } + } + } + } +} + + +fn selection_sort(slice: &mut [T]) { + for i in 0..slice.len() { + let mut selected = i; + for j in (i + 1)..slice.len() { + if slice[j] < slice[selected] { + selected = j; + } + } + + slice.swap(i, selected); + } +} + + +fn insertion_sort(slice: &mut [T]) { + for i in 1..slice.len() { + for j in (1..=i).rev() { + if slice[j] < slice[j - 1] { + slice.swap(j, j - 1); + } else { + break; + } + } + } +} + + +/// 实现 1: +/// 此实现需要大量浅复制(move),但不需要深拷贝,对primitive type排序较慢,但对没有 Copy Trait 的类型较快 +fn merge_sort(mut v: Vec) -> Vec { + if v.len() < 2 { + return v; + } + + // Split the right half and sort them first + let mut right = merge_sort(v.split_off(v.len() / 2)); + let mut left = merge_sort(v); + + let mut result = Vec::new(); + + // 反向merge,因为 `Vec::remove(0)` 的复杂度是 `O(n)` 而且需要大量复制 + while !left.is_empty() && !right.is_empty() { + if left.last().unwrap() > right.last().unwrap() { + result.push(left.pop().unwrap()); + } else { + result.push(right.pop().unwrap()); + } + } + result.extend(left.into_iter().rev()); + result.extend(right.into_iter().rev()); + result.reverse(); + + result +} + + +/// 实现 2: +/// 此实现使用了相对更少的复制,但需要更多的深拷贝。Primitive type排序速度更快,需要深拷贝的类型速度更慢 +fn merge_sort2(v: &mut [T]) { + if v.len() < 2 { + return; + } + + let mid_idx = v.len() / 2; + + merge_sort2(&mut v[..mid_idx]); + merge_sort2(&mut v[mid_idx..]); + + let mut temporary = Vec::with_capacity(v.len()); + + let mut l = 0; + let mut r = mid_idx; + + while l < mid_idx && r < v.len() { + if v[l] < v[r] { + temporary.push(v[l].clone()); + l += 1; + } else { + temporary.push(v[r].clone()); + r += 1; + } + } + temporary.extend(v[l..mid_idx].iter().cloned()); + temporary.extend(v[r..].iter().cloned()); + + for (item, dest) in temporary.into_iter().zip(v.iter_mut()) { + *dest = item; + } +} + + +/// 实现 3: +/// 此实现类似实现2,但使用 unsafe 避免了深拷贝,性能优于实现1与实现2 +fn merge_sort3(v: &mut [T]) { + if v.len() < 2 { + return; + } + + // 可以在遇到较短的数组时使用插入排序,性能较佳。但即使不使用插入排序,此实现性能依然优于实现1与实现2 + if v.len() < 32 { + insertion_sort(v); + return; + } + + let mid_idx = v.len() / 2; + + merge_sort3(&mut v[..mid_idx]); + merge_sort3(&mut v[mid_idx..]); + + let alloc_array = |size: usize| -> *mut T { + // 等同于C中: `(T*)malloc(sizeof(T) * size)` + unsafe { + std::alloc::alloc( + std::alloc::Layout::array::(size).unwrap_unchecked(), + ) as *mut T + } + }; + let dealloc_array = |ptr: *mut T, size: usize| unsafe { + // 等同于C中: `free(ptr)` + std::alloc::dealloc( + ptr as *mut u8, + std::alloc::Layout::array::(size).unwrap_unchecked(), + ) + }; + + let temporary = alloc_array(v.len()); + let mut used_len = 0; + + let mut l = 0; + let mut r = mid_idx; + + unsafe { + while l < mid_idx && r < v.len() { + if v[l] < v[r] { + temporary + .add(used_len) + .copy_from_nonoverlapping(v.as_ptr().add(l), 1); + l += 1; + } else { + temporary + .add(used_len) + .copy_from_nonoverlapping(v.as_ptr().add(r), 1); + r += 1; + } + used_len += 1; + } + + let left_remain = mid_idx - l; + temporary + .add(used_len) + .copy_from_nonoverlapping(v.as_ptr().add(l), left_remain); + used_len += left_remain; + + let right_remain = v.len() - r; + temporary + .add(used_len) + .copy_from_nonoverlapping(v.as_ptr().add(r), right_remain); + + v.as_mut_ptr().copy_from_nonoverlapping(temporary, v.len()); + } + + dealloc_array(temporary, v.len()); +} + + + +fn quick_sort(slice: &mut [T]) { + const PIVOT: usize = 0; + + match slice.len().cmp(&2) { + Ordering::Less => {} + Ordering::Equal => { + if slice[0] > slice[1] { + slice.swap(0, 1); + } + } + Ordering::Greater => { + let mut swap_point = 0; + for i in 1..slice.len() { + if slice[i] < slice[PIVOT] { + swap_point += 1; + slice.swap(swap_point, i); + } + } + slice.swap(PIVOT, swap_point); + + quick_sort(&mut slice[..swap_point]); + quick_sort(&mut slice[(swap_point + 1)..]); + } + } +} + + +fn timed_sort(values: &mut [Vec], sort_fn: F) -> std::time::Duration + where + T: Ord, + F: Fn(&mut [T]), + { + let start = std::time::Instant::now(); + for v in values.iter_mut() { + sort_fn(v.as_mut_slice()); + } + + start.elapsed() / values.len() as u32 + } + + fn timed_sort2( + values: Vec>, + sort_fn: F, + ) -> (Vec>, std::time::Duration) + where + T: Ord, + F: Fn(Vec) -> Vec, + { + let v_len = values.len() as u32; + + let start = std::time::Instant::now(); + let result = values.into_iter().map(sort_fn).collect(); + (result, start.elapsed() / v_len) + }