快速排序
void quick_sort(int q[],int l,int r)
{
if(l>=r) return;//递归终止
int st=l-1,ed=r+1;
int x=a[l+r+1>>1];
while(st<ed)
{
do st++;while(a[st]<x);
do ed--;while(a[ed]>x);
if(st<ed)swap(a[st],a[ed]);
}
quick_sort(q,l,st-1);
quick_sort(q,st,r);
}
算法思想:
本质是分治,先找一个值x让数组左边的一部分小于x,右边的一部分大于x,如此递归下去即可
详述:
中间值的选取:不能选取左右端点,因为如果所给的数组本身就是排好序的那么就会调用n次函数,时间复杂度会降低到O(n^2),只能选取l+r>>1或者l+r+1>>1;
为什么采用do while:因为使用while循环即:
while(q[i]<x)i++;
while(q[j]>x)j--;
当q[i]和q[j]都为x时,i和j不会更新,导致外层的while循环陷入死循环;
为什么do while中的循环条件中没有等于:如果数组中有很多和x相等的数,那么在循环中就会跳过这个数,而忽略了另一边可能有需求的数。此处可以让相等的数停止循环于另一端需要交换的进行交换。总之就是让循环在恰当的位置停止。
算法中的循环(结束后)会让st左边的值(不包括st自己)都是小于等于x,会让ed右边的值(不包括ed自己)都是大于等于x;所以如果x取的是l+r+1,那么递归就需要使用st-1和st;如果x取的是l+r,那么递归就需要使用ed和ed+1
归并排序
void merge_sort(int q[],int l,int r)
{
if(l>=r)return;
int mid=l+r>>1;
merge_sort(q,l,mid);
merge_sort(q,mid+1,r);
int k=l;
int i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(q[i]>q[j])tmp[k++]=q[j++];
else tmp[k++]=q[i++];
}
while(i<=mid)tmp[k++]=q[i++];
while(j<=r)tmp[k++]=q[j++];
for(int p=l;p<=r;p++)
q[p]=tmp[p];
}
同样是分治,比较容易理解,就不需要多讲了。
分治思想
第一步:分成子问题
第二步:递归处理子问题
第三步:合并子问题
经典题目: