数组排序——快速排序
一、一般的快速排序:
思路:
1、选择一个基准值,
2、比较数组中的元素,比基准值小的放入基准值的左边,比基准值大的放入基准 值的右边
3、递归的进行第二步,分别对左边和右边进行排序
代码 :
public static int[] quickSort(int[] a, int l,int r){
if(l >= r){
return a;
}
int i = l;
int j = r;
//选取基准值
int k = a[l];
while(i < j){
//从右边开始找到第一个小于k的元素,并把它放到左边去
while(i < j && a[j] >= k){
j--;
}
if(i < j){
a[i] = a[j];
i++;
}
//从左边开始找到第一个大于k的元素,并把它放到右边去
while(i < j && a[i] < k){
i++;
}
if(i < j){
a[j] = a[i]
j--;
}
}
//经过上面的处理;随着i的位置的变化,k的位置应该变化到i处
a[i] = k;
//对左子数组,排序
quickSort(a, l, i-1);
//对右子数组,排序
quickSort(a, i+1, r);
return a;
}
上面这一种排序方法,当数组中的重复元素较多的时候,虽然效率尚可,但是还是有优化空间的
优化的时候,基于一个事实,重复的元素是不需要进行排序的,上面的这种方式,会让重复的元素进入左右子数组中进行排序
寻找一种方法,不要让k的重复元素进入左右子数组
二、利用三向切分法
思路:
1、维护三个指针:lt i gt , 选中基准值 k
2、l:是数组的左边界,r:是数组的右边界,
让 l ~ lt-1区间的元素都小于k ; lt ~ i-1 区间全是等于k的元素;i ~ gt :是不确定的元素,需要处理的元素;gt +1 ~ r 全是大于的k的元素,
3、处理过程:
- a[i] > k ,那就交换a[gt] 和a[i]的位置 gt--
- a[i] < k ,那就交换a[lt] 和a[i]的位置 lt ++
- a[i]=k ,说明需要缩小i ~ gt的空间, i++ :慢慢的变成=k的空间,即lt+1 ~ gt-1
切分过程,如图:
代码:
public static int[] quickSortThreeWay(int[] a,int l ,int r){
if(l >= r){
return a;
}
int lt = l;
int i = l + 1;
int gt = r;
int k = a[l];
while(i <= gt){
if(a[i] > k){
int tm = a[gt];
a[gt] = a[i];
a[i] = tm;
gt--;
}else if(a[i] < k){
int tm = a[lt];
a[lt] = a[i];
a[i] = tm;
lt++;
}else{
i++
}
}
quickSortThreeWay(a,l lt - 1);
quickSortThreeWay(a,gt + 1,r);
return a;
}