目录
三数取中值分割法获得枢纽元
快速排序的主例程
直接插入排序代码
快速排序完整代码
快速排序
快速排序是实践中的一种快速的排序算法,它的平均运行时间是O(N log N),该算法之所以特别快,是因为它有非常精炼和高度优化的内部循环。
可以将快速排序和直接插入排序结合起来得到优化后的快速排序,当数据量较小时,如果继续利用快速排序对其进行排序操作,其效率比较低下,因为快速排序是递归的,因此当遇到很小的数组(N<=20)时,采用直接排序对其进行排序.
三数取中值分割法获得枢纽元
在选择快速排序的枢纽元时,采取三数中值分割法(即在数组第一个元素,数组最后一个元素和数组中间元素三个元素中选择值处在中间的那个数)
以上述数据为例 ,设该数组为arr,分别将找到其left,mid,right
之后对这三个数据进行比较,将其进行交换,比较方式如下:
1、比较left下标的值和mid下标的值,如果arr[left] > arr[mid],将left下标的值和mid下标的值交换;
2、比较left下标和right下标的值,如果arr[left] > arr[right],将left下标的值与right下标的值进行交换;
3、比较right下标的值和mid下标的值,如果arr[right] < arr[mid],将right下标的值和mid下标的值交换;
4、在完成上述比较后,再将right-1下标的值和mid下标的值进行交换;
5、返回arr[right-1].
进行完上述步骤后,arr变为
具体代码实现
public static int median3(int[] arr, int left, int right) {
int mid = (left + right) / 2;
if(arr[left] > arr[mid]) {
swap(arr,left,mid);
}
if(arr[left] > arr[right]) {
swap(arr,left,right);
}
if(arr[mid] > arr[right]) {
swap(arr,mid,right);
}
//找到中间元素后将其放在arr.length-1的位置.
swap(arr,mid,right-1);
return arr[right-1];
}
快速排序的主例程
1、首先判断目前分治后需要排序的数据数量,设定CUTOFF = 10,若数据量小于等于CUTOFF,直接进行插入排序,反之进行快速排序;
2、令i = left,j = right - 1,利用i++寻找到左边第一个大于pivot的值,利用j--在右边寻找到第一个小于pivot的值,并对其进行交换;
3、 交换之后依次递归以枢纽元分割好的两个部分,分别对其进行快速排序.
当i和j指向这两个位置时,对其进行交换
交换完成后继续进行寻找,直至i > j为止,对于arr数组来说,下图所示状态为其截止状态
之后再将arr[i] 和arr[pivot]进行交换,得到如下结果
之后以i下标作为分割线,分别对i左边和右边的数据进行快速排序.
具体代码实现
public static final int CUTOFF = 10;
public static void quickSort(int[] arr, int left, int right) {
if(left + CUTOFF <= right) {
int pivot = median3(arr,left,right);
int i = left;
int j = right-1;
for(; ;) {
while(arr[++i] < pivot) {}
while(arr[--j] > pivot) {}
if(i < j) {
swap(arr,i,j);
}else {
break;
}
}
swap(arr,i,right-1);
quickSort(arr,left,i-1);
quickSort(arr,i+1,right);
}else {
insertSort1(arr,left,right);
}
}
直接插入排序代码
public static void insertSort1(int[] arr,int left,int right) {
for (int i = left+1; i <= right; i++) {
int tmp = arr[i];
int j = i-1;
for(; j >= left; j--) {
if(arr[j] > tmp) {
arr[j+1] = arr[j];
}else {
break;
}
}
arr[j+1] = tmp;
}
}
快速排序完整代码
快速排序完整代码+测试用例
/**
* 快速排序
* @param arr
*/
public static final int CUTOFF = 10;
public static void quickSort(int[] arr, int left, int right) {
if(left + CUTOFF <= right) {
int pivot = median3(arr,left,right);
int i = left;
int j = right-1;
for(; ;) {
while(arr[++i] < pivot) {}
while(arr[--j] > pivot) {}
if(i < j) {
swap(arr,i,j);
}else {
break;
}
}
swap(arr,i,right-1);
quickSort(arr,left,i-1);
quickSort(arr,i+1,right);
}else {
insertSort1(arr,left,right);
}
}
//三数取中分割法
public static int median3(int[] arr, int left, int right) {
int mid = (left + right) / 2;
if(arr[left] > arr[mid]) {
swap(arr,left,mid);
}
if(arr[left] > arr[right]) {
swap(arr,left,right);
}
if(arr[mid] > arr[right]) {
swap(arr,mid,right);
}
//找到中间元素后将其放在arr.length-1的位置.
swap(arr,mid,right-1);
return arr[right-1];
}
//直接插入排序
public static void insertSort1(int[] arr,int left,int right) {
for (int i = left+1; i <= right; i++) {
int tmp = arr[i];
int j = i-1;
for(; j >= left; j--) {
if(arr[j] > tmp) {
arr[j+1] = arr[j];
}else {
break;
}
}
arr[j+1] = tmp;
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] arr = {5,8,16,4,32,64,25,31,1,26,27,11};
quickSort(arr,0,arr.length-1);
System.out.println("快速排序后的数组为:");
System.out.println(Arrays.toString(arr));
}