c++ · 2024年9月6日 0

排序算法

今天是第一阶段最后一节课
今日内容:

一.排序算法
选择排序
对于n个无序的数列遍历n-1次, 每次选中剩余的数据的最小值, 放在对应的位置上

int data[5] = {9, 7, 3, 5, 1};

9 7 3 5 1 
_ _ _ _ _ 
0 1 2 3 4 

第一次遍历:从下标为1的数据, 找出数据最小的值的下标, 然后和下标为0的数据交换位置

1 7 3 5 9 
_ _ _ _ _ 
0 1 2 3 4  
最小的值为1, 下标是4  
int tmp = data[0];
data[0] = data[4];
data[4] = tmp;
找到所有数据的最小值, 和下标为0的值做替换 

第二次遍历 : 找出第二小的值, 和下标为1的位置做替换
1 3 7 5 9
_ _ _ _ _
0 1 2 3 4
最小的值为3, 下标为2
int tmp = data[1];
data[1] = data[2];
data[2] = tmp;

第三次遍历 : 找出剩余最小的值, 和下标为2的位置做替换
1 3 5 7 9
_ _ _ _ _
0 1 2 3 4
最下的值为5, 下标为3
int tmp = data[2];
data[2] = data[3];
data[3] = tmp;

第四次遍历 : 找出剩余最小的值, 和下标为3的位置做替换
1 3 5 7 9
_ _ _ _ _
0 1 2 3 4
最小的值为7, 下标为3 不再需要替换

1 5 3 2 7
1 5 3 2 7
1 2 3 5 7
1 2 3 5 7

快速排序 – 递归函数
例如:
0 10 80 30 60 50 40 70 20 90 100
思路 :
找出一个基准值, 其左边的数据小于他, 他右边的数据大于他

第一次实现 : 让数据50作为基准值, 进行依次分组,
把比50小的数据放在其左边, 把比50大的数据放在其右边

第二次实现:
对50左边的数据分组 对50右边的数据分组
对50左边的数据分组 -> 以30为基准
对50右边的数据分组 -> 以90为基准

第三次实现:
对30的左边分组 -> 10
对90的左边分组 -> 70

直到剩余最后一个或者没有 - 无需分组 

以50为基准 : 0 10 30 40 20 <50> 80 60 70 90 100
30,90为基准 : 0 10 20 <<30>> 40 <50> 80 60 70 <<90>> 100
10,70为基准 : 0 <10> 20 <<30>> 40 <50> 60 <70> 80 <<90>> 100

0, 10, 20 – 看起来不需要 – 实际上需要
xx, xx, xx – 三个数据, 比30小

通过三个游标来实现:
定义三个游标来实现原地分组
pivot = 基准值
int i = 0;//左边界
int j = size – 1;//右边界
int pivot = data[p];//将基准值备份到pivot变量中, 基准值的下标为p
pivot = 50;//存储了基准值

0 10 80 30 60 50 40 70 20 90 100
     i 
              p 
                              j  

for(; !(i>=p || pivot < data[i]); i++); i >= p -> 假
pivot < data[i] -> 假

当ip || data[i] > pivot
data[i] > pivot -> 该条件成立
data[p] = data[i];
p = i;
0 10 80 30 60 80 40 70 20 90 100
i
p
j

当j>p, data[j] > pivot, j–
何时不j–, j

该条件成立
data[p] = data[j];
p = j;
0 10 20 30 60 80 40 70 20 90 100
i
p
j

当ip || data[i] > pivot
data[p] = data[i];
p = i;
0 10 20 30 60 80 40 70 60 90 100
i
p
j
当j>p, data[j] > pivot, j–
何时不j–, j

该条件成立
data[p] = data[j];
p = j;
0 10 20 30 40 80 40 70 60 90 100
i
p
j

i变化 – j变化 – i变化 ….
0 10 20 30 40 80 80 70 60 90 100
i
p
j

停止, 直到i=p=j, 此时就是基准值应该在的位置
data[p] = pivot;
0 10 20 30 40 50 80 70 60 90 100
i
p
j

i变化, j变化, i变化, j变化, …

0 10 20 30 40 50 80 70 60 90 100
0 1  2  3  4  5  6  7  8  9  10 
l             p              r  
left                         right 
p - left > 1 -> 基准值p左边的数据大于1个 排序 
right - p > 1 -> 基准值p右边的数据大于1个 排序 

二.查找算法
线性查找
在数列中挨个匹配要查找的数据, 对于数据的有序性没有要求

mkdir find
vim find.h
vim find.c
vim sort.h
vim sort.c
vim main.c

折半查找 – 二分查找 – 递归函数
前提 – 数据必须有序, 无序则先排序
让数列对半分, 拿着目标值和中间值进行比较

相等 – 返回下标
目标值 > 中间值 -> 右侧继续二分查找
目标值 < 中间值 -> 左侧继续二分查找

10 20 30  40  50  60 70 
0  1  2   3   4   5  6
l     m-1 mid m+1    r 

10 20 30  40  50   
0  1  2   3   4   
l     m-1 mid m+1/r 

int recu_find(int data[], int left, int right, int key){

}

60 -> 中间值