快速排序算法
快速排序是一种基于划分和迭代的排序算法。
主要原理:在每一次迭代时,都把向量分城左,中,右(left, mid, right)三部分,其中左边部分全部都小于中间值,而右边部分全部大于等于中间值。这样,将整个向量分解成一个类似二叉树的结构,从而达到排序的目的。
而这种方法减小计算量的关键技术是,在选定mid指针所指的值之后,要用最快的方法将小于mid值和大于mid值的数分开。
基本思路:在当前循环下,将mid值与向量队尾/队头的值进行交换。将left中左起第一个大于mid的数字,与right中右起第一个小于mid的数字进行互换。当一遍遍历完成之后,left和right会和,而所指数值正好是第一个大于/小于mid值的数字。然后,将放置于队尾/队头的mid元素与之进行互换,就完成了第一次迭代。然后将left子列调用原函数,再将right子列调用原函数.
快速排序的效率:
空间复杂度:快速排序是递归算法,每一层的调用数据用栈来存放,所以递归调用层数与二叉树高度类似。理想情况下,递归生成一个满二叉树,设数列长度为n,设二叉树高度为h,则有
n / (2 ^ h) = 1. 即有 h = log2(n) 即空间复杂度最小为O(log2(n))
最坏情况下,二叉树为单链,则栈长度为n,空间复杂度为O(n)
时间复杂度:设T(n)为对长度为n的待排序列进行排序的时间。则理想情况下,每次划分都生成两个等长子列。即有:
T(n) <= c * n + 2 * T(n / 2) 其中c * n为每次划分所需的n次比较的时间。 T(n / 2)为对子列排序所需时间。继续推导:
T(n) <= c * n + 2 * T(n / 2)
<= 2 * c * n + 2 * (c * n / 2 + 2* T(n / 4)) = 2 * c * n + 4 * T(n / 4) ...... 递归次数即二叉树高度h
<= log2(n) * c * n + n(T(1) = O(n*log2(n))
所以非理想情况下 h 不是 log2(n) 而是 n, 即时间复杂度为 O(n^2)
class Solution:
def quick_sort(self, nums):
lens = len(nums)
if lens <= 1:
return(nums)
mid = lens // 2
nums[-1], nums[mid] = nums[mid], nums[-1]
mid = -1
right = lens - 1
left = 0
print(left, mid)
while right > left:
while nums[left] <= nums[mid] and right > left:
left = left + 1
while nums[right] > nums[mid] and right > left:
right = right - 1
nums[right], nums[left] = nums[left], nums[right]
nums[right], nums[mid] = nums[mid], nums[right]
mid = right
#print(nums)
nums[:mid] = self.quick_sort(nums[:mid])
nums[mid + 1:] = self.quick_sort(nums[mid + 1:])
print(nums)
return(nums)
if __name__ == "__main__":
sol = Solution()
res = sol.quick_sort([9,7,5,3,2,7,5,4,23,9,56,67,23,11])
优化:
1.上述算法中,mid = len // 2 一步可以省略,因为支点只是要放到队首或队尾等待比较的点,与其在数列中的初始位置并无关系,所以可以找任意一个点作为支点。
基于这点,算法可改如下:
def quick_sort2(self, nums):
lens = len(nums)
if lens <= 1:
return(nums)
mid = -1
right = lens - 1
left = 0
while right > left:
while nums[left] <= nums[mid] and right > left:
left = left + 1
while nums[right] > nums[mid] and right > left:
right = right - 1
nums[right], nums[left] = nums[left], nums[right]
nums[right], nums[mid] = nums[mid], nums[right]
mid = right
nums[:mid] = self.quick_sort(nums[:mid])
nums[mid + 1:] = self.quick_sort(nums[mid + 1:])
print(nums)
return(nums)