python之快速排序-QuickSort

介绍

快速排序同冒泡排序一样,也是属于交换排序,通过比较并交换元素位置来达到排序的最终效果

但不同的是,冒泡排序只是把其中选择出来的1个元素交换到数列的一侧
快速排序是在每一轮的交换比较过程中,每次选择一个基准元素,把数列当中比基准元素的元素移动到它的一侧,比基准元素的元素移动到它的另外一侧,循环往复最终排好顺序


快速排序总体的平均时间复杂度是在O(nlogn)
但是在最坏的情况下依然有O(n^2)的可能


快速排序的一个很重要的核心问题就是基数的选择

那么基数的选择一共有两种方式:

  1、可以将数列的首个元素作为基数;
  2、也可以随机的选取一个数列当中的元素作为基数

基数选择好之后就看具体实现的方法了,实现的方法有两种:

  1、双边循环
  2、单边循环


一、双边循环

举一个简单的例子:

 用随机生成的列表:[17, 14, 30, 8, 20, 2, 8, 23]

在这个列表当中用下标为0的元素作为基数pivot,也就是17,在最左右两侧各设置一个指针,分别为left,right


下面来实现第一轮,第一次遍历

 pivot
[17, 14, 30, 8, 20, 2, 8, 23]
  left               right

一开始,动right指针,让right指针所指的元素和pivot进行比较,如果大于等于pivot,那right指针就向左移动一位;如果小于pivot,则right指针停止,切换到left指针
在当前的列表中23>17,则向左移动,比较之后发现8<17,则right指针指向8,停止

 pivot
[17, 14, 30, 8, 20, 2, 8, 23]
  left             right

此时,轮到left指针,让left指针指向的元素和pivot进行比较,如果小于等于pivot,则left指针向右移动;如果大于pivot,则指针停止,一开始的left和pivot是一个元素,所以值相等,left向右移动一位,指向14,发现14小于17

 pivot
[17, 14, 30, 8, 20, 2, 8, 23]
       left           right

那么left指针向右再移动一位,到30,发现17<30,则left指针停止

 pivot
[17, 14, 30, 8, 20, 2, 8, 23]
            left         right

停止之后,交换left和right指针所指向的对应的值,

 pivot
[17, 14, 8, 8, 20, 2, 30, 23]
            left      right

发生数组元素的交换之后,开始第一轮,第二次的遍历
依旧从right指针开始,由于right指向的值是30>17,所以right指针向左移动

 pivot
[17, 14, 8, 8, 20, 2, 30, 23]
            left    right

当right 指向到2之后,2<17,right指针停止,此时轮到left指针,由于8<17,所以右移一位

 pivot
[17, 14, 8, 8, 20, 2, 30, 23]
                 left     right

但此时,当前left指向的值8,依然小于17,所以left指针继续右移

 pivot
[17, 14, 8, 8, 20, 2, 30, 23]
                 left  right

此时left指向的20是大于pivot的,left指针停止,停止之后,left和right指针各自指向的值,发生交换

 pivot
[17, 14, 8, 8, 2, 20, 30, 23]
               left   right

发生交换之后开始第一轮,第三次遍历
重新回到right指针,20<17,right指针向左移动。此时,right和left重合

 pivot
[17, 14, 8, 8, 2, 20, 30, 23]
                left
               right

重合之后,将pivot的元素和left、right指针重合的元素进行交换

            pivot
[2, 14, 8, 8, 17, 20, 30, 23]
              left
             right

交换元素之后,第一轮遍历完成,开始下一轮的遍历,之后同理


二、代码实现

def quick_sort_use(startIndex, endIndex, randomList):
	'''
	快速排序双向循环
	:param startIndex: 开始位置下标
	:param endIndex: 结束位置下标
	:param randomList: 创建的用于排序的随机数组
	:return: 左右指针
	'''

	# 选择列表当中第一个元素作为基数
	choose_pivot = randomList[startIndex]
	# 确定left指针
	left_pointer = startIndex
	# 确定right指针
	right_pointer = endIndex
	# 准备遍历
	while left_pointer != right_pointer:
		isRightExchange = True
		# right指针的移动
		if left_pointer < right_pointer and choose_pivot <= randomList[right_pointer]:
			right_pointer -= 1
			isRightExchange = False
		isLeftExchange = True
		# left指针移动
		if left_pointer < right_pointer and choose_pivot >= randomList[left_pointer]:
			left_pointer += 1
			isLeftExchange = False
		if isLeftExchange and isRightExchange and left_pointer < right_pointer:
			randomList[left_pointer], randomList[right_pointer] = randomList[right_pointer], randomList[left_pointer]

	# 左右指针重合之后,与pivot进行交换
	randomList[startIndex] ,randomList[left_pointer] = randomList[left_pointer], choose_pivot


	return left_pointer , right_pointer # 返回left指针, right指针

num_list = [27, 30, 24, 39, 25, 46, 26, 29, 20]

# 递归实现快排
def use_quickSort(startIndex, endIndex, randomList):
	
	if startIndex >= endIndex:return
	pivot = quick_sort_use(startIndex, endIndex, randomList)
	use_quickSort(startIndex, pivot[0] - 1, randomList)  # 左边
	use_quickSort(pivot[1] + 1 ,endIndex, randomList)  # 右边

# 调用快排

use_quickSort(0, len(num_list) - 1, num_list)
print('双边循环结果:\n%s'%num_list)

在这里插入图片描述


三、单边循环

单边循环,顾名思义从数列的一侧进行遍历

参考数列如下:
  [15, 17, 10, 3, 6, 9, 10, 4]

首先,选中一个元素作为基数:

pivot [15, 17, 10, 3, 6, 9, 10, 4]

再设置一个pointer指针,指向数列起始位置

pivot [15, 17, 10, 3, 6, 9, 10, 4]
      p

准备好之后,开始遍历

从基数的下一个元素开始遍历,如果遍历到的元素大于基数,则接着向后遍历
如果遍历到的元素小于基数,则pointer指针向右移动一位,然后将遍历的元素,和移动pointer指针之后所指的元素进行交换

第一轮开始:
从15的下一个元素开始遍历,17大于15,因此接着向后遍历

pivot [15, 17, 10, 3, 6, 9, 10, 4]
      p

遍历到10的时候,发现,10<15,此时pointer指针向右移动一位,指向17

pivot [15, 17, 10, 3, 6, 9, 10, 4]
            p

交换二者的位置

pivot [15, 10, 17, 3, 6, 9, 10, 4]
            p

完成交换之后接着向后遍历

发现3<15,此时pointer指针向右移动一位

pivot [15, 10, 17, 3, 6, 9, 10, 4]
                    p

交换二者位置

pivot [15, 10, 3, 17, 6, 9, 10, 4]
                   p

接着向后遍历,6<15,pointer指针随即向右移动一位

pivot [15, 10, 3, 17, 6, 9, 10, 4]
                     p

开始交换

pivot [15, 10, 3, 6, 17, 9, 10, 4]
                    p

交换之后接着遍历,9<17,pointer右移一位

pivot [15, 10, 3, 6, 17, 9, 10, 4]
                           p

开始交换

pivot [15, 10, 3, 6, 9, 17, 10, 4]
                          p

交换之后,继续遍历,后面同理,全部遍历完成之后的结果如下:

pivot [15, 10, 3, 6, 9, 10, 4, 17]
                         p

此时第一轮全部遍历完成,将pointer所指的元素和pivot互换

pivot [4, 10, 3, 6, 9, 10, 15, 17]
                        p

第一轮完成,分治法后,开始递归各自剩下的区域


四、单边循环代码

def unidirection_quick_sort(startIndex, endIndex, num_list):
	'''
	处理快排的单边循环
	:param startIndex:开始位置下标
	:param endIndex:结束位置下标
	:param num_list:待排序的数组
	:return:pointer指针
	'''
	pivot = num_list[startIndex]
	pointer = startIndex
	for i in range(startIndex + 1, endIndex + 1):  # 循环遍历整个数列
		if num_list[i] < pivot:
			pointer += 1
			num_list[i], num_list[pointer] = num_list[pointer], num_list[i]
	# 一趟遍历完成之后,交换pointer指向的值和pivot
	num_list[startIndex], num_list[pointer] = num_list[pointer], num_list[startIndex]

	return pointer

同样递归实现方法的调用

quick_num = [15, 17, 10, 3, 6, 9, 10, 4]
use_unidirection_quick_sort(0, len(quick_num) - 1, quick_num)
print('单边循环结果:\n%s'%quick_num)

python之快速排序-QuickSort_第1张图片

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