快速选择算法
内容是根据leetcode第215题编写的,并且以下编程语言采用C语言
快速选择算法往往是为了在不将数字序列完整排序的前提下找到指定相对大小的数值(相对大小是指在相对于整个数字序列的大小,如“第3大的数字”,“第4小的数字”,“最大的数字”,“倒数第2个数字”等)
如果学习过快速排序算法,就可以很容易编写出来快速选择算法的内容(在下就是这样~)
快速排序算法
快速排序算法的一个核心是在当前限定的范围内(限定范围为下标left
到right
),选取一个轴值pivotVal
,并根据排序是升序还是降序,将比pivotVal
小的值和比pivotVal
大的值分别“扔到”pivotVal
两侧(升序排序则把比pivotVal
小的值扔在左侧,比pivotVal
大的值扔到左侧;降序排序反之),这样当前的轴值就会在排序完毕后的正确位置。
接着采用递归的方式,分别在轴值左右两段(left~pivot-1
和right~pivot+1
)的数值选取各自的轴值,重复把数值扔两侧的操作,一直递归到排序完毕为止(即left >= right
时,此时已经无法继续分段,之前的数字都已经在正确的位置上)
轴值的选取
轴值的临时存储位置要么选在数组当前分段的最左侧,要么选在最右侧。注意:这里说的是轴值的临时存储位置,这是因为:
- 轴值不一定就等于当前位置上的值。这是因为快速排序算法有两种形式,一种是将轴值的值固定为最左(右)侧位置上时直接采用当前位置上的值,一种是选取了位置但是值的选取是在当前分段中随机选取的(这是为了避免当序列为有序时,会发现划分出来的两个子序列一个里面没有元素,而另一个则只比原来少一个元素的情况)。这里我采用随机选取值的做法(快速排序的随机化版本),并且位置我选取了最左侧
- 说是临时存储位置是因为轴值的位置需要通过后续的条件判断将比轴值小的值和比轴值大的值各自分成两批之后,其中间值位置才能找到,这时才能确定轴值的位置
// 随机选取当前分段的轴值的值
// 随机选取当前分段一个下标值
srand((unsigned)time(NULL));
int random = left + rand() % (right - left + 1);
// 交换选取到的下标位置的值和最左侧的值的位置
// 这样就选取好了轴值的值并放置在最左侧
swap(&arr[left], &arr[random]);
开始排序
上述操作只是选取了值和临时存储位置,现在则是要找到轴值的正确位置
(采取的是升序排序)
int pivotVal = arr[left]; // 轴值的值,临时放在了最左侧
/* 轴值的当前位置,要在比轴值小的值和比轴值大的值
各自分成两批之后才能确定轴值的正确位置 */
int pivot = left;
int pre = pivot + 1; // 当前用于和轴值比较大小的值的下标
/* 当前下标值超出最右侧时则停止,
此时比轴值小的值和比轴值大的值已各自分成两批 */
while(pre <= right) {
// 因为是升序排序,当比轴值小时则应该靠左侧放置
if(arr[pre] < pivotVal) {
// 当前轴值下标位置改变
pivot ++;
// 交换当前值和新轴值下标位置的值的位置
swap(&arr[pre]