一、 快速排序基准位置的选取方法
1.固定位置法(就是选取的基准是固定的、一般是数组的第一个元素)
2.随机选取基准法
import java.util.Arrays;
import java.util.Random;
/**
* @ClassName TestDemo3
* @Description 快速排序,随机选取基准法
* @Author lzq
* @Date 2018/10/27 22:24
* @Version 1.0
**/
public class TestDemo3 {
public static void main(String[] args) {
int[] array = {20,1,9,56,25,32,87,45,12,69,54,19,98,51,25};
quickSort(array);
System.out.println(Arrays.toString(array));
}
/**
* 快速排序
* @param array
*/
public static void quickSort(int[] array) {
sort(array,0,array.length-1);
}
/**
* 递归的排序数据
* @param array
* @param start
* @param end
*/
private static void sort(int[] array,int start,int end) {
Random random = new Random();
int x = random.nextInt(end-start+1)+start;//产生在start到end之间的随机数
swap(array,start,x);
int once = once(array,start,end);
if(once > start) { //排序左边
sort(array,start,once-1);
}
if(once < end) { //排序右边
sort(array,once+1,end);
}
}
/**
* 一趟快速排序
* @param array
* @param start
* @param end
* @return
*/
private static int once(int[] array,int start,int end) {
int tmp = array[start];
while(start < end) {
while(start < end && array[end] >= tmp) {
--end;
}
array[start] = array[end]; //把比基准tmp大的数字移到后面
while(start < end && array[start] <= tmp) {
++start;
}
array[end] = array[start]; //把比基准tmp小的数字移到前面
}
array[start] = tmp; //把基准放在它该放的位置
return start; //返回基准的位置,后面分别在这个基准位置两边重复上面的操作
}
/**
* 将产生的随机下标与start下标交换,而这个新的array[start]会为成为后面比较
* 的基准,这样就达到了,随机选取基准的目的
* @param array
* @param start
* @param end
*/
public static void swap(int[] array,int start,int end) {
int tmp = array[start];
array[start] = array[end];
array[end] = tmp;
}
}
3、三分取基准
这个方法也就是把数组的第一个最后一个和最中间的元素拿出来比较一下,把三者中最大的放最后面,最小的放最前面,剩下那个元素放中间。然后在用递归的方式比较排序:
import java.util.Arrays;
/**
* @ClassName TestDemo4
* @Description 快速排序——三分取基法
* @Author lzq
* @Date 2018/10/27 22:33
* @Version 1.0
**/
public class TestDemo4 {
public static void main(String[] args) {
int[] array = {20,23,98,54,12,15,0,19,3,46,78,59,84};
System.out.println("原数组"+Arrays.toString(array));
quickSort(array);
System.out.println("排序后数组:"+Arrays.toString(array));
}
/**
* 快速排序
* @param array
*/
public static void quickSort(int[] array) {
new_Sort(array,0,array.length-1);
}
/**
* 三分取基
* @param array
* @param start
* @param end
*/
public static void new_Sort(int[] array,int start,int end) {
int mid = start+(end-start)>>>1;
if(array[start] > array[end]) {//目标 array[end] >= array[start]
swap(array,start,end);
}
if(array[start] > array[mid]) { // mid > start
swap(array,start,mid);
}
if(array[end] < array[mid]) { //end< mid
swap(array,end,mid);
}
System.out.println("经过new_Sort()后数组"+Arrays.toString(array));
sort(array,0,array.length-1);
}
/**
* 交换数组元素位置
* @param array
* @param start
* @param end
*/
public static void swap(int [] array ,int start,int end) {
int temp = array[start];
array[start] = array[end];
array[end] = temp;
}
/**
* 递归的排序数据
* @param array
* @param start
* @param end
*/
private static void sort(int[] array,int start,int end) {
int once = once(array,start,end);
if(once > start) { //排序左边
sort(array,start,once-1);
}
if(once < end) { //排序右边
sort(array,once+1,end);
}
}
/**
* 一趟快速排序
* @param array
* @param start
* @param end
* @return
*/
private static int once(int[] array,int start,int end) {
int tmp = array[start];
while(start < end) {
while(start < end && array[end] >= tmp) {
--end;
}
array[start] = array[end]; //把比基准tmp大的数字移到后面
while(start < end && array[start] <= tmp) {
++start;
}
array[end] = array[start]; //把比基准tmp小的数字移到前面
}
array[start] = tmp; //把基准放在它该放的位置
return start; //返回基准的位置,后面分别在这个基准位置两边重复上面的操作
}
}
运行结果:
原数组[20, 23, 98, 54, 12, 15, 0, 19, 3, 46, 78, 59, 84]
经过new_Sort()后数组[0, 23, 98, 54, 12, 15, 20, 19, 3, 46, 78, 59, 84]
排序后数组:[0, 3, 12, 15, 19, 20, 23, 46, 54, 59, 78, 84, 98]
二、优化:
1、当待排序数组当中数据比较少的时候,用直插
import java.util.Arrays;
/**
* @ClassName TestDemo1
* @Description 快速排序的优化
* @Author lzq
* @Date 2018/10/27 21:24
* @Version 1.0
**/
public class TestDemo1 {
public static void main(String[] args) {
int[] array = {20,1,9,56,25,32,87,45,12,69,54,19};
System.out.println(Arrays.toString(array));
quickSort(array);
System.out.println(Arrays.toString(array));
}
/**
* 快速排序
* @param array
*/
public static void quickSort(int[] array) {
sort(array,0,array.length-1);
}
/**
* 递归的排序数据
* @param array
* @param start
* @param end
*/
private static void sort(int[] array,int start,int end) {
if(array.length <= 100) {
insert_Sort(array); //数据不多,用直接插入排序
}else {
int once = once(array, start, end);
if (once > start) { //排序左边
sort(array, start, once - 1);
}
if (once < end) { //排序右边
sort(array, once + 1, end);
}
}
}
/**
* 直接插入排序
* @param array
*/
public static void insert_Sort(int[] array) {
int tmp = 0,j;
for(int i = 1;i < array.length;i++) {
tmp = array[i];
for(j = i-1;j >= 0;j--) {
if(array[j] > tmp) {
array[j+1] = array[j]; //比tmp大的向后移
}else {
//直到找到比tmp小的停止比较,因为每次比较前面的已经有序,只是在找tmp应该插入的位置
break;
}
}
array[j+1] = tmp; //把tmp放到当前已排序的数据中应该放入的位置
}
}
/**
* 一趟快速排序
* @param array
* @param start
* @param end
* @return
*/
private static int once(int[] array,int start,int end) {
int tmp = array[start];
while(start < end) {
while(start < end && array[end] >= tmp) {
--end;
}
array[start] = array[end]; //把比基准tmp大的数字移到后面
while(start < end && array[start] <= tmp) {
++start;
}
array[end] = array[start]; //把比基准tmp小的数字移到前面
}
array[start] = tmp; //把基准放在它该放的位置
return start; //返回基准的位置,后面分别在这个基准位置两边重复上面的操作
}
}
2、聚集相同元素法(基准一样的元素),减少递归的次数
当i和j遍历完后,也就把相同元素聚集完了,
这时,下一次基准的左右两边再次递归排序时,就不是这次基准位置的两边了,而是left的左边和right的右边。
import java.util.Arrays;
/**
* @ClassName TestDemo5
* @Description 聚集相同元素法
* @Author lzq
* @Date 2018/10/27 22:47
* @Version 1.0
**/
public class TestDemo5 {
public static void main(String[] args) {
int[] array = {20,20,20,56,25,32,87,45,12,69,54,20,98,51,25};
quickSort(array);
System.out.println(Arrays.toString(array));
}
/**
* 快速排序
* @param array
*/
public static void quickSort(int[] array) {
sort(array,0,array.length-1);
}
/**
* 一趟快速排序
* @param array
* @param start
* @param end
* @return
*/
private static int once(int[] array,int start,int end) {
int tmp = array[start];
while(start < end) {
while(start < end && array[end] >= tmp) {
--end;
}
array[start] = array[end]; //把比基准tmp大的数字移到后面
while(start < end && array[start] <= tmp) {
++start;
}
array[end] = array[start]; //把比基准tmp小的数字移到前面
}
array[start] = tmp; //把基准放在它该放的位置
return start; //返回基准的位置,后面分别在这个基准位置两边重复上面的操作
}
/**
* 递归的排序数据
* @param array
* @param start
* @param end
*/
private static void sort(int[] array,int start,int end) {
int once = once(array, start, end);
int left = once-1;
int right = once+1;
int[] brray = focus(array,start,end,once);
left = brray[0];
right = brray[1];
if(once > start+1) {
sort(array,start,left);
}
if(once < end-1) {
sort(array,right,end);
}
}
/**
* 聚集相同元素
* @param array
* @param start
* @param end
* @param par
* @return
*/
public static int[] focus(int[] array, int start, int end, int par) {
//查找的范围
int left = par-1;
int right = par+1;
//交换的指引变量
int parLeft = par-1;
int parRight = par+1;
//左边找
for (int i = left; i >=start; i--) {
if(array[i] == array[par]) {
if(i != parLeft) {
swap(array, parLeft, i);
parLeft--;
}
else {
parLeft--;
}
}
}
//右边找
for (int i = right; i <=end; i++) {
if(array[i] == array[par]) {
if(i != parRight) {
swap(array, parRight, i);
parRight++;
}
else{
parRight++;
}
}
}
return new int[] {parLeft,parRight};
}
/**
* 交换元素位置
* @param array
* @param start
* @param end
*/
public static void swap(int [] array ,int start,int end){
int temp = array[start];
array[start] = array[end];
array[end] = temp;
}
}
运行结果:
[12, 20, 20, 20, 20, 25, 25, 32, 45, 51, 54, 56, 69, 87, 98]