一、伪代码(快速排序)
QUICKSORT(A, p, r)
1 if p < r
2 then q ← PARTITION(A, p, r)
3 QUICKSORT(A, p, q - 1)
4 QUICKSORT(A, q + 1, r)
PARTITION(A, p, r)1 x ← A[r]
2 i ← p – 1
3 for j ← p to r – 1
4 do if A[j] ≤ x
5 then i ← i + 1
6 exchange A[i] <-> A[j]
7 exchange A[i + 1] <-> A[r]
8 return i + 1
二、算法分析
快排代码(未改进):
quicksort在递归到只有几个元素大小的数组时开始用插入排序的方法。改进的快速排序方法在期望时间=原始快排的期望时间+插入排序方法的期望时间。
这里还是要用到7.4(算法导论第7章)的分析方法。对于快排还要计算期望比较次数。因为被划分在同一个小数组k中的元素,是不会在快排里比较的。所以Xij只要计算那些i和j相差k-1个以上的元素比较就可以了。
定义一个元素集合Zij={zi,zi+1,,,,,,,,zj},定义一个指示器随机变量Xij=I{zi与zj进行了比较},E[Xij]=Pr[Xij]=Pr{zi与zj进行了比较}=Pr{zi是Zij的主元}+Pr{zj是Zij的主元}=2/(j-i+1)//因为在快排中,二者能够比较,则其中一个必是主元.快速排序的期望比较次数E[Xij]为
那么快排的期望时间是O(nlg(n/k)),假设优化后的快排产生的小数组大小O(k),在每个大小O(k)的小数组里使用插入排序,时间复杂度为O(k^2),总共有O(n/k)个小数组,则插入排序时间为O(nk),。那么把这些时间加起来就是O(nk+nlog(n/k))。
但是k的值并不是越大越好,当k值超过临界值后,其性能会变差。
三、算法优化(改进后)
QUICKSORT(A, p, r)
1 if p < r
2 then q ← PARTITION(A, p, r)
3 QUICKSORT(A, p, q - 1)
4 QUICKSORT(A, q + 1, r)
PARTITION(A, p, r)1 x ← A[r]
2 i ← p – 1
3 for j ← p to r – 1
4 do if A[j] ≤ x
5 then i ← i + 1
6 exchange A[i] <-> A[j]
7 exchange A[i + 1] <-> A[r]
8 return i + 1
二、算法分析
快排代码(未改进):
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#include <iostream>
using namespace std;
int k = 70;
void swap(int* p, int* q)
{
int x;
x = *p;
*p = *q;
*q = x;
}
int partition(int *a, int p, int r)
{
int i = 0;
int j = 0;
int x = 0;
i = p - 1;
x = a[r];
for (j = p; j < r - 1; j++)
{
if (a[j] <= x)
{
i++;
swap(&a[i], &a[j]);
}
}
swap(&a[i + 1], &a[r]);
return i + 1;
}
void quicksort(int *a,int p,int r )
{
int q=0;
if (r>p)
{
q = partition(a, p, r);
quicksort(a, p, q - 1);
quicksort(a, q + 1, r);
}
}
int main(int argc,char* argv[])
{ struct timeval start,finish;
double Totaltime = 0.0;
int a[200000] = { 0 };
int i = 0;
srand((unsigned)time(NULL));
for (i = 0; i < 200000; i++)
{
a[i] = rand() % 1000000;
}
printf("随机生成的数组:\n");
printf("\n");
gettimeofday(&start,NULL);
quicksort(a,0,199999);
gettimeofday(&finish,NULL);
Totaltime = finish.tv_sec - start.tv_sec + (finish.tv_usec - start.tv_usec) / 1000000.0;
std::cout<<"程序运行时间为:"<<Totaltime<<std::endl;
printf("对数组进行插入排序:\n");
printf("\n");
system("pause");
return 0;
}
quicksort在递归到只有几个元素大小的数组时开始用插入排序的方法。改进的快速排序方法在期望时间=原始快排的期望时间+插入排序方法的期望时间。
这里还是要用到7.4(算法导论第7章)的分析方法。对于快排还要计算期望比较次数。因为被划分在同一个小数组k中的元素,是不会在快排里比较的。所以Xij只要计算那些i和j相差k-1个以上的元素比较就可以了。
定义一个元素集合Zij={zi,zi+1,,,,,,,,zj},定义一个指示器随机变量Xij=I{zi与zj进行了比较},E[Xij]=Pr[Xij]=Pr{zi与zj进行了比较}=Pr{zi是Zij的主元}+Pr{zj是Zij的主元}=2/(j-i+1)//因为在快排中,二者能够比较,则其中一个必是主元.快速排序的期望比较次数E[Xij]为
那么快排的期望时间是O(nlg(n/k)),假设优化后的快排产生的小数组大小O(k),在每个大小O(k)的小数组里使用插入排序,时间复杂度为O(k^2),总共有O(n/k)个小数组,则插入排序时间为O(nk),。那么把这些时间加起来就是O(nk+nlog(n/k))。
但是k的值并不是越大越好,当k值超过临界值后,其性能会变差。
三、算法优化(改进后)
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#include <iostream>
using namespace std;
int k = 70;
void swap(int* p, int* q)
{
int x;
x = *p;
*p = *q;
*q = x;
}
int partition(int *a, int p, int r)
{
int i = 0;
int j = 0;
int x = 0;
i = p - 1;
x = a[r];
for (j = p; j < r - 1; j++)
{
if (a[j] <= x)
{
i++;
swap(&a[i], &a[j]);
}
}
swap(&a[i + 1], &a[r]);
return i + 1;
}
void quicksort(int *a,int p,int r )
{
int q=0;
if (r-p>=k)
{
q = partition(a, p, r);
quicksort(a, p, q - 1);
quicksort(a, q + 1, r);
}
}
void insertSort(int *a, int p, int r)
{
int i, j;
int tmp = 0;
for (i = p + 1; i <= r; i++)
{
tmp = a[i];
j = i;
while (a[j - 1] > tmp)
{
a[j] = a[j - 1];
j--;
}
a[j] = tmp;
}
}
void promote_sort(int *a, int p, int r)
{
quicksort(a, p, r);
insertSort(a, p, r);
}
int main(int argc,char* argv[])
{
struct timeval start,finish;
double Totaltime = 0.0;
int a[200000] = { 0 };
int i = 0;
srand((unsigned)time(NULL));
for (i = 0; i < 200000; i++)
{
a[i] = rand() % 1000000;
}
printf("随机生成的数组:\n");
printf("\n");
gettimeofday(&start,NULL);
promote_sort(a,0,199999);
gettimeofday(&finish,NULL);
Totaltime = finish.tv_sec - start.tv_sec + (finish.tv_usec - start.tv_usec) / 1000000.0;
std::cout<<"改进后的插入快排运行时间为:"<<Totaltime<<std::endl;
printf("对数组进行插入快速排序:\n");
printf("\n");
system("pause");
return 0;
}