快速排序
难易程度 : 中等
类似归并排序,快速排序是一种分治算法。快速排序挑选一个元素作为基数,然后围绕选定的基数分割给定的数组。快速排序有很多版本,这些版本以不同的方式挑选基数。
- 总是挑选第一个元素作为基数
- 总是挑选最后一个元素作为基数(下面有实现的案例)
- 挑选任意元素作为基数
- 挑选中位数作为基数
快速排序的关键步骤是分区。分区的目标是给定数组和基数x,把x放到有序数组中正确的位置,然后把所有比x小的数放到x前面,再把所有比x大的数放在x之后。所有这些操作完成的时间应该是线性的。
快速排序递归函数伪代码
/* --> Starting index, high --> Ending index */
quickSort(arr[], low, high)
{
if (low < high)
{
/* pi is partitioning index, arr[pi] is now at right place */
pi = partition(arr, low, high);
quickSort(arr, low, pi - 1); // Before pi
quickSort(arr, high, pi + 1); // After pi
}
}
分区算法
有很多种方法实现分区,下面的伪代码采用算法导论中的方法。逻辑很简单,从数组最左侧元素开始,记录小于等于基数的元素索引为i。遍历数组,如果发现更小的元素,则将当前元素与arr[i]交换位置。如否则忽略当前元素。
/* low --> Starting index, high --> Ending index */
quickSort(arr[], low, high)
{
if (low < high)
{
/* pi is partitioning index, arr[pi] is now at right palce */
pi = partition(arr, low, high);
quickSort(arr, low, pi - 1); // Before pi
quickSort(arr, high, pi + 1); // After pi
}
}
分区伪代码
/* This function takes last element as pivot, places
the pivot element at its correct position in sorted
array, and places all smaller (smaller than pivot)
to left of pivot and all greater elements to right
of pivot */
partition (arr[], low, high)
{
// pivot (Element to be places at right position)
pivot = arr[high];
i = (low - 1) // Index of smaller element and indicates the
// right position of pivot found so far
for (j = low; j <= high - 1; j++)
{
// If current element is smaller than the pivot
if (arr[j] < pivot)
{
i++; // increment index of smaller element
swap arr[i] and arr[j]
}
}
swap (arr[i + 1] and arr[high])
return (i + 1)
}
分区函数说明
arr[] = {10, 80, 30, 90, 40, 50, 70}
Indexes: 0 1 2 3 4 5 6
low = 0, high = 6, pivot = arr[h] = 70
Initialize index of smaller element, i = -1
Traverse elements from j = low to high-1
j = 0: Since arr[j] <= pivot, do i++ and swap(arr[i], arr[j])
i = 0
arr[] = {10, 80, 30, 90, 40, 50, 70} // No change as i and j
// are same
j = 1: Since arr[j] > pivot, do nothing
// No change in i and arr[]
j = 2: Since arr[j] <= pivot, do i++ and swap(arr[i], arr[j])
i = 1
arr[] = {10, 30, 80, 90, 40, 50, 70} // We swap 80 and 30
j = 3: Since arr[j] > pivot, do nothing
// No change in i and arr[]
j = 4: Since arr[j] <= pivot, do i++ and swap(arr[i], arr[j])
i = 2
arr[] = {10, 30, 40, 90, 80, 50, 70} // 80 and 40 Swapped
j = 5: Since arr[i] <= pivot, do i++ and swap arr[i] with arr[j]
i = 3
arr[] = {10, 30, 40, 50, 80, 90, 70} // 90 and 50 Swapped
We come out of loop because j is now equal to high-1.
Finally we place pivot at correct position by swapping
arr[i+1] and arr[high] (or pivot)
arr[] = {10, 30, 40. 50, 70, 90, 80} // 80 and 70 Swapped
Now 70 is at its correct place. All elements smaller than
70 are before it and all elements greater than 70 are after
it.
代码实现
# Python3 implementation of QuickSort
# This Function handles sorting part of quick sort
# start and end points to first and last element of
# an array respectively
def partion(start, end, array):
# Initializing pivot's index to start
pivot_index = start
pivot = array[pivot_index]
# This loop runs till start pointer crosses
# end pointer, and when it does we swap the
# pivot with element on end pointer
while start < end:
# Increment the start pointer till it finds an
# element greater than pivot
while start < len(array) and array[start] <= pivot:
start += 1
# Decrement the end pointer till it finds an
# element less than pivot
while array[end] > pivot:
end -= 1
# If start and end have not crossed each other,
# swap the numbers on start and end
if(start < end):
array[start], array[end] = array[end], array[start]
# Swap pivot element with element on end pointer.
# This puts pivot on its correct sorted place.
array[end], array[pivot_index] = array[pivot_index], array[end]
# Returning end pointer to divide the array into 2
return end
# The main function that implements QuickSort
def quick_sort(start, end, array):
if (start < end):
# p is partitioning index, array[p]
# is at right place
p = partition(start, end, array)
# Sort elements before partion
# and after partition
quick_sort(start, p - 1, array)
quick_sort(p + 1, end, array)
# Driver code
array = [10, 7, 8, 9, 1, 5]
quick_sort(0, len(array) - 1, array)
print(f'Sorted array: {array}')
# This code is contributed by Adnan Aliakbar
输出结果
Sorted array:
1 5 7 8 9 10
简洁版代码
#User function Template for python3
class Solution:
#Function to sort a list using quick sort algorithm.
def quickSort(self,arr,low,high):
# code here
if (low < high):
p = self.partition(arr, low, high)
self.quickSort(arr, low, p-1)
self.quickSort(arr, p+1, high)
def partition(self,arr,low,high):
# code here
pivot_index = low
pivot = arr[pivot_index]
while low < high:
while low < len(arr) and arr[low] <= pivot:
low += 1
while arr[high] > pivot:
high -= 1
if (low < high):
arr[low], arr[high] = arr[high], arr[low]
arr[high], arr[pivot_index] = arr[pivot_index], arr[high]
return high
#{
# Driver Code Starts
#Initial Template for Python 3
# if __name__ == "__main__":
# t=int(input()) # provide array length
# for i in range(t):
# n=int(input()) # provide sort length, less or equal than array length
# arr=list(map(int,input().split())) # provide array, seprated with space
# Solution().quickSort(arr,0,n-1)
# for i in range(n):
# print(arr[i],end=" ")
# print()
# simple version
if __name__ == '__main__':
arr = [4, 1, 3, 9, 7]
n = 5
Solution().quickSort(arr, 0, n-1)
print(arr)
# } Driver Code Ends
快速排序分析
快速排序时间复杂度一般来说可以记作如下:
T(n) = T(k) + T(n-k-1) + θ(n)
前两项是两个递归调用,最后一个是分区过程。k是比基数小的所有元素。
快速排序时间复杂度取决于输入数据和分区策略。