快速排序
快排的性质
中文名称 | 英文名称 | 平均时间复杂度 | 最坏时间复杂度 | 最好时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|---|---|---|
快速排序 | Quick | n*logn | n2 | n*logn | n*logn | 不稳定 |
快排采用的是分治的思想,每次递归的的时候需要排序数组的长度都会减少,所以每次递归的时候只需要遍历子数组就好
有两种理解的方式,先说我觉得比较好理解的一种方式
1、先取一个元素为key,最简单的方式是取第一个元素为key,然后后面会基于这个元素进行比较
2、每次进入排序的方法的时候有两个指针分别指向待排序数组的头和尾,我这里以left和right命名,left指向头,right指向尾
3、先将尾指针向前移动,直到找到了第一个小于key的元素,停下来,假设此时指向的值是1
4、再将头指针向后移动,直到找到第一个大于key的元素,停下来,假设此时指向的值是5
5、交换头尾指针指向的值,按照上面的假设就是交换1和5的位置
6、继续移动指针并重复三四五的动作,直到两个指针重合
7、将指针重合位置的值和key进行交换
8、然后将重合位置的前半部分和后半部分重复执行执行1-7
一定要先移动右边的指针
其中3、4步骤指针移动的前提是尾指针的索引大于头指针才移动
code
public static void sort(int arr[], int left, int right){
//空数组的话当然要直接返回了
if(arr == null || arr.length == 0){
return;
}
//头指针的索引大于尾指针了,证明当前递归到最底层了
//因为递归到只有一个元素的子数组时传入的参数肯定是头大于尾了
if(left > right){
return;
}
//记录key
int key = arr[left];
//记录要循环的指针
int l = left;
int r = right;
//当头尾指针没有重合的时候,循环
while(l != r){
//从后往前找到一个小于key的元素的索引
while (arr[r] >= key && l < r){
r--;
}
//从前往后再找到一个大于key的元素的索引
while (arr[l] <= key && l < r){
l++;
}
//如果尾指针小于头指针,交换位置
//因为有可能移动到同一个位置了,那就不需要交换了
if(l < r){
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
}
//这时候l和r肯定指向同一个位置,直接用l就行
//将key的位置和l的位置交换
arr[left] = arr[l];
arr[l] = key;
//递归处理左边和右边
sort(arr, left, l - 1);
sort(arr, l + 1, right);
}
我觉得理解起来费劲的方式,上学的时候老师就是这么讲的,即使画了图也很理解
1、先取一个元素为key,最简单的方式是取第一个元素为key,然后后面会基于这个元素进行比较
2、每次进入排序的方法的时候有两个指针分别指向待排序数组的头和尾,我这里以left和right命名,left指向头,right指向尾
3、先将尾指针向前移动,直到找到了第一个小于key的元素,将此时right的值赋值给left
4、再将头指针向后移动,直到找到第一个大于key的元素,将此时left的值赋值给right
5、继续移动指针并重复三四五的动作,直到两个指针重合
6、将key的值赋值给指针重合的位置
7、然后将重合位置的前半部分和后半部分重复执行执行1-7
仔细一想这个效果其实和上面第一种也是一样的,两两元素交换位置,但是理解起来就感觉很绕,这讲法就是阻止我学会快排的最大障碍,但是看了第一种再来理解这样的交换就好理解多了,上代码
public static void sort2(int arr[], int left, int right){
if(arr == null || arr.length == 0){
return;
}
if(left > right){
return;
}
int key = arr[left];
int l = left;
int r = right;
while (l != r){
while (arr[r] >= key && l < r){
r--;
}
arr[l] = arr[r];
while (arr[l] <= key && l < r){
l++;
}
arr[r] = arr[l];
}
arr[l] = key;
sort2(arr, left, l - 1);
sort2(arr, l + 1, right);
}
下面这种少一个交换的动作,省了一个中间变量,空间复杂度应该会更低一些