@ -237,6 +237,159 @@ fn main() {
最后,如果你想要了解 `Vector` 更多的用法,请参见本书的标准库解析章节:[`Vector`常用方法](https://course.rs/std/vector.html)
## Vector 的排序
在 rust 里,实现了两种排序算法,分别为稳定的排序 `sort` 和 `sort_by` ,以及非稳定排序 `sort_unstable` 和 `sort_unstable_by` 。
当然,这个所谓的 `非稳定` 并不是指排序算法本身不稳定,而是指在排序过程中对相等元素的处理方式。在 `稳定` 排序算法里,对相等的元素,不会对其进行重新排序。而在 `不稳定` 的算法里则不保证这点。
总体而言,`非稳定` 排序的算法的速度会由于 `稳定` 排序算法,同时,`稳定` 排序还会额外分配原数组一半的空间。
### 整数数组的排序
以下是对整数列进行排序的例子。
```rust
fn main() {
let mut vec = vec![1, 5, 10, 2, 15];
vec.sort_unstable();
assert_eq!(vec, vec![1, 2, 5, 10, 15]);
}
```
### 浮点数数组的排序
我们尝试使用上面的方法来对浮点数进行排序:
```rust
fn main() {
let mut vec = vec![1.0, 5.6, 10.3, 2.0, 15f32];
vec.sort_unstable();
assert_eq!(vec, vec![1.0, 2.0, 5.6, 10.3, 15f32]);
}
```
结果,居然报错了,
```
error[E0277]: the trait bound `f32: Ord` is not satisfied
--> src/main.rs:29:13
|
29 | vec.sort_unstable();
| ^^^^^^^^^^^^^ the trait `Ord` is not implemented for `f32`
|
= help: the following other types implement trait `Ord` :
i128
i16
i32
i64
i8
isize
u128
u16
and 4 others
note: required by a bound in `core::slice::<impl [T]>::sort_unstable`
--> /home/keijack/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/mod.rs:2635:12
|
2635 | T: Ord,
| ^^^ required by this bound in `core::slice::<impl [T]>::sort_unstable`
For more information about this error, try `rustc --explain E0277` .
```
原来,在浮点数当中,存在一个 `NAN` 的值,这个值无法与其他的浮点数进行对比,因此,浮点数类型并没有实现全数值可比较 `Ord` 的特性,而是实现了部分可比较的特性 `PartialOrd` 。
如此,如果我们确定在我们的浮点数数组当中,不包含 `NAN` 值,那么我们可以使用 `partial_cmp` 来作为大小判断的依据。
```rust
fn main() {
let mut vec = vec![1.0, 5.6, 10.3, 2.0, 15f32];
vec.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
assert_eq!(vec, vec![1.0, 2.0, 5.6, 10.3, 15f32]);
}
```
OK, 现在可以正确执行了。
### 对结构体数组进行排序
有了上述浮点数排序的经验,我们推而广之,那么对结构是否也可以使用这种自定义对比函数的方式来进行呢?马上来试一下:
```rust
#[derive(Debug)]
struct Person {
name: String,
age: u32,
}
impl Person {
fn new(name: String, age: u32) -> Person {
Person { name, age }
}
}
fn main() {
let mut people = vec![
Person::new("Zoe".to_string(), 25),
Person::new("Al".to_string(), 60),
Person::new("John".to_string(), 1),
];
// 定义一个按照年龄倒序排序的对比函数
people.sort_unstable_by(|a, b| b.age.cmp(&a.age));
println!("{:?}", people);
}
```
执行后输出:
```
[Person { name: "Al", age: 60 }, Person { name: "Zoe", age: 25 }, Person { name: "John", age: 1 }]
```
结果正确。
从上面我们学习过程当中,排序需要我们实现 `Ord` 特性,那么如果我们把我们的结构体实现了该特性,是否就不需要我们自定义对比函数了呢?
是,但不完全是,实现 `Ord` 需要我们实现 `Ord` 、`Eq`、`PartialEq`、`PartialOrd` 这些属性。好消息是,你可以 `derive` 这些属性:
```rust
#[derive(Debug, Ord, Eq, PartialEq, PartialOrd)]
struct Person {
name: String,
age: u32,
}
impl Person {
fn new(name: String, age: u32) -> Person {
Person { name, age }
}
}
fn main() {
let mut people = vec![
Person::new("Zoe".to_string(), 25),
Person::new("Al".to_string(), 60),
Person::new("Al".to_string(), 30),
Person::new("John".to_string(), 1),
Person::new("John".to_string(), 25),
];
people.sort_unstable();
println!("{:?}", people);
}
```
执行输出
```
[Person { age: 1, name: "John" }, Person { age: 25, name: "John" }, Person { age: 25, name: "Zoe" }, Person { age: 30, name: "Al" }, Person { age: 60, name: "Al" }]
```
需要 `derive` `Ord` 相关特性,需要确保你的结构体中所有的属性均实现了 `Ord` 相关特性,否则会发生编译错误。`derive` 的默认实现会依据属性的顺序依次进行比较,如上述例子中,当 `Person` 的 `name` 值相同,则会使用 `age` 进行比较。
## 课后练习
> [Rust By Practice ](https://zh.practice.rs/collections/vector.html ),支持代码在线编辑和运行,并提供详细的[习题解答](https://github.com/sunface/rust-by-practice/blob/master/solutions/collections/Vector.md)。