一.快排
时间复杂度:O(nlogn)
写法1
两个指针从前往后,末尾元素作为分界:
划分:
int Partition(int data[],int length,int start,int end)
{
if(data==nullptr||length<=0||start<0||end>=length)
{
throw new std::exception("Invlid Parameters");
}
int small=start-1;
int index=RanadomInRange(start,end);
swap(data[index],data[end]);
for(int index=start;index<end;++index)
{
if(data[index]<index[end])
{
++small;
swap(data[index],data[small]);
}
}
++small;
swap(data[small],data[end]);
return small;
}
可以这样理解代码:其中index的任务是找后面部分小于划分元素的元素位置,small保存的是前面部分大于划分元素的位置的前一位。
调用方进行快排:
void QuickSort(int data[],int length,int start,int end)
{
if(start==end) return;
int index=Partition(data,length,start,end);
if(index>start)
QuickSort(data,length,start,index-1);
if(index<end)
QuickSort(data,length,index+1,end);
}
写法二
两个指针从左右向中间靠拢,写法如下所示:
以下是剑指offer40最小的k个数的快排写法
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
if(arr.empty() || k==0) return {};
int len=arr.size();
vector<int> ans;
quickSort(arr,0,len-1,k);
for(int i=0;i<k;++i)
{
ans.push_back(arr[i]);
}
return ans;
}
void quickSort(vector<int>& arr,int left,int right,int &k)
{
if(left>=right) return;
int loc=partition(arr,left,right);
if(loc==k)
{
return;
}
else if(loc>k)
{
quickSort(arr,left,loc-1,k);
}
else
{
quickSort(arr,loc+1,right,k);
}
}
int partition(vector<int>& arr,int left,int right)
{
int pivot=arr[left];
int l=left,r=right+1;
while(l<r)
{
while(l<right && arr[++l]<pivot);
while(r>left && arr[--r]>pivot);
if(l<r)
{
swap(arr[l],arr[r]);
}
}
swap(arr[left],arr[r]);
return r;
}
};
从中我们可以提取出快排的写法:
void quickSort(vector<int>& arr,int left,int right)
{
if(left>=right) return;
int index=partition(arr,left,right);
if(index>left)
{
quickSort(arr,left,index-1);
}
if(index<right)
{
quickSort(arr,index+1,right);
}
}
int partition(vector<int>& arr,int left,int right)
{
int pivot=arr[left];
int l=left,r=right+1;
while(l<r)
{
while(l<right && arr[++l]<pivot);
while(r>left && arr[--r]>pivot);
if(l<r)
{
swap(arr[l],arr[r]);
}
}
swap(arr[left],arr[r]);
return r;
}
这里的一些细节,包括partition函数内的两个内循环为什么这么写,right和left为什么这么初始化,都是有原因的,具体可以去做一下题,看一下用例。
二.堆排
时间复杂度是O(nlogn)
这里以剑指offer40最小的k个数为例,说一下堆排的一个应用:
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> ans;
if(k==0) return ans;
int len=arr.size();
priority_queue<int> Q;
for(int i=0;i<k;++i)
{
Q.push(arr[i]);
}
for(int i=k;i<len;++i)
{
if(Q.top()>arr[i])
{
Q.pop();
Q.push(arr[i]);
}
}
for(int i=0;i<k;++i)
{
ans.push_back(Q.top());
Q.pop();
}
return ans;
}
};
未完待续~