根号n段合并排序算法(详细注释)-Rust语言编写

题目:

n \sqrt{n} n 段合并排序算法:

将数组 a [ 0 , n − 1 ] a[0,n-1] a[0,n1]划分为 ⌊ n ⌋ ⌊\sqrt{n}⌋ n 个子数组,每个子数组有 O ( n ) O(\sqrt{n}) O(n )个元素。然后递归地对分割后的子数组进行排序,最后将所得到的 ⌊ n ⌋ ⌊\sqrt{n}⌋ n 个排好序的子数组合并排序。

解法:

use rand::prelude::*;

fn square_merge_sort(a: &mut Vec<usize>, start: usize, end: usize) {
    let num = ((end - start + 1) as f64).sqrt() as usize;

    if num > 1 {
        // 前 num - 1 个子数组,数组中元素个数为 num
        for i in 0..num - 1 {
            square_merge_sort(a, start + i * num, start + (i + 1) * num - 1);
        }
        // 第 num 个子数组,数组中元素个数可能大于 num
        square_merge_sort(a, start + (num - 1) * num, end);
        // 进行合并
        merge(a, start, end, num);
    } else {
        // 当 num 为 1 时进行直接排序,即子数组元素个数为 1、2、3 的情况
        sort_num_equal_1(a, start, end);
    }
}

fn sort_num_equal_1(a: &mut Vec<usize>, start: usize, end: usize) {
    let num = end - start + 1;
    // 当个数为 1 时直接返回
    if num == 1 {
        return;
    }
    // 当个数为 2 时的处理
    if a[start] > a[start + 1] {
        a.swap(start, start + 1);
    }
    if num == 3 {
        if a[start] > a[start + 2] {
            a.swap(start, start + 2);
        }
        if a[start + 1] > a[start + 2] {
            a.swap(start + 1, start + 2);
        }
    }
}

fn merge(a: &mut Vec<usize>, start: usize, end: usize, num: usize) {
    // 新建一个辅助数组
    let mut tmp: Vec<usize> = Vec::new();
    // 记录每一个子数组当前的索引位置,用于判断子数组是否添加完成
    let mut part_index: Vec<usize> = Vec::new();
    for _ in 0..num {
        part_index.push(0);
    }
    for _ in 0..end - start + 1 {
        let mut min = usize::MAX;
        let mut index: usize = 0;
        for i in 0..num {
            // 如果子数组已经全部添加,则跳过这个子数组,直接遍历下一个子数组,这边要分是前 num 个子数组还是第 num 个子数组两种情况(因为第 num 个子数组个数不一定是 num )
            if (i != num - 1 && part_index[i] == num) || (i == num - 1 && part_index[i] == end - start + 1 - (num - 1) * num) {
                continue;
            }
            // 寻找各子数组中的最小值,并做标记是哪一个子数组
            if min > a[start + i * (num) + part_index[i]] {
                min = a[start + i * (num) + part_index[i]];
                index = i;
            }
        }
        // 当前有最小值的子数组索引加 1,表示当前的值已经作为最小值添加过
        part_index[index] = part_index[index] + 1;
        tmp.push(min);
    }
    // 修改原数组
    for i in 0..end - start + 1 {
        a[start + i] = tmp[i];
    }
}
fn main() {

    // 1、创建一个数组
    let mut a: Vec<usize> = Vec::new();

    // 2、在数据中生成 50个 0~100 的随机数
    let mut rng = rand::thread_rng();
    for _ in 0..50 {
        a.push(rng.gen_range(0..101));
    }

    // 3、打印生成的原数组
    for (_, num) in a.iter().enumerate() {
        print!("{} ", num);
    }

    // 4、进行排序
    let length = a.len();
    square_merge_sort(&mut a, 0, length - 1);

    // 5、打印排序后的数组
    println!("");
    for (_, num) in a.iter().enumerate() {
        print!("{} ", num);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值