You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对Vec中按切片划分的序列进行字典序排序?

原地排序Vec中固定大小的分块元素(编译期未知块大小)

你之前的思路里,Chunk结构体是对原切片的引用,排序Chunk对象只会改变引用的顺序,完全不会影响底层的Vec数据——这就是问题所在。要实现对原数据的排序,不能直接排序引用,得通过排序块的索引来间接调整原数据的位置,或者用临时存储重新构建排序后的Vec。

方法一:原地置换(内存高效)

这种方法通过处理置换环来原地调整块的位置,不需要额外分配与原数据等大的内存,适合大数据量场景:

#[derive(PartialEq, Eq)]
struct Chunk<'a> {
    slice: &'a [usize],
}

impl<'a> PartialOrd for Chunk<'a> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.slice.partial_cmp(other.slice)
    }
}

impl<'a> Ord for Chunk<'a> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.slice.cmp(other.slice)
    }
}

impl<'a> Chunk<'a> {
    /// 将chunks视为长度为chunk_size的切片集合,原地排序该集合,保持每个切片完整。若chunks长度不是chunk_size的倍数会panic。
    pub fn sort_slice_of_chunks(chunks: &mut Vec<usize>, chunk_size: usize) {
        let n_slices = chunks.len() / chunk_size;
        assert_eq!(chunks.len(), n_slices * chunk_size, "chunks长度必须是chunk_size的整数倍");
        
        // 生成所有块的索引,并按块的字典序排序索引
        let mut indices: Vec<_> = (0..n_slices).collect();
        indices.sort_unstable_by(|&i, &j| {
            let chunk_i = &chunks[i * chunk_size..(i+1)*chunk_size];
            let chunk_j = &chunks[j * chunk_size..(j+1)*chunk_size];
            chunk_i.cmp(chunk_j)
        });
        
        // 通过置换环原地调整块的位置
        let mut visited = vec![false; n_slices];
        for i in 0..n_slices {
            if visited[i] {
                continue;
            }
            let mut current = i;
            while !visited[current] {
                visited[current] = true;
                let target = indices[current];
                if current != target {
                    // 交换两个块的全部元素
                    chunks.swap_ranges(
                        current * chunk_size..(current+1)*chunk_size,
                        target * chunk_size..(target+1)*chunk_size,
                    );
                }
                current = target;
            }
        }
    }
}

// 测试示例
fn main() {
    let mut data = vec![1, 2, 4, 1, 2, 3, 2, 2, 1];
    Chunk::sort_slice_of_chunks(&mut data, 3);
    assert_eq!(data, vec![1, 2, 3, 1, 2, 4, 2, 2, 1]);
    println!("排序成功: {:?}", data);
}

方法二:临时存储(代码简洁)

如果内存不是瓶颈,这种方法更简单:先按排序后的索引收集所有块,再替换原Vec:

impl<'a> Chunk<'a> {
    /// 简洁版实现:使用临时存储,代码更易读但会分配额外内存
    pub fn sort_slice_of_chunks_simple(chunks: &mut Vec<usize>, chunk_size: usize) {
        let n_slices = chunks.len() / chunk_size;
        assert_eq!(chunks.len(), n_slices * chunk_size, "chunks长度必须是chunk_size的整数倍");
        
        let mut indices: Vec<_> = (0..n_slices).collect();
        indices.sort_unstable_by(|&i, &j| {
            let chunk_i = &chunks[i * chunk_size..(i+1)*chunk_size];
            let chunk_j = &chunks[j * chunk_size..(j+1)*chunk_size];
            chunk_i.cmp(chunk_j)
        });
        
        let mut sorted = Vec::with_capacity(chunks.len());
        for &idx in &indices {
            sorted.extend_from_slice(&chunks[idx * chunk_size..(idx+1)*chunk_size]);
        }
        
        *chunks = sorted;
    }
}

关键说明

  • 不能直接通过排序Chunk引用修改原数据:因为Chunk只是原切片的视图,排序视图不会改变原数据的物理位置。
  • 两种方法的取舍:原地置换法内存效率更高,适合处理大体积数据;临时存储法代码更简洁,开发成本低,适合中小规模数据。

内容的提问来源于stack exchange,提问作者Erik P.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 05:22:07