在之前的帖子里我用c语言也实现过快速排序,所以就简单再介绍一下就直接上代码。
首先用语言来简单说明一下快速排序的实现过程:
- 选择一个基准数,通常选择要排序数列的首元素,放入一个独立的临时变量temp暂存基准数,防止基准数元素位置上的值在排序过程中被覆盖,然后生成两个指针,一个指针指向首元素位置我们称之为begin,然后在生成一个指针指向尾元素称为end。
- 然后用temp与end比较,如果end<temp,就将end的值放到begin当前所在的那个元素位置上,注意直接放上去就好,不需要交换两值,如果end>temp那就不做操作,end++开始向前移动指针,并且依次与temp比较,如果找到一个比temp小的值就将其值放到tbegin当前所在的元素位置上,如果找不到就一直自减到begin的位置为止。
- 将比temp小的值放好以后,此时我们不再从end开始比较,我们开始从begin开始,这时我们要做的是如果找到一个比temp大的值,就将这个值放到end当前所在的位置上去,注意此时的end不一定还指向尾元素,如果找不到就begin++开始向后移动,直到找到一个比temp大的值为止,如果一直找不到,那就到end指针的位置为止。
- 做完上面两个步骤,就将temp基准数的值再放到begin当前所在的位置上去,此时以temp基准数所在的位置为分界线,将这个数组一分为二,分成两个数组,再分别对这两个数组单独进行上面的步骤,然后每个数组再分别分成两个再执行…依次嵌套执行。
看完上面的步骤就会发现这完全可以用递归来实现,的确,快速排序用递归来实现更直观些,在上篇文章中我也是用递归来实现的,但要知道的是递归要进行不断的函数调用,不断的函数调用是很费时间的,所以这次我们用非递归的方式来实现。
首先是快速排序的核心算法部分,也就是单次对单独的一个数组的排序
#include<iostream>
#include<time.h>
using namespace std;
//快速排序
int quick_sort(int* list, int begin, int end)
{
//保存基准数
int temp=list[begin];
//如果begin小于end
while(begin<end)
{
//如果找不到比temp小的值,
//end指针就开始从后往前移动
while ((begin<end)&&(temp<=list[end]))
end--;
//找到后放到begin的位置上
list[begin]=list[end];
//然后开始从begin开始向后查找比temp大的数
while ((begin<end)&&(temp>list[begin]))
begin++;
//然后将比temp大的数放到end所在的位置上去
list[end]=list[begin];
}
//再将temp放到begin所在的位置上
list[begin]=temp;
//返回begin的位置,即分界线的位置
return begin;
}
现在,单次对单个的数组的比较就完成了,但我们要清楚的是,快速排序并不是比较一轮就能将顺序排出来的,在递归的写法中,我们在最后将两个数组的起始位置算出来后再分别调用一次单次排序的函数递归即可,但是非递归我们不能怎么写,那怎么办呢?没错,再写一个函数用循环!
void take_quick(int* list,int begin,int end)
{
//计时,与算法本身无关
clock_t start=clock();
//申请一块内存做栈来使用,用来临时存放
//单个数组的起始地址
int* stack=(int*)malloc(end*sizeof(int));
if(!stack)
return ;
//存储begin与end并且设置栈顶偏移0
int begin_temp=begin;
int end_temp=end-1;
int stack_top=0;
//先进行第一次排序
int p=quick_sort(list,begin_temp,end_temp);
//获取单个数组的起始地址
//并存入栈
if(p>(begin_temp+1))
{
//先入栈的后出栈
stack[stack_top++]=p-1;
//后入栈的先出栈
stack[stack_top++]=begin_temp;
}
if(p<(end_temp-1))
{
stack[stack_top++]=end_temp;
stack[stack_top++]=p+1;
}
//如果栈顶偏移为0,那说明两个if都未执行
//结束循环,排序结束
while (stack_top>0)
{
//从栈中获取起始地址
begin_temp=stack[--stack_top];
end_temp=stack[--stack_top];
//进行单次排序
p=quick_sort(list,begin_temp,end_temp);
//同上面两个if,不再解释
if(p>(begin_temp+1))
{
stack[stack_top++]=p-1;
stack[stack_top++]=begin_temp;
}
if(p<(end_temp-1))
{
stack[stack_top++]=end_temp;
stack[stack_top++]=p+1;
}
}
free(stack);
//计时,与算法本身无关
double now=double((clock()-start))/CLOCKS_PER_SEC;
cout<<"快速时间:"<<fixed<<now<<"s\n";
}
结果:
我这里本来是写了三种排序算法的代码用来比较时间,其余两种之后会提到,看这个结果图会发现,插入排序居然比快速排序要快?当然在对元素数少的数列进行排序的时候的确有时会出现这种情况,因为元素数两比较少,所以差距不大,但如果随机生成一个有10000个元素的数列进行排序的话,情况就会不一样了。