004.排序算法——(一)交换排序——快速排序

004.排序算法——(一)交换排序——快速排序

介绍

  • 在平均状况下,排序 n n n 个项目要 O ( n l o g n ) Ο(nlogn) O(nlogn) 次比较
  • 在最坏状况下则需要 O ( n 2 ) Ο(n^2) O(n2)次比较,但这种状况并不常见
  • 快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环可以在大部分的架构上很有效率地被实现出来
  • 快速排序使用分治法策略来把一个串行分为两个子串行
  • 本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法
  • 快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多

算法步骤

  1. 从数列中挑出一个元素,称为 “基准”;
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)
  3. 在这个分区退出之后,该基准就处于数列的中间位置
  4. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序

代码

def quickSort(arr, left=None, right=None):	# 可以指定排序的区间
    left = 0 if not isinstance(left,(int, float)) else left
    right = len(arr)-1 if not isinstance(right,(int, float)) else right
    if left < right:
        partitionIndex = partition(arr, left, right)
        quickSort(arr, left, partitionIndex-1)
        quickSort(arr, partitionIndex+1, right)
    return arr


# index:指向刚交换到的比基准小的数
# i:用来遍历数组的指针
def partition(arr, left, right):
    pivot = left    # 指定left对应的数据为基准
    index = pivot+1	# 保持基准位置不变,从下一位开始
    i = index
    while  i <= right:
        if arr[i] < arr[pivot]:
            swap(arr, i, index)     # 将index对应的数和i对应的数交换(index对应的数一定是大于等于基准的),和i指向同一个数的情况下除外
            index+=1    # 完成交换之后,index指向这个比基准小的数的下一个位置,这个位置已经由i进行过排除,所以对应的数也是大于等于基准的
        i+=1
    swap(arr,pivot,index-1) # 将最新的小于基准的数和基准交换,就能实现基准左边都是小于它的数,右边都是大于它的数
    return index-1


def swap(arr, i, j):
    arr[i], arr[j] = arr[j], arr[i]


def main():
	nums = [2, 5, 4, 7, 5, 0, 9,  1]	# 可变数据类型
	quickSort(nums)
	print(nums)


if __name__ == '__main__':
	main()

改进

随机选取基准对于快速排序来说是更能接近时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
将该代码背下来

import random
def quickSort(arr, left=None, right=None):	# 可以指定排序的区间
    left = 0 if not isinstance(left,(int, float)) else left
    right = len(arr)-1 if not isinstance(right,(int, float)) else right
    if left < right:
        partitionIndex = RandomGetIndex(arr, left, right)
        quickSort(arr, left, partitionIndex-1)
        quickSort(arr, partitionIndex+1, right)
    return arr


def RandomGetIndex(nums, left, right):
    temp = random.choice(range(left,right+1))   
    swap(nums, left, temp)
    index = partition(nums,left,right)
    return index


# index:指向刚交换到的比基准小的数
# i:用来遍历数组的指针
def partition(arr, left, right):
    pivot = left    # left对应的数据为基准(但是前面是随机选取的)
    index = pivot+1	# 保持基准位置不变,从下一位开始
    i = index
    while  i <= right:
        if arr[i] < arr[pivot]:
            swap(arr, i, index)     # 将index对应的数和i对应的数交换(index对应的数一定是大于等于基准的),和i指向同一个数的情况下除外
            index+=1    # 完成交换之后,index指向这个比基准小的数的下一个位置,这个位置已经由i进行过排除,所以对应的数也是大于等于基准的
        i+=1
    swap(arr,pivot,index-1) # 将最新的小于基准的数和基准交换,就能实现基准左边都是小于它的数,右边都是大于它的数
    return index-1


def swap(arr, i, j):
    arr[i], arr[j] = arr[j], arr[i]


def main():
	nums = [2, 5, 4, 7, 5, 0, 9,  1]	# 可变数据类型
	quickSort(nums)
	print(nums)


if __name__ == '__main__':
	main()

非递归方式,同样非常重要

import random
def quickSort(arr, left=None, right=None):	# 可以指定排序的区间
    left = 0 if not isinstance(left,(int, float)) else left
    right = len(arr)-1 if not isinstance(right,(int, float)) else right

    stack = [left, right]   # 模拟一个栈
    while stack:
        j = stack.pop()
        i = stack.pop()

        partitionIndex = partition(arr, i, j)

        if i < partitionIndex - 1:
            stack.append(i)
            stack.append(partitionIndex -1)
        
        if j > partitionIndex + 1:
            stack.append(partitionIndex + 1)
            stack.append(j)


def RandomGetIndex(nums, left, right):
    temp = random.choice(range(left,right+1))   
    swap(nums, left, temp)
    index = partition(nums,left,right)
    return index


# index:指向刚交换到的比基准小的数
# i:用来遍历数组的指针
def partition(arr, left, right):
    pivot = left    # left对应的数据为基准(但是前面是随机选取的)
    index = pivot+1	# 保持基准位置不变,从下一位开始
    i = index
    while  i <= right:
        if arr[i] < arr[pivot]:
            swap(arr, i, index)     # 将index对应的数和i对应的数交换(index对应的数一定是大于等于基准的),和i指向同一个数的情况下除外
            index+=1    # 完成交换之后,index指向这个比基准小的数的下一个位置,这个位置已经由i进行过排除,所以对应的数也是大于等于基准的
        i+=1
    swap(arr,pivot,index-1) # 将最新的小于基准的数和基准交换,就能实现基准左边都是小于它的数,右边都是大于它的数
    return index-1


def swap(arr, i, j):
    arr[i], arr[j] = arr[j], arr[i]


def main():
	nums = [2, 5, 4, 7, 5, 0, 9,  1]	# 可变数据类型
	quickSort(nums)
	print(nums)


if __name__ == '__main__':
	main()

时间复杂度:最差情况下 O ( n 2 ) O(n^2) O(n2), 平均情况下 O ( n l o g n ) O(nlogn) O(nlogn)
稳定性:不稳定

你可能感兴趣的:(算法,快速排序,排序算法,数据结构,Python,交换排序)