1. 快排的原理
时隔多日我们在被要求去写一个快速排序的时候可能无从下手,对于一个算法的考单纯的记忆不足以牢牢掌握它,深刻理解其机制才是学习算法的重要手段。
下面我们来解读一下快速排序。
快速排序由东尼·霍尔所发展。快速排序通常明显比其他 Ο(nlogn) 算法更快。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。递归和分治是快排的核心。
快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn)
记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn)
的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。
2. 用C实现快排
思路:
- 对于一个给定的数组,从中间位置选择一个元素,以该元素为界将其余元素划分为两个子集,一个子集中的元素都小于该元素,另一个子集中的元素都大于或等于该元素。
- 对这样的两个子集递归执行这一过程,当某一个子集中的元素的个数小于2时,这个子集就不需要再次排序,终止递归。
代码实现:
void swap(int v[],int i,int j)//用以交换
{
int temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
void quick_sort(int v[],int left,int right)
{
int i,last;
if(left >= right)
{
return ;
}
swap(v,left,(left+right)/2); //(left+right)/2 为基准点
last = left;
for(i = left + 1;i <= right;i++)
{
if(v[i] < v[left])
{
swap(v,++last,i);
}
}
quick_sort(v,left,last);
quick_sort(v,left,last-1);
quick_sort(v,last+1,right);
}
但是也可以不用递归
typedef struct _Range {
int start, end;
} Range;
Range new_Range(int s, int e) {
Range r;
r.start = s;
r.end = e;
return r;
}
void swap(int *x, int *y) {
int t = *x;
*x = *y;
*y = t;
}
void quick_sort(int arr[], const int len) {
if (len <= 0)
return; // 避免发生段错误
// r[]为模拟列表,p为数量,r[p++]为push,r[--p]为pop且取得元素
Range r[len];
int p = 0;
r[p++] = new_Range(0, len - 1);
while (p) {
Range range = r[--p];
if (range.start >= range.end)
continue;
int mid = arr[(range.start + range.end) / 2]; // 选取中间点
int left = range.start, right = range.end;
do {
while (arr[left] < mid) ++left; // 检测左侧是否符合要求
while (arr[right] > mid) --right; //检测右侧是否符合要求
if (left <= right) {
swap(&arr[left], &arr[right]);
left++;
right--; // 移动指针
}
} while (left <= right);
if (range.start < right) r[p++] = new_Range(range.start, right);
if (range.end > left) r[p++] = new_Range(left, range.end);
}
}
3. 用java实现快排
java实现,思路和c的基本一样
public class QuickSort implements IArraySort {
@Override
public int[] sort(int[] sourceArray) throws Exception {
// 对 arr 进行复制,不改变参数内容
int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
return quick_sort(arr, 0, arr.length - 1);
}
private int[] quick_sort(int[] arr, int left, int right) {
if (left < right) {
int partitionIndex = partition(arr, left, right);
quick_sort(arr, left, partitionIndex - 1);
quick_sort(arr, partitionIndex + 1, right);
}
return arr;
}
private int partition(int[] arr, int left, int right) {
// 设定基准值(pivot)
int pivot = left;
int index = pivot + 1;
for (int i = index; i <= right; i++) {
if (arr[i] < arr[pivot]) {
swap(arr, i, index);
index++;
}
}
swap(arr, pivot, index - 1);
return index - 1;
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}