快速排序之C++实现
1.快速排序之C++实现
快速排序本质上是一个分治算法,其重点在于数组的拆分。当我们定义一个比较基准元素后,将数组中小于该基准元素的数放到其左边,将大于基准元素的放到其右边。这样我们就将数组拆分成了左右两部分:小于比较元素的数组;大于比较元素的数组。我们再对这两个数组进行同样的拆分,直到拆分到不能再拆分,数组就自然而然地以升序排列了。
抛开快速排序的数组划分,这个划分思想我们要注意在其他算法设计时可扩展性。
下面介绍两种划分数组的方式实现,分别命名为split和partition。
1.1 split划分
split算法使用一个单向的指针来对数组进行遍历,开始之时将数组首元素设置为基准元素,然后将第二个开始的元素依次与基准元素比较,如果大于基准元素则跳过,如果小于基准元素则将其与前面较大的元素进行交换,将数组中所有元素交换完毕后,再将基准元素放到中间位置。此时基准元素左边的值均小于基准元素,基准元素右边的值均大于基准元素。
是不是很像数组处理中的快慢指针法
下面是以数组{4,7,6,3,8,2,1,5}为初始数组划分一次的示意图,可以看到一轮划分后按照基准元素4将数组划分为两个部分。
1.2 partition划分
partition算法使用首尾两个反向的指针进行遍历,也是先将数组第一个元素设置为基准元素,左指针i
从左至右找到第一个大于基准元素的数,右指针j
从右至左找到第一个小于基准元素的数,全部交换完毕后将基准元素放到中间位置。注意在最后一次指针位置更新后,此时的i和j
指向了同一个元素,虽然此时出现了i=j
但是进入循环之前的i<j
是成立的,也就是说此时不用再进行两个元素的交换。所以我们选择在碰到这种边界条件时直接将跳出本层循环,将其与基准元素交换。
需要注意的是我们上面过程中的指针移动的先后次序是不能调换的,也就是必须先移动j指针
,然后再移动i指针
,否则就会导致不好定位与基准元素交换位置的元素。如在上面的例子中就会使得i
指针走过头,此时的i和j
会同时指向元素8.
2.具体代码
//快速排序实现
int split(int *a,int low,int high){
int i =low;
int x = a[i];
for(int j=i+1;j<=high;j++){
//如果当前元素小于基准元素
if(a[j] <= x){
//应该放在基准元素左边,根据慢指针进行填充
//并将可能不属于左边的元素换到后面去
i++;
if (i != j) {
swap(nums[i], nums[j]);
}
}
}
//交换基准元素与最后一个小于等于基准元素的值
swap(a[low],a[i]);
return i;
}
int partitiion(int *a,int low,int high){
int x=a[low];
int i =low,j=high;
while(i<j){
//从右到左找第一个小于等于基准的值
while(i<j && a[j]>=x){
j--;
}
//从左到右找第一个大于等于基准的值
while(i<j && a[i]<=x){
i++;
}
//如果不是指向同一个位置则说明还未处理完,交换元素
if(i!=j){
swap(a[i],a[j]);
}
}
//i==j 已经遍历完
swap(a[low],a[i]);
return i;
}
void quickSort(int *a,int low,int high){
if(low < high){
int par = partitiion(a,low,high);
cout<<"这次分隔的par是"<<par<<endl;
quickSort(a,0,par-1);
quickSort(a,par+1,high);
}
}
绝了,代码还是要手写一遍,不然有些很细节的错误还是不好把握