基本逻辑
以从小到大排序为例:找到一个基准值,然后把比基准值大的放左边,比基准值小的放右边,直至基准值左边全部比基准值小,右边全部比基准值大为止。然后以现基准值为分界线,左右两边分别重复此过程。
代码步骤
调用排序函数的函数中
1、定义数组头和数组尾
排序函数中
1、定义基准值和基准下标
2、定义从数组头移动的下标和数组尾部移动的下标
3、比较数组尾部和基准值,如果比基准值小,则双方互换,否则尾部指针 -1
4、比较数组头部和基准值,如果比基准值大,则双方互换,否则头部指针 +1
5、头尾相遇,循环终止
6、递归循环上述过程
步骤详解
以数组int array[] = {6, 1, 2, 17, 19, 13, 4, 5, 20, 18, 16, 11, 12, 7, 9, 3, 14, 15, 10, 8}为例子
定义数组头和数组尾
数组头就是第一个元素的下标:0,数组尾就是最后一个元素的下标:sizeof(array) / sizeof(int) - 1
定义基准值
基准值一般就以数组的第一个元素的值,即array[0]。基准下标就是0。后续递归的时候也是以排序的第一个值作为基准值其下标为基准下标
定义从数组头移动的下标和数组尾部移动的下标
数组头部移动的下标初始值就是数组头,数组尾部移动的下标初始值就是数组尾部
比较数组尾部和基准值,如果比基准值小,则双方互换,否则尾部指针 -1
比较数组头部和基准值,如果比基准值大,则双方互换,否则头部指针 +1
要先从尾部开始,因为我们的基准是头部。当发生了交换之后,就立马切换到从头部开始。当从头部开始之后,如果发生交换,就立即切换到尾部开始,循环往复
头尾相遇,循环终止
头尾相遇的适合,说明基于基准值,它的左边已经全部比它小,右边已经全部比它大了
递归循环上述过程
排序一轮之后,基准值的左边和右边仍是无序的,递归是比较好理解的做法。递归结束的条件是数组的头尾相遇,因为头尾相遇了,说明已经没有数据可以再排了,全部排序完成
代码
#include <stdio.h>
/* 交换函数 */
void swap(int *a, int *b)
{
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
/**
* 排序函数
* @param int *a 待排序的数组
* @param int left 数组头
* @param int right 数组尾
*/
void quicksort(int *a, int left, int right)
{
int low = left; /* 从头部移动的下标 */
int high = right; /* 从尾部移动的下标 */
int mid = left; /* 基准值下标 */
int base = a[mid]; /* 基准值 */
/* 递归结束的条件 */
if (left > right) {
return;
}
/* 大循环,每跑完一次循环即排序完成一次 */
while (low < high) {
/* 从尾部开始移动 */
while (low < high) {
if (a[high] < base) {
/* 尾部的值比基准值小,互换之后再从头部开始比较 */
swap(&a[high], &a[mid]);
mid = high; /* 因为数据互换,下标也要互换 */
break;
} else {
high--;
}
}
/* 从头部开始移动 */
while (low < high) {
if (a[low] > base) {
/* 头部的值比基准值大,互换之后再从尾部开始比较 */
swap(&a[low], &a[mid]);
mid = low;
break;
} else {
low++;
}
}
}
/* 递归 */
quicksort(a, left, mid - 1); /* 基准值左边递归 */
quicksort(a, mid + 1, right); /* 基准值右边递归 */
}
int main(int argc, char const *argv[])
{
int i;
int a[] = {6, 1, 2, 17, 19, 13, 4, 5, 20, 18, 16, 11, 12, 7, 9, 3, 14, 15, 10, 8};
int left = 0;
int right = sizeof(a) / sizeof(int) - 1;
quicksort(a, left, right);
for (i = 0; i < right + 1; i++) {
printf("%d ", a[i]);
}
printf("\n");
return 0;
}