这周听了老师讲的分治策略,不由想起了快速排序问题,回忆了一下,才发现对快排的许多细节已经忘掉了,因此我拿出以前的快排代码,重新学习一下,同时也分享一下我的收获,加深我的印象。
先贴代码:(我这个存储数据的数组是从a[1]开始的,a[0]中并无数据)
int FindPivot(int i, int j,int a[100000])
{
int key;
int k;
key=a[i];
for (k=i+1;k<=j;k++){
if(a[k]>key) return k;
else if (a[k]<key) return i;
}
return 0;
}
int Partition(int i, int j , int pivot,int a[100000]){
int l,r,temp;
l=i;
r=j;
do {
temp=a[l];
a[l]=a[r];
a[r]=temp;
while(a[l]<pivot)
l++;
while(a[r]>pivot||a[r]==pivot)
r--;
}while (l<r||l==r);
return l;
}
void QuickSort(int a[100000],int i ,int j)
{
int pivot;
int pivotindex;
int k;
pivotindex=FindPivot1(i,j,a);
if (pivotindex !=0)
{
pivot=a[pivotindex];
//printf("%d",pivotindex);
k=Partition1(i,j,pivot,a);
QuickSort1(a,i,k-1);
QuickSort1(a,k,j);
}
}
快排作为分治策略的一个典型体现,利用递归,将数组一分为二,并在一分为二的两个数组中继续进行快排。
而FindPivot、Partition函数对比最基础的快排进行了一些改进,这些改进是为了提高算法的效率,以及提高算法在特殊情况下的速度。
先说说FindPiovt函数:
这个函数的目的就是找出一个可以作为一分为二的参照的数的下标。对于这个参照数,如果只是随便的从数组中找一个固然也是可以的,但是这样会使快排在数组中有大量重复时,进行许多不必要的比较。在FindPiovt函数中,由于我的数据是从a[1]开始存储的,所以返回0时,代表该段中都是同一个数,不需要进行比较、调换顺序,也就可以避免上面所说的问题。
int FindPivot(int i, int j,int a[100000])
{
int key;
int k;
key=a[i];
for (k=i+1;k<=j;k++){
if(a[k]>key) return k;
else if (a[k]<key) return i;
}
return 0;
}
在来看看Partition函数:
这个函数的目的就是对数组中的数进行排序,在这个函数中,我同是从两端进行遍历,找到左端比参照数大的数后,查找右端比参照数小的数,然后交换,这样可以将查找的次数减少一部分,从而达到提高算法效率的目的。而返回的数,则是将这个数组一分为二的地方。
int Partition(int i, int j , int pivot,int a[100000]){
int l,r,temp;
l=i;
r=j;
do {
temp=a[l];
a[l]=a[r];
a[r]=temp;
while(a[l]<pivot)
l++;
while(a[r]>pivot||a[r]==pivot)
r--;
}while (l<r||l==r);
return l;
}
而最后这个 QuickSort就是一个递归函数,让分而治之这个理念在快排中从头体现到尾。
总的来讲这个虽然优化的不多,但是比最基础的随意选一个数作为参照数的从一端遍历的快排性能上要好上不少。而快排作为基础排序中的重点,是很值得我们去温习将它牢牢掌握的。