快速排序是冒泡排序,选择排序,插入排序,奇偶排序,,归并排序,希尔排序中最快的排序,所以我们当然有必要去深入了解快速排序。
我们首先来了解一下划分算法,
何谓划分算法?
其实就是以一个数为基准(枢纽),这个比枢纽大的数,把我们它放在数组的右边,这个比枢纽小的我们放左边。
那我们如何来做呢?
假设现在我们有一个数组,上面杂乱无章的有十个数字,我们以50为枢纽,比50大的放在数组右边,比50小的放在数组左边。
起初:
1开始:
谨记规则:比枢纽小的放左边,比枢纽大的放右边
我们用LEFTARROW从数组左侧开始寻找,找到比枢纽数大的数字我们就停下,如果没找到,就一直往下遍历
相应的,我们用向右键从数组右侧开始寻找,找到比枢纽数小的我们就停下,如果没找到,就一直往下遍历
2-若停下:
交换数据
3-继续往下找:
4-若停下
交换数据
......(重复上述过程,直到左边的数都比枢纽的要小,右边的的数都比枢纽要大)
最后的结果如图:
在这里我们可以发现结束的条件应为LEFTARROW>向右键
那么LEFTARROW =向右键要不要结束条件,我们想一想它们什么时候会都指向同一个数字,是不是那个数字就是基准数的时候,两个箭头指向同一个数,说明左边的数全都已经比枢纽小,右边的全都比枢纽要大。
所以结束条件为:LEFTARROW> =向右键
知道上述过程,理解代码就容易多了:
int leftArrow = -1;
int rightArrow = 10; (也就是数组的容量)
而(theArray [++ LEFTARROW] <枢轴);
而(theArray [ - 向右键>枢轴]);
交换(theArray [LEFTARROW],theArray [向右键]);
注:交换为执行交换两个数的方法(函数),枢轴为枢纽的意思
我们执行完一遍以后要继续遍历,所以很可以自然的想到要循环上述过程,也就是重复上述过程
所以我们加个而循环:
而(真){
而(theArray [++ LEFTARROW] <枢轴);
而(theArray [ - 向右键>枢轴]);
交换(theArray [LEFTARROW],theArray [向右键]);
}
前面已经讲过,如果LEFTARROW> =向右键,我们的目的就达到了,左边放的都是比枢纽下的数,右边放的都是比枢纽大的数,停止循环。
而(真){
而(theArray [++ LEFTARROW] <枢轴);
而(theArray [ - 向右键>枢轴]);
如果(LEFTARROW> =向右键)
打破;
交换(theArray [LEFTARROW],theArray [向右键]);
}
考虑特殊情况;
上面都是杂乱无章的数,有比枢纽大的数,有比枢纽小的数,那么如果全都的英文比枢纽小的数,我们按照上面的代码运行的话会出现什么样的状况呢答案就是:造成数组越界相同的,如果,全都是比枢纽大的数,也会造成数组越界为了防止这种情况,我们需要在找比枢纽大或找比枢纽小的,而循环里面要增添条件:因为我们起初都是先自增以后再跟枢纽比较,举个例子,我们假设数组容量为10,当我们的LEFTARROW已经指向8时,我们判断其<9,所以我们自增LEFTARROW指向图9中,将theArrow [9]和枢纽枢轴进行比较,此时已经到达数组最后一个元素了,下次判断的时候,LEFTARROW <9,但此时LEFTARROW指向的是图9中,我们就不再继续遍历下去了,假设我们再继续遍历下去,LEFTARROW先自增以后,就是theArray [10]和枢纽枢轴比较,这样就会造成数组下标越界。
而(真){
while(leftArrow <9 && theArray [++ leftArrow] <pivot);
while(rightArrow> 0 theArray [ - rightArrow> pivot]);
如果(LEFTARROW> =向右键)
打破;
交换(theArray [LEFTARROW],theArray [向右键]);
}
经过上述操作,我们就完成我们想要达到的目的:比枢纽小的放在左边,比枢纽大的统一放在右边。
这就是快速排序最基本的思想,如果我们又把分好的两组又像上述过程那样,又设定一个枢纽值,又按照上述规则划分,大的放一边,小的放一边,完成有,我们又这样,又设定一个枢纽,然后划分,这样一直重复上述过程(很容易想到递归方法)是不是就可以完成排序了呢?没错,这就是快速排序。
那么我们如何实现快速排序呢?按照上面的思路,我们最重要的就是要知道枢纽,因为数组里面的数都是按枢纽来排序的,打的放右边,小的放左边,为了排序这一列的数组,我们当然不能像上面那样无中生有的直接创造一个枢纽,所以我们的枢纽设置为是数组里面的一个数,为了简单,暂且我们将枢纽:均设置为最右边的数。
排序都是一整列的,为了方便用户我们定义一个方法,方法里面再调用快速排序。
public void QuickSort(){
reQuickSort(0,nElems-1);
}
public void reQuickSort(int left,int right){
如果(左> =右)
返回;
int pivot = theArray [right];
int partition = partition(left,right,pivot);
reQuickSort(左,分区-1);
reQuickSort(分区+ 1,右边);
} // partiton是分区的意思,我们通过partition获取中止的地方小标,将数组“拆分”成两半,分别进行划分(大放一边小放一边)
public int partition(int left,int right,int pivot){
int leftArrow = left - 1;
int rightArrow = right;
而(真){
而(theArray [++ LEFTARROW] <枢轴); //不需要另加条件的原因是,我们是以最右边的数为枢纽的,不会出现数全小于枢纽的//的情况,遍历到最后一个总是是等于枢纽的,所以不用考虑数组越界的问题
while(rightArrow> 0 && theArray [ - right]> pivot); //按照上面想法,下标有可能越界
如果(LEFTARROW> =向右键)
打破;
交换(LEFTARROW,向右键);
}
交换(LEFTARROW,右);
return leftArrow;
}
转下篇:https://blog.csdn.net/szlg510027010/article/details/83108239