快速排序(C语言)

Posted 曹李序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速排序(C语言)相关的知识,希望对你有一定的参考价值。

简介

快速排序与归并排序一样也是一种分治递归算法,其排序(升序)步骤可以简述如下:

1、在待排元素集合N中任选一元素做为枢纽元

2、开始分割元素,使左部元素均小于枢纽元,右部元素均大于枢纽元

3、对左右子序列递归应用步骤1、2


1、选取枢纽元

有一种极其常见的、错误的、非常糟糕的枢纽元的选取,是选取数组第一个或者最后一个元素为枢纽元,如果输入序列是随机的那么上述做法可以接受,但如果输入的序列与我们要排的序列正好相反,那么在分割元素阶段就会出现所有元素被划分到左半部或者右半部,更糟糕的是,在其后续递归过程中也是如此,那么其排序花费的时间将是二次的,因此该种枢纽元的选取应该摒弃。

void swap(int *p_num, int k, int j){ if (NULL == p_num) { return; } int tmp = p_num[k]; p_num[k] = p_num[j]; p_num[j] = tmp;} void quick_sort(int * p_num, int left, int right){ if ((NULL == p_num) || left >= right) { return; } int last = left; swap(p_num, left, (left + right) / 2); for (int i = left + 1; i <= right; i++) { if (p_num[i] < p_num[left]/* 直接将最左边的元素作为枢纽元 */) { swap(p_num, ++last, i); } } swap(p_num, left, last); quick_sort(p_num, left, last - 1); quick_sort(p_num, last + 1, right);}

那么我们该如何选取枢纽元呢?有两种常见的做法,一种是使用随机数生成器随机选取(但我们要注意到随机数的选取是昂贵的),另一种做法是选取3个数的中位数,这种选取方式总的来说是好的稳妥的,如下:

void Swap(int *A, int *B){ int Tmp = *A; *A = *B; *B = Tmp;}int median3(int nums[], int left, int right){ int center = (left + right) / 2; if (nums[left] > nums[center]) { Swap(&nums[left], &nums[center]); } if (nums[left] > nums[right]) { Swap(&nums[left], &nums[right]); } if (nums[center] > nums[right]) { Swap(&nums[center], &nums[right]); }
Swap(&nums[center], &nums[right]); // 隐藏枢纽元
return nums[right];}

2、分割策略

分割所做的事就是将小元素移动到数组左边,大元素移动到数组右边,一种安全稳妥的分割策略是,选取枢纽元之后将其与最后一个元素交换,然后对第0个元素和倒数第二个元素分割,因为没有必要对枢纽元进行分割,故将其移动到最后进行隐藏,具体分割步骤如下:

上述分割策略摘自数据结构与算法分析第二版page180

3、代码实现

#define Cutoff (3)void Swap(int *A, int *B){ int Tmp = *A; *A = *B; *B = Tmp;}
void select_sort(int *p_arr, const int size){ assert(p_arr != NULL); for (int i = 0; i < size; i++) { for (int j = i + 1; j < size; j++) { if (*(p_arr + i) > *(p_arr + j)) { Swap(p_arr + i, p_arr + j); } } }}
void qsort(int nums[], int left, int right){ int i = 0, j = 0, pivot = 0;
if (left + Cutoff <= right) { pivot = median3(nums, left, right); i = left; j = right; for (;;) { while (nums[++i] < pivot) { } while (nums[--j] > pivot) { } if (i < j) { Swap(&nums[i], &nums[j]); } else { break; } } Swap(&nums[i], &nums[right]);
qsort(nums, left, i - 1); qsort(nums, i + 1, right); } else { // 不满3个元素进行选择排序 select_sort(nums + left, right - left + 1); }}
void quicksort(int nums[], int size){ qsort(nums, 0, size - 1);}

参考文献

数据结构与算法分析第二版


以上是关于快速排序(C语言)的主要内容,如果未能解决你的问题,请参考以下文章

C语言,快速排序算法

C语言快速排序算法及代码

快速排序的c语言实现代码

快速排序 + 代码实现(C语言)

快速排序 + 代码实现(C语言)

快速排序算法学习(C语言和python代码对比)