快速排序
package sort; import java.util.Scanner; public class 快排 { private static void sort(int x,int y,int[] a){ int i,j,k,t,l; i=x; j=y; k=a[(i+j)/2]; do{ while ( (i<j) && (a[i]<k)) { i++;} while ( (i<j) && (a[j]>k) ) { j—;} if (i<j) { t=a[i]; a[i]=a[j];a[j]=t; } }while (i<j); if i-1>x) { sort(x,i-1,a); } if (j+1<y) { sort(j+1,y,a); } } public static void main(String[] args) { Scanner read = new Scanner(System.in); //System.out.println("输入元素个数N:="); int n=read.nextInt(); int a[]; a=new int[n]; for (int i=0;i<n;i++) a[i]=read.nextInt(); sort(0,n-1,a); for (int i=0;i<n;i++) System.out.print(a[i]+" "); } }
快排原理是分治思想,其中随机化快排最快。这段代码是错误的,是我一开始的代码,我改了很久,发现其中有几点值得关注。
问题一:一个是a[I],a[j]与k的比较有没有等号的问题。
问题二:离开do while循环时,I=j对应的值是否为k的问题。
先说第一个,假设存在等号,那会出现什么情况,看这组数据--------
10
1 1 4 4 6 6 2 2 3 3
当第一次执行时,k=6,然而执行完,I=j=9;直接出现问题二,也就是说,如果有等号,那么离开的时候,I=j对应的值就不一定是k,也就是说,你接下来的分治有问题。(分治是基于k已经定位好,且以k为中心进行划分)
那么如何解决这个问题呢,大家踊跃留言吧...(我暂时没想到在保留等号下的快排算法)
我们继续看,当没等号的时候,又会出现什么情况。
先看这组数据:
7
1 4 3 4 1 4 8
这组数据会导致死循环,问题出在哪里呢?还是相等问题,当k值在数列中多次出现,就可能出现这种情况。
一开始我的解决方案是在a[I]a[j]交换后加I++,j—;
但事实是,可能出现第一次所提到的问题二。
总是有问题二出现,事实上,它也是这个算法成立的基础条件,既然你这么重要,那我给你加个标记,省的你乱跑找不到。于是我写了这个代码:
package sort; import java.util.Scanner; public class 快排 { private static void sort(int x,int y,int[] a){ int i,j,k,t,l; i=x; j=y; l=(i+j)/2; k=a[l]; do{ System.out.print(i+" "+j+" "+k+"------"); while ( (i<j) && (a[i]<k)) { i++;} while ( (i<j) && (a[j]>k) ) { j--;} System.out.println(i+" "+j+" "+k); if (i<j) { if (a[i]==k ) l=j; if (a[j]==k) l=i; t=a[i]; a[i]=a[j];a[j]=t; i++; j--; } }while (i<j); if (l-1>x) { sort(x,l-1,a); } if (l+1<y) { sort(l+1,y,a); } } public static void main(String[] args) { Scanner read = new Scanner(System.in); int n=read.nextInt(); int a[]; a=new int[n]; for (int i=0;i<n;i++) a[i]=read.nextInt(); sort(0,n-1,a); for (int i=0;i<n;i++) System.out.print(a[i]+" "); } }
这段代码基本解决了了刚才所提到的问题,暂时还没找到错误的数据,如果大家有更简洁的代码,记得分享一下。