再談快速排序
阿新 • • 發佈:2018-11-17
本篇部落格是在快速排序基礎上優化的。
演算法思想
快速排序是基於分治模式構思的,具體描述如下:
- 分解:陣列A[p..r]被劃分成兩個(可能空)子陣列A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每個元素都小於等於A(q),而且,小於等於A[q+1..r]中的元素。下標q也在這個劃分過程中進行計算。
- 解決:通過遞迴呼叫快速排序,對子陣列A[p..q-1]和A[q+1..r]排序。
- 合併:因為兩個子陣列是就地排序的,將它們合併不需要操作:整個陣列A[p..r]已排序。
// QUICKSORT
QUICKSORT(A, p, r)
if p < r
then q = PARTITION(A, p, r)
QUICKSORT(A, p, q-1)
QUICKSORT(A, q+1, r)
// PARTITION
PARTITION(A, p, r)
x = A[r]
i = p-1
for j = p to r-1
do if A[j] <= x
then i = i+1
exchange(A[i], A[j])
exchange(A[i+1], A[r])
return i+1
演算法解析
具體執行步驟如下:
- i=p-1, j=p, x=A[r]
- 因為A[i]<=x,i=p,A[i]和A[j]交換
- A[j]=7>x,j遞增
- 當A[j]=1時,因為A[i]<=x,i=p+1,A[i]和A[j]交換
- 當A[j]=3時,因為A[i]<=x,i=p+2,A[i]和A[j]交換
- A[j]=5>x,j遞增
- A[j]=6>x,j遞增
- j=r,A[r]和A[i+1]交換
源程式
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
void swap(int &x, int &y);
int partition(int *array, int left, int right);
void qsort(int *array, int left, int right);
void print(int *array, int left, int right);
void print(int *array, int n);
void input(int *&array, int n);
const int number = 8;
int main(int argc, char *argv[])
{
//int array[] = {13, 19, 9, 5, 12, 8, 7, 4, 21, 2, 6, 11};
int array[] = {2, 8, 7, 1, 3, 5, 6, 4};
//int *array = new int[number];
int n = number;
//input(array, number);
printf("befor qsort\n");
print(array, n);
printf("\n");
struct timeval stv;
gettimeofday(&stv, NULL);
int st_usec = stv.tv_sec * 1000000 + stv.tv_usec;
qsort(array, 0, n - 1);
struct timeval end_tv;
gettimeofday(&end_tv, NULL);
int end_usec = end_tv.tv_sec * 1000000 + end_tv.tv_usec;
int cost = end_usec - st_usec;
printf("qsort cost time : %dus\n", cost);
printf("after qsort\n");
print(array, n);
//delete []array;
exit(0);
}
void qsort(int *array, int left, int right)
{
if (left < right)
{
//print(array, 0, number - 1);
int pos = partition(array, left, right);
qsort(array, left, pos - 1);
qsort(array, pos + 1, right);
}
}
int partition(int *array, int left, int right)
{
printf("before partition\n");
print(array, 0, number - 1);
int i = left - 1;
int x = array[right];
for (int j = left; j < right; j++)
{
printf("in partition : ");
if (array[j] <= x)
{
++i;
swap(array[i], array[j]);
}
//print(array, 0, number - 1);
print(array, left, right);
//printf("in partition\n");
}
swap(array[i + 1], array[right]);
printf("after partition\n");
print(array, 0, number - 1);
printf("\n");
return i + 1;
}
void swap(int &x, int &y)
{
int temp = x;
x = y;
y = temp;
}
void print(int *array, int left, int right)
{
for (int i = left; i <= right; i++)
{
printf("%d ", array[i]);
}
printf("\n");
}
void print(int *array, int n)
{
print(array, 0, n - 1);
}
void input(int *&array, int n)
{
for (int i = 0; i < n; i++)
{
array[i] = rand() % n;
}
}
演算法執行過程
befor qsort
2 8 7 1 3 5 6 4
before partition
2 8 7 1 3 5 6 4
in partition : 2 8 7 1 3 5 6 4
in partition : 2 8 7 1 3 5 6 4
in partition : 2 8 7 1 3 5 6 4
in partition : 2 1 7 8 3 5 6 4
in partition : 2 1 3 8 7 5 6 4
in partition : 2 1 3 8 7 5 6 4
in partition : 2 1 3 8 7 5 6 4
after partition
2 1 3 4 7 5 6 8
before partition
2 1 3 4 7 5 6 8
in partition : 2 1 3
in partition : 2 1 3
after partition
2 1 3 4 7 5 6 8
before partition
2 1 3 4 7 5 6 8
in partition : 2 1
after partition
1 2 3 4 7 5 6 8
before partition
1 2 3 4 7 5 6 8
in partition : 7 5 6 8
in partition : 7 5 6 8
in partition : 7 5 6 8
after partition
1 2 3 4 7 5 6 8
before partition
1 2 3 4 7 5 6 8
in partition : 7 5 6
in partition : 5 7 6
after partition
1 2 3 4 5 6 7 8
qsort cost time : 3610us
after qsort
1 2 3 4 5 6 7 8
演算法複雜度分析
時間複雜度 | 空間複雜度 | 說明 |
---|---|---|
最優情況 | O(nlogn) | O(logn) |
平均情況 | O(nlogn) | O(logn) |
最壞情況 | O(n^2) | O(n) |
演算法耗時分析
數量級 | 耗時 | 說明 |
---|---|---|
1萬 | 1.7ms | |
1百萬 | 238ms | |
1千萬 | 2.5s | |
2千萬 | 5.4s | |
5千萬 | 14s | |
1億 | 無 | 記憶體空間有限 |
參考文獻
[1] Thomas H.Cormen, Charles E.Leiserson,etc. 演算法導論