增量编译:
设置环境变量:RUSTC_FORCE_INCREMENTAL=1
冒泡排序
冒泡排序每次比较没有排完序的数字,如果前面的数字大于后面数字,那么交换它们的位置。第i次遍历后,第i大的元素必然被交换到了正确的位置上,因此总共需要n-1次遍历,算法时间复杂度为 O ( n 2 ) O(n^2) O(n2)
步骤
- 比较两个相邻元素,若首个元素比次个元素大,置换两者的位置。
- 依序对相邻元素执行步骤一,直到抵达序列顶端,此时顶端元素排序完成。
- 重复步骤1 - 2 的整个序列叠代,直到任何一次叠代没有执行元素置换。
fn main() {
let mut v:Vec<usize> = vec![1, 7, 3, 8, 9, 10, 108, 2, 5];
bubble_sort(&mut v);
println!("{:?}",v);
}
fn bubble_sort(v: &mut Vec<usize>) {
let n=v.len();
for i in 0..(n-1) {
for j in 1..(n-i) {
if v[j-1] > v[j] {
v.swap(j-1, j);
}
}
}
}
插入排序
插入排序将数组视为两部分,已经排好序的前部和未排好序的后部,每次取出后部第一个数字,找到在前部合适的插入位置,然后将插入位置后的数字全部后移,最后在前部合适的位置插入。算法需要将n-1个元素插入到以及排好序的前部(从只有一个元素开始),最坏情况下需要移动前部全部的数字,因此最坏时间复杂度依然是 O ( n 2 ) O(n^2) O(n2)
步骤
将序列分为未排序与部分排序两个区域。
- 取第一个元素,将该元素视为已排序。
- 取出下一元素,该元素将插入序列的部分排序区域。
- 寻找正确位置:若部分排序元素比新元素大,则互换位置。并重复步骤2 - 3,直到部分排序元素小于等于新元素。
- 插入元素:将新元素插入最后的位置。
- 重复步骤2 - 4,直到排序完成。
简而言之,即是每次取一个元素,寻找并插入该元素在部分排序区域的排序位置,再逐步把序列单边排序完成。
fn main() {
let mut v:Vec<usize> = vec![1, 7, 3, 8, 9, 10, 108, 2, 5];
insert_sort(&mut v);
println!("{:?}",v);
}
fn insert_sort(v: &mut Vec<usize>) {
for i in 1..v.len() {
let (mut p, value) = (i, v[i]);
while value<v[p-1] && p > 0 {
v[p] = v[p-1];//把p-1的位置的值往后移
p -= 1;
}
v[p] = value;//最后在前部合适的位置插入
}
}
选择排序
选择排序同样将数组视为两部分,排好序的前部和未排序的后部,和插入排序不一样的地方在于,每次将后部的最小元素加入到前部的末尾。时间复杂度 O ( n 2 ) O(n^2) O(n2)
- 最简单的排序法之一。
- 对小资料序列排序效率较高。
- 不稳定排序:排序后,相同键值的元素相对位置可能改变。
- 原地排序:不需额外花费储存空间来排序。
fn main() {
let mut arr= [1, 7, 3, 8, 9, 10, 108, 2, 5];
selection_sort(&mut arr);
println!("{:?}",arr);
}
pub fn selection_sort(arr: &mut [i32]) {
let len = arr.len();
for i in 0..len {
let mut temp = i;
for j in (i + 1)..len {
if arr[temp] > arr[j] {
temp = j;
}
}
arr.swap(i, temp);
}
}
快速排序
快速排序每次选个一个数字,然后将数组分割成两部分,一部分都是小于该数字的数字,另一部分都是大于该数字的数字。然后,再次在划分好的数组片段上继续做划分。在最好情况下,每次数组被均匀地分割成大小相同的两个片段,此时的算法复杂度为
归并排序
归并排序通过不断归并排好序的数组片断得到完整的排序数组。只有一个数字的数组显然算是排好序的,归并排序自底向上将数组片断两两归并得到最终的排序数组。这是一个二分然后递归的过程,因此算法复杂度为
希尔排序
希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进。希尔排序又叫缩小增量排序
基本思想:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。