排序算法–快排的优化
下面是我写的一种快排:
#include <iostream>
#include <stdlib.h>
using namespace std;
void Print(int arr[],int len)
{
int i=0;
for(i;i<len;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
int Parition(int arr[],int first,int end)
{
int key=arr[first];
while(first<end)
{
while(first<end && arr[end]>=key)
{
end--;
}
if(first<end)
{
arr[first]=arr[end];
}
while(first<end && arr[first]<=key)
{
first++;
}
if(first<end)
{
arr[end]=arr[first];
}
}
arr[first]=key;
return first;
}
void Quick(int arr[],int first,int end)
{
int k;
if(first<end)
{
//最少有两个数据
//找寻基准点
k=Parition(arr,first,end);
Quick(arr,first,k-1);
Quick(arr,k+1,end);
}
}
void QuickSort(int arr[],int len)
{
if(arr==NULL || len<1)
{
return;
}
//快速排序就是找基准点的位置
//将基准点大的数字放在基准点右,反之为左边
Quick(arr,0,len-1);
}
int main()
{
int arr[]={12,45,11,12,20,1,5,4,30,2,9};
int len=sizeof(arr)/sizeof(int);
Print(arr,len);
QuickSort(arr,len);
Print(arr,len);
return 0;
}
我们从示例中发现,要是数组越趋于有序呢,那么我们递归的次数越来越多导致开销特别大,每次的遍历都循环遍历数组;
针对快排优化一:
- 之前我们采用的基准数是数组的第一位,所以如果数组是有序数组的话,我们可以随机选取基准点,合理的利用rand()函数,
- Swap(arr,first,rand()%(end-first+1)+first);//将随机值放入第一位
针对快排优化二:
我们还可以采取三数取中法;
int mid=(end-first)/2+first;
getMiddleMaxNum(arr,first,mid,end);
void getMiddleMaxNum(int arr[],int first,int mid,int end)
{
if(arr[mid]>arr[end])
{
Swap(arr,mid,end);//基准点为mid 和 end中较大的数为基准点
}
if(arr[first]<arr[end])
{
Swap(arr,first,end);
}
if(arr[first]>arr[mid])
{
Swap(arr,first,mid);
}
}
针对快排优化三:
快排呢,适用于数据量大的排序,和堆排序是适用的,那么在数据量小和数据量大的分界线处,小直接使用直接插入排序,他最快可以达到o(n);
if((end-first)<20)
{
//数据量 直接使用插入排序
Insert(arr,first,end);//插入排序最好的情况能达到O(n)的效率
return;
}
针对快排优化四;
我们可以使用非递归的方式来实现快排
void Sort(int arr[],int first,int end)
{
int* st=(int *)malloc(sizeof(int)*(end-first+1)*2);//开辟对应的空间
//int *st=(int *)malloc(sizeof(int)*end);
int top=0;
st[top++]=first;
st[top++]=end;
int k;
while(top!=0)
{
end=st[top-1];
top--;
first=st[top-1];
top--;
k=Parition(arr,first,end);
//从右区间开始
if(k+1<end)
{
//右区间至少有两个元素
st[top++]=k+1;
st[top++]=end;
}
if(first<k-1)
{
//左区间至少有两个元素
st[top++]=first;
st[top++]=k-1;
}
}
free(st);
}