快速排序两种方式实现及优化总结
2016-09-26 20:01
841 查看
今天看了快速排序,现在对自己的已知的方法进行总结,欢迎拍砖。
快速排序被认为是20世纪十大算法之一,在排序中,快速排序其实就是我们前面认为最慢的冒泡排序的升级,它们都属于交换排序类。即快排也是通过不断比较和移动交换来实现排序的,不过它的实现,增大了记录的比较和移动的距离,将关键字较大的记录从前面直接移动到后面,关键字较小的从后面直接移动到前面,从而减少了总的比较次数和移动交换次数。
在这里,我们假设对"6,1,2,7,9,3,4,5,10,8"这10个数进行排序。首先在这个序列中随便找一个数作为基准数,在这里为了方便,我们直接选取第一个数作为基准数,(在后面的优化中,会对基准数的选取做出优化),接下来需要将这个序列中所有比基准数大的数放在6的右边,基准数小的数放在6的左边,转变成这样:3
1 2 5 4 6 9
7 10 8;接下来再对6左边和6右边的元素进行相同操作的递归。
快排方法(一)和方法(二)在实现方式中有些差别,我们首先对于方法(一)的过程分析:
首先分别对原始序列的两端进行探测,先从右往左找一个比6小的数,再从左向右找一个比6大的数,(在后面会说明为什么先要从6 的右边向左开始找)然后进行交换,直至当左向标等于右向标,然后将其共同指向的数与这轮的基准值进行交换,交换完毕后,分别从left到i-1的序列和从i+1到right进行递归,直至完全排序。
NOTE:
在实现快排方法(一)之前,我们先对快排一中为什么必须首先从右边开始向左边找做一个说明^_^
如果我们在上述过程中,首先从左开始向右查找比6大的值,开始的左右互换不会出现问题,但是在最后与基准值交换就会出现问题!比如我们现在已经换到了这样的序列:6,1,2,7,9;此时若i从左向右进行查找, i到了7的位置会停下,j从右向左进行查找,j到了7的位置,和i相同,也会停下,这时6会与7进行交换,嘿嘿,这时7居然跑到了基准值6的右边!导致了结果错误,所以开始必须从右开始向左查找比基准值小的数。
快排(一)实现具体如下:
下面我们来总结一下快排方法(二)的过程:
快排方法二的总体其实和快排方法一是一样的,只是在循环条件和到每一轮最后中和基准值交换的时候有些不同。快排二是首先从左向右找出大值,接着再从右向左找出较小的值,(仔细想想与前面的顺序不同,接着是怎样来处理的)。因为快排方法一中的分析,我们可以了解到,如果是首先从左到右进行搜索时,会出现最后交换值的问题,为了避免交换值的问题,其中的一种思路是采用先从右向左搜索的方式,第二种思路则是依然是先从左到右搜索,但是在每一轮中跳出循环后,不是将左边left下标指向的值与基准值进行交换,而是将右边right下标指向的值与基准值进行交换,这样就可以避免最后在交换时出现最后将基准值换错的问题。
快排(二)实现具体如下:
快排的优化
今天天色已晚,关于快排的优化,明天再做下总结
快速排序被认为是20世纪十大算法之一,在排序中,快速排序其实就是我们前面认为最慢的冒泡排序的升级,它们都属于交换排序类。即快排也是通过不断比较和移动交换来实现排序的,不过它的实现,增大了记录的比较和移动的距离,将关键字较大的记录从前面直接移动到后面,关键字较小的从后面直接移动到前面,从而减少了总的比较次数和移动交换次数。
在这里,我们假设对"6,1,2,7,9,3,4,5,10,8"这10个数进行排序。首先在这个序列中随便找一个数作为基准数,在这里为了方便,我们直接选取第一个数作为基准数,(在后面的优化中,会对基准数的选取做出优化),接下来需要将这个序列中所有比基准数大的数放在6的右边,基准数小的数放在6的左边,转变成这样:3
1 2 5 4 6 9
7 10 8;接下来再对6左边和6右边的元素进行相同操作的递归。
快排方法(一)和方法(二)在实现方式中有些差别,我们首先对于方法(一)的过程分析:
首先分别对原始序列的两端进行探测,先从右往左找一个比6小的数,再从左向右找一个比6大的数,(在后面会说明为什么先要从6 的右边向左开始找)然后进行交换,直至当左向标等于右向标,然后将其共同指向的数与这轮的基准值进行交换,交换完毕后,分别从left到i-1的序列和从i+1到right进行递归,直至完全排序。
NOTE:
在实现快排方法(一)之前,我们先对快排一中为什么必须首先从右边开始向左边找做一个说明^_^
如果我们在上述过程中,首先从左开始向右查找比6大的值,开始的左右互换不会出现问题,但是在最后与基准值交换就会出现问题!比如我们现在已经换到了这样的序列:6,1,2,7,9;此时若i从左向右进行查找, i到了7的位置会停下,j从右向左进行查找,j到了7的位置,和i相同,也会停下,这时6会与7进行交换,嘿嘿,这时7居然跑到了基准值6的右边!导致了结果错误,所以开始必须从右开始向左查找比基准值小的数。
快排(一)实现具体如下:
#include <stdio.h> int a[101],n;//定义全局变量,这两个变量需要在子函数中使用 void quicksort(int left,int right) { int i,j,t,temp; if(left>right) return; temp=a[left]; //temp中存的就是基准数 i=left; j=right; while(i!=j) { //顺序很重要,要先从右边开始找 while(a[j]>=temp && i<j) j--; //再找右边的 while(a[i]<=temp && i<j) i++; //交换两个数在数组中的位置 if(i<j) { t=a[i]; a[i]=a[j]; a[j]=t; } } //最终将基准数归位 a[left]=a[i]; a[i]=temp; quicksort(left,i-1);//继续处理左边的,这里是一个递归的过程 quicksort(i+1,right);//继续处理右边的 ,这里是一个递归的过程 } int main() { int i,j,t; //读入数据 scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); quicksort(1,n); //快速排序调用 //输出排序后的结果 for(i=1;i<=n;i++) printf("%d ",a[i]); getchar();getchar(); return 0; }
下面我们来总结一下快排方法(二)的过程:
快排方法二的总体其实和快排方法一是一样的,只是在循环条件和到每一轮最后中和基准值交换的时候有些不同。快排二是首先从左向右找出大值,接着再从右向左找出较小的值,(仔细想想与前面的顺序不同,接着是怎样来处理的)。因为快排方法一中的分析,我们可以了解到,如果是首先从左到右进行搜索时,会出现最后交换值的问题,为了避免交换值的问题,其中的一种思路是采用先从右向左搜索的方式,第二种思路则是依然是先从左到右搜索,但是在每一轮中跳出循环后,不是将左边left下标指向的值与基准值进行交换,而是将右边right下标指向的值与基准值进行交换,这样就可以避免最后在交换时出现最后将基准值换错的问题。
快排(二)实现具体如下:
#include <stdio.h> int a[101],n;//定义全局变量,这两个变量需要在子函数中使用 int Patition(int a[],int p,int r) { int i=p,j=r+1; int tt; int x = a[p]; while(true){ while(a[++i]<x&&i<r); while(a[--j]>x); if(i>=j) break; tt=a[i]; a[i]=a[j]; a[j]=tt; } a[p] = a[j]; a[j] = x; return j; } void QuickSort(int a[],int p,int r) { if(p<r){ int q = Patition(a,p,r); QuickSort(a,p,q-1); QuickSort(a,q+1,r); } } int main(){ int i,j,t; //读入数据 scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i]); QuickSort(a,1,n); //快速排序调用 //输出排序后的结果 for(i=1;i<=n;i++) printf("%d ",a[i]); getchar();getchar(); return 0; }
快排的优化
今天天色已晚,关于快排的优化,明天再做下总结
相关文章推荐
- 算法整理(二)---快速排序的两种实现方式:双边扫描和单边扫描
- 快速排序两种实现方式
- 快速排序的三种实现及两种优化
- 快速排序的两种实现方式,主要是Partition函数的实现原理不一样
- 快速排序的两种实现方式(Java)
- 算法整理(二)---高速排序的两种实现方式:双边扫描和单边扫描
- MySQL 中的ORDER BY两种排序实现方式
- 冒泡排序、选择排序、堆排序、快速排序、插入排序算法复杂度分析与算法实现(自己总结与转)
- 自定义类型数组排序的两种实现方式
- 详谈排序算法之交换类排序(两种方法实现快速排序【思路一致】)
- 两种简单的方式快速实现hashCode 和 equals方法
- TreeSet集合排序两种实现方式Comparable和Comparator比较
- 快速排序的三种不同的实现方式。
- 冒泡排序、选择排序、堆排序、快速排序、插入排序算法复杂度分析与算法实现(自己总结与转)
- 快速排序的两种实现
- (总结)Nginx使用的php-fpm的两种进程管理方式及优化
- 用冒泡的方式对数组进行排序, 并写出对应的优化后的代码实现。(重点写思路、原理)
- 快速排序,两种实现
- 选择,插入,希尔,快速,堆,归并排序六种排序方式的Java 实现和性能对比(付代码)
- 黑马程序员 TreeSet排序的两种实现方式