快速排序
逻辑
采用分治思想的排序
- 定基准——选定一个基准默(默认为列表的最后一个元素)
- 划分区——分成比基准大、小的两个集合
- 递归调用——递归排序,拼装结果
- 注意递归终止条件,当集合只有一个元素
『递归 + 非原地排序』的实现虽然简单易懂,但是如此一来『快速排序』便不再是最快的通用排序算法了,因为递归调用过程中非原地排序需要生成新数组,空间复杂度颇高。list comprehension 大法虽然好写,但是用在『快速排序』算法上就不是那么可取了。
Two-way partitioning
对于仅使用一个索引进行 partition 操作的快排对于随机分布数列的效果还是不错的,但若数组本身就已经有序或者相等的情况下,每次划分仅能确定一个元素的最终位置,故最坏情况下的时间复杂度变为 O(n^2)O(n2 ). 那么有什么办法尽可能避免这种最坏情况吗?聪明的人类总是能找到更好地解决办法——使用两个索引分别向右向左进行 partition.
先来一张动图看看使用两个索引进行 partition 的过程。
python
def quick_sort(collection):
"""
out-in-place - 非原地快排
『递归 + 非原地排序』的实现虽然简单易懂,但是如此一来『快速排序』便不再是最快的通用排序算法了,因为递归调用过程中非原地排序需要生成新数组,空间复杂度颇高。
:param collection:
:return:
"""
print(collection)
length = len(collection)
if length <= 1:
return collection
pivot = collection.pop()
greater, lesser = [], []
for num in collection:
if num > pivot:
greater.append(num)
else:
lesser.append(num)
return quick_sort(lesser) + [pivot] +quick_sort(greater)
def quick_sort1(arr, low, upper):
"""
in-place - 原地快排
one index for partition
"""
print(arr)
if low >= upper:
return
m = low
for i in range(low + 1, upper + 1):
if arr[i] < arr[low]:
m += 1
arr[m], arr[i] = arr[i], arr[m]
# 交换m和low的位置
arr[m], arr[low] = arr[low], arr[m]
print(arr)
quick_sort1(arr, low, m - 1)
quick_sort1(arr, m + 1, upper)
unsortedArray = [6, 5, 3, 1, 8, 7, 2, 4]
print(quick_sort1(unsortedArray, 0, len(unsortedArray) - 1))
def quick_sort2(arr, low, upper):
'''
Two-way partitioning
'''
print(arr)
if low >= upper:
return arr
target = arr[low]
left, right = low + 1, upper
while left <= right:
while left <= right and arr[left] < target:
left += 1
while left <= right and arr[left] > target:
right -= 1
if left > right:
break
arr[left], arr[right] = arr[right], arr[left]
arr[low], arr[right] = arr[right], arr[low]
quick_sort2(arr, low, right - 1)
quick_sort2(arr, right + 1, upper)
java
public class quickSort {
public static void main(String[] args) {
int unsortedArray[] = new int[]{6, 5, 3, 1, 8, 7, 2, 4};
quickSort(unsortedArray);
}
public static void quickSort1(int[] array,int l,int u) {
for (int item : array) {
System.out.print(item + "");
}
System.out.println();
if (l>u) return;
int m =l;
for (int i = l+1;i<=u;i++){
if (array[i]<array[l]){
m +=1;
int temp = array[m];
array[m] = array[i];
array[i] = temp;
}
}
int temp = array[m];
array[m] = array[l];
array[l] = temp;
quickSort1(array,l,m-1);
quickSort1(array,m+1,u);
}
public static void quickSort2(int[] array, int l ,int u) {
for (int item :array){
System.out.print(item+"");
}
System.out.println();
if (l >= u) return;
int pivot = array[l];
int left = l + 1;
int right = u;
while (left <= right) {
while (left <= right && array[left] < pivot) {
left++;
}
while (left <= right && array[right] >= pivot) {
right--;
}
if (left > right) break;
int temp = array[left];
array[left] = array[right];
array[right] = temp;
}
int temp = array[right];
array[right] = array[l];
array[l] = temp;
quickSort2(array, l, right - 1);
quickSort2(array, right + 1, u);
}
public static void quickSort(int[] array) {
quickSort2(array,0,array.length-1);
}
}