一、递归
定义:函数直接或者间接调用自身的一种编程技巧,通过将问题分解为更小的同类子问题来解决;
关键要素:①递归终止的条件,防止无线循环;②递归条件:将问题分解为更小规模的同类问题;
经典递归问题:
①阶乘的计算:计算 n! = n × (n-1) × ... × 1。
pub fn factorial(n: u32) -> u32 {
if n == 0 {
1
} else {
n * factorial(n - 1)
}
}
②斐波那契数列:求第 n 项的值,满足 F(n) = F(n-1) + F(n-2),且 F(0)=0, F(1)=1。
pub fn fibonacci(n: u32) -> u32 {
if n == 0 {
0
} else if n == 1 {
1
} else {
fibonacci(n - 1) + fibonacci(n - 2)
}
}
二、排序
常见的排序算法:冒泡、插入、选择、快速、归并等
冒泡排序:重复遍历要排序的列表,比较相邻的两个元素,如果顺序错误就交换,直到列表被完全排序;
//generic
fn generic_bubble_sort<T: PartialOrd>(arr: &mut [T]) {
let len = arr.len();
for i in 0..len {
let mut swapped = false;
for j in 0..(len - i - 1) {
if arr[j] > arr[j + 1] {
arr.swap(j, j + 1);
swapped = true;
}
}
if !swapped {
break;
}
}
}
fn main() {
let mut numbers = [64, 34, 25, 12, 22, 11, 90];
generic_bubble_sort(&mut numbers);
println!("Ordered numbers: {:?}", numbers);
let mut words = ["banana", "apple", "cherry", "date"];
generic_bubble_sort(&mut words);
println!("Ordered words: {:?}", words);
}
插入排序:
将需要排序的一个数组,分为已经排序和未排序的两个区间,初始排序开始,已经排序只有一个元素,然后从未排序的区间取出一个元素放到已经排序的区间里面合适位置放下,直到未排序区间为空为止;
// 为泛型类型 T 实现插入排序,要求 T 可比较且可拷贝(适用于基本数据类型)
fn insertion_sort<T: PartialOrd + Copy>(arr: &mut [T]) {
// 从第二个元素开始遍历(索引 1)
for i in 1..arr.len() {
let key = arr[i]; // 当前待插入元素
let mut j = i; // 从右向左查找插入位置
// 将比 key 大的元素向右移动
while j > 0 && arr[j - 1] > key {
arr[j] = arr[j - 1];
j -= 1;
}
arr[j] = key; // 插入 key 到正确位置
}
}
// 测试代码
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty() {
let mut arr: Vec<i32> = vec![];
insertion_sort(&mut arr);
assert_eq!(arr, vec![]);
}
#[test]
fn test_single_element() {
let mut arr = vec![5];
insertion_sort(&mut arr);
assert_eq!(arr, vec![5]);
}
#[test]
fn test_sorted() {
let mut arr = vec![1, 2, 3, 4, 5];
insertion_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_reverse_sorted() {
let mut arr = vec![5, 4, 3, 2, 1];
insertion_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_random() {
let mut arr = vec![3, 1, 4, 1, 5, 9, 2, 6];
insertion_sort(&mut arr);
assert_eq!(arr, vec![1, 1, 2, 3, 4, 5, 6, 9]);
}
}
// 示例用法
fn main() {
let mut numbers = vec![3, 7, 1, 4, 2, 5];
println!("排序前: {:?}", numbers); // 排序前: [3, 7, 1, 4, 2, 5]
insertion_sort(&mut numbers);
println!("排序后: {:?}", numbers); // 排序后: [1, 2, 3, 4, 5, 7]
}
选择排序:
选择排序的思路和插入排序差不多,但是选在排序是从未排序区间取最小值出来放到已经排序区间的合适位置即可;
// 泛型选择排序实现 (T 需要满足可比较特性)
fn selection_sort<T: PartialOrd>(arr: &mut [T]) {
let len = arr.len();
// 遍历所有元素(最后一个元素无需处理)
for i in 0..len {
// 假设当前索引是最小值的位置
let mut min_index = i;
// 在剩余元素中查找实际最小值
for j in (i + 1)..len {
if arr[j] < arr[min_index] {
min_index = j;
}
}
// 将最小值交换到正确位置
arr.swap(i, min_index);
}
}
// 测试模块
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty() {
let mut arr: Vec<i32> = vec![];
selection_sort(&mut arr);
assert_eq!(arr, vec![]);
}
#[test]
fn test_single_element() {
let mut arr = vec![5];
selection_sort(&mut arr);
assert_eq!(arr, vec![5]);
}
#[test]
fn test_sorted() {
let mut arr = vec![1, 2, 3, 4, 5];
selection_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_reverse_sorted() {
let mut arr = vec![5, 4, 3, 2, 1];
selection_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_random() {
let mut arr = vec![3, 1, 4, 1, 5, 9, 2, 6];
selection_sort(&mut arr);
assert_eq!(arr, vec![1, 1, 2, 3, 4, 5, 6, 9]);
}
}
// 示例用法
fn main() {
// 测试整数排序
let mut numbers = vec![3, 7, 1, 4, 2, 5];
println!("排序前: {:?}", numbers); // 排序前: [3, 7, 1, 4, 2, 5]
selection_sort(&mut numbers);
println!("排序后: {:?}", numbers); // 排序后: [1, 2, 3, 4, 5, 7]
// 测试浮点数排序
let mut floats = vec![3.2, 1.8, 4.5, 1.1, 5.0];
selection_sort(&mut floats);
println!("排序后 floats: {:?}", floats); // [1.1, 1.8, 3.2, 4.5, 5.0]
// 测试字符串排序
let mut words = vec!["banana", "apple", "cherry", "date"];
selection_sort(&mut words);
println!("排序后 words: {:?}", words); // ["apple", "banana", "cherry", "date"]
}
归并排序:
思路:将需要排序的数组从中间分为两部分,分别将两个部分进行排序之后合并在一起;
// 归并排序实现(泛型版本,支持所有可比较类型)
fn merge_sort<T: Ord + Clone>(arr: &mut [T]) {
let len = arr.len();
if len <= 1 {
return; // 基线条件:空数组或单元素数组直接返回
}
// 分割数组为左右两部分
let mid = len / 2;
let mut left = arr[..mid].to_vec(); // 使用 to_vec 创建拷贝
let mut right = arr[mid..].to_vec();
// 递归排序左右子数组
merge_sort(&mut left);
merge_sort(&mut right);
// 合并排序后的子数组
merge(arr, &left, &right);
}
// 合并两个有序数组
fn merge<T: Ord + Clone>(arr: &mut [T], left: &[T], right: &[T]) {
let (mut i, mut j, mut k) = (0, 0, 0);
let (left_len, right_len) = (left.len(), right.len());
// 比较左右数组元素并按顺序合并
while i < left_len && j < right_len {
if left[i] <= right[j] {
arr[k] = left[i].clone();
i += 1;
} else {
arr[k] = right[j].clone();
j += 1;
}
k += 1;
}
// 处理剩余元素
while i < left_len {
arr[k] = left[i].clone();
i += 1;
k += 1;
}
while j < right_len {
arr[k] = right[j].clone();
j += 1;
k += 1;
}
}
// 测试模块
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty() {
let mut arr: Vec<i32> = vec![];
merge_sort(&mut arr);
assert_eq!(arr, vec![]);
}
#[test]
fn test_single_element() {
let mut arr = vec![5];
merge_sort(&mut arr);
assert_eq!(arr, vec![5]);
}
#[test]
fn test_already_sorted() {
let mut arr = vec![1, 2, 3, 4, 5];
merge_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_reverse_sorted() {
let mut arr = vec![5, 4, 3, 2, 1];
merge_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_random() {
let mut arr = vec![3, 1, 4, 1, 5, 9, 2, 6];
merge_sort(&mut arr);
assert_eq!(arr, vec![1, 1, 2, 3, 4, 5, 6, 9]);
}
}
// 示例用法
fn main() {
// 测试整数排序
let mut numbers = vec![3, 7, 1, 4, 2, 5];
println!("排序前: {:?}", numbers); // 排序前: [3, 7, 1, 4, 2, 5]
merge_sort(&mut numbers);
println!("排序后: {:?}", numbers); // 排序后: [1, 2, 3, 4, 5, 7]
// 测试字符串排序
let mut words = vec!["banana", "apple", "cherry", "date"];
merge_sort(&mut words);
println!("排序后 words: {:?}", words); // ["apple", "banana", "cherry", "date"]
}
快速排序:
对于需要排序的数组从中选取一个节点为z节点,遍历数组,和z节点进行比较,将z节点放到中间,大于z节点放在右边,小于z节点放在左边,最后再进行递归排序即可;
// 快速排序实现(泛型版本,支持所有可比较类型)
fn quick_sort<T: Ord>(arr: &mut [T]) {
if arr.len() <= 1 {
return; // 基线条件:空数组或单元素数组直接返回
}
// 选择基准并分区
let pivot_index = partition(arr);
// 递归排序左右子数组
let (left, right) = arr.split_at_mut(pivot_index);
quick_sort(left);
quick_sort(&mut right[1..]); // 跳过基准元素
}
// 分区函数(Lomuto 分区方案)
fn partition<T: Ord>(arr: &mut [T]) -> usize {
// 选择中间元素作为基准(避免最坏情况)
let pivot_index = arr.len() / 2;
arr.swap(pivot_index, arr.len() - 1); // 移动基准到末尾
let mut i = 0;
for j in 0..arr.len() - 1 {
if arr[j] <= arr[arr.len() - 1] {
arr.swap(i, j);
i += 1;
}
}
// 将基准元素放到正确位置
arr.swap(i, arr.len() - 1);
i
}
// 测试模块
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty() {
let mut arr: Vec<i32> = vec![];
quick_sort(&mut arr);
assert_eq!(arr, vec![]);
}
#[test]
fn test_single_element() {
let mut arr = vec![5];
quick_sort(&mut arr);
assert_eq!(arr, vec![5]);
}
#[test]
fn test_already_sorted() {
let mut arr = vec![1, 2, 3, 4, 5];
quick_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_reverse_sorted() {
let mut arr = vec![5, 4, 3, 2, 1];
quick_sort(&mut arr);
assert_eq!(arr, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_random() {
let mut arr = vec![3, 1, 4, 1, 5, 9, 2, 6];
quick_sort(&mut arr);
assert_eq!(arr, vec![1, 1, 2, 3, 4, 5, 6, 9]);
}
#[test]
fn test_duplicates() {
let mut arr = vec![5, 3, 5, 3, 5];
quick_sort(&mut arr);
assert_eq!(arr, vec![3, 3, 5, 5, 5]);
}
}
// 示例用法
fn main() {
// 测试整数排序
let mut numbers = vec![3, 7, 1, 4, 2, 5];
println!("排序前: {:?}", numbers); // 排序前: [3, 7, 1, 4, 2, 5]
quick_sort(&mut numbers);
println!("排序后: {:?}", numbers); // 排序后: [1, 2, 3, 4, 5, 7]
// 测试字符串排序
let mut words = vec!["banana", "apple", "cherry", "date"];
quick_sort(&mut words);
println!("排序后 words: {:?}", words); // ["apple", "banana", "cherry", "date"]
}
967

被折叠的 条评论
为什么被折叠?



