快速排序(不稳定)
算法思想
任取待排序元素序列中的某个元素作为基准值,按照该排序码将待排序序列分割为两个子序列,其左子序列中所有元素均小于基准值,其右子序列中所有元素均大于基准值,然后将其左右子序列按照上述过程重复操作,直到所有元素均排列在相应位置上为止。
时间复杂度
- 最好情况:O(n log n)
- 最坏情况:O(n^2)
- 平均复杂度:O(n log n)
实现思路
若规定基准值key始终为待排序序列的最后一个元素,定义两个索引left和right,left将在待排序序列中从前往后找到第一个大于key的元素,right将在待排序序列中从后往前找到第一个小于key的元素,均找到之后进行交换,如此重复操作直到left与right重合时与基准值key交换即可。
以arr[7] = {10,5,1,7,8,3,6},size = 7
- 待排序区间为[0,size),待排序数组为arr[7] = {10,5,1,7,8,3,6},基准值key = 6,left指向待排序区间的开始,即arr[0];right指向待排序区间的末尾,即下标为size - 1 = 6的元素。开始移动left和right,条件为left<right:
1.arr[left] = arr[0] = 10 > key = 6,找到了一个大于基准值的元素;arr[right] = arr[6] = 6 !< key = 6,所以向前继续找 arr[right–] = arr[5] = 3 < key = 6,找到一个小于基准值的元素。将这两个元素交换,此时数组变为arr[7] = {3,5,1,7,8,10,6}
2.arr[left++] = arr[1] = 5 < key = 6,所以left++继续向后找,arr[left++] = arr[2] = 1 < key = 6,所以left++继续向后找,arr[left] = arr[3] = 7> key = 6,找到了一个大于基准值的元素;arr[right–] = arr[4] = 8 > key = 6,所以right–继续向后找,此时left = 3 !< right = 3,left与right重合,所以将left指向的元素与基准值交换,数组变为arr[7] = {3,5,1,6,8,10,7}
此时基准值key = 6左边的元素均小于它,右边元素均大于它!!!待排序区间重新划分,以基准值的下标为边界,划分为左右两个区间:左边区间为[0,3),待排序数组为{3,5,1};右边区间为[4,size),待排序数组为{8,10,7} - 待排序区间为[0,3),待排序数组为{3,5,1},基准值key = 1,left指向待排序区间的开始,即arr[0],right指向待排序区间的末尾,即下标为3 - 1 = 2的元素。开始移动left和right,移动条件为left < right:
1.arr[left] = arr[0] = 3 > key = 1,找到一个大于基准值的元素;arr[right] = arr[2] = 1 !< key = 1,所以继续向前找,arr[right–] = arr[1] = 5 !< key = 1,所以继续向前找,left = 0 !< right–,left和right重合,将left指向的元素和基准值交换,数组变为arr = {1,5,3}
此时基准值key = 1的左边元素均小于它,右边元素均大于它!!!待排序区间重新划分,以基准值的下标为边界,划分为左右两个区间:左边区间为[0,0),不需要排序;右边区间为[1,3),待排序数组为{5,3} - 待排序区间为[1,3),待排序数组为{5,3},基准值key = 3,left指向待排序区间的开始,即下标为1的元素,right指向待排序区间的末尾,即下标为3 - 1 = 2的元素。开始移动left和right,条件为left < right
1.arr[left] = arr[1] = 5 > key = 3,找到了大于基准值的元素;arr[right] = arr[2] = 3 !< key = 3,所以继续向前找,right-- = 1 !> left,left和right重合,将left指向的元素和基准值交换,此时数组变为arr = {3,5}。
此时基准值key = 3的左边元素均小于它,右边元素均大于它!! - 待排序区间为[4,size),待排序数组为arr = {8,10,7},基准值key = 7,left指向待排序区间开始即下标为4的元素,right指向待排序区间的末尾,即下标为size - 1 = 6的元素。开始移动left和right,条件为left < right
1.arr[left] = arr[4] = 8 > key = 7,找到大于基准值的元素;arr[right] = arr[6] = 7 !< key = 7,所以继续向前找,arr[right–] = arr[5] = 10 !< key = 7,所以继续向前找,left !< right = 4,left和right重合,所以将left指向的元素与基准值交换,数组变为arr = {7,10,8}。
此时基准值key = 7左边的元素均小于它,右边的元素均大于它!!!待排序区间重新划分,以基准值的下标为边界,划分为左右两个区间:左边区间为[4,4),不需要排序;右边区间为[5,size),待排序数组为arr = {10,8} - 待排序数组为[5,size),基准值key = 8,left指向待排序区间的开始,即下标为5的元素,right指向待排序区间的末尾,即下标为size - 1 = 6的元素。开始移动left和right,条件为left < right
1.arr[left] = arr[5] = 10 > key = 8,找到了大于基准值的元素;arr[right] = arr[6] = 8 !< key = 8,所以继续向前找,left !< right-- = 5,left和right重合,将left指向的元素和基准值交换,数组变为{8,10}。
此时基准值key = 8左边的元素均小于它,右边元素均大于它!!!
至此,整个排序结束,数组变为arr = {1,3,5,6,7,8,10}
代码实现
package Sort;
import java.util.Arrays;
public class QuickSort {
public static void QuickSort(int[] arr,int size){
if(size <= 1){
return;
}
//定义一个函数用于递归处理数组
QuickSort1(arr,0,size);
}
public static void QuickSort1(int[] arr,int beg,int end){
if(end - beg <= 1){
return;
}
//定义Partion函数是对[beg,end)区间排序
//排序成一个以基准值为中心,左侧小于基准值右侧大于基准值
//返回的是排序后基准值所在的下标
int mid = Partion(arr,beg,end);
QuickSort1(arr,beg,mid);
QuickSort1(arr,mid + 1,end);
}
public static int Partion(int[] arr,int beg,int end){
int left = beg;
int right = end - 1;
//取最后一个元素为基准值
int key = arr[end - 1];
while(left < right){
//从左向右寻找大于基准值的值
while(left < right && arr[left] < key){
left++;
}
//从右向左寻找小于基准值的值
while(left < right && arr[right] >= key){
right--;
}
//找到之后进行交换
if(left < right){
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
}
//退出循环后将left和right同时指向的值与key指向的值进行交换
int temp = arr[left];
arr[left] = arr[end - 1];
arr[end - 1] = temp;
return left;
}
public static void main(String[] args) {
int[] arr = {10,5,1,7,8,3,6};
QuickSort(arr,arr.length);
System.out.println(Arrays.toString(arr));
}
}