通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

代码实现

  1. class QuickSort:
  2. def __init__(self, data: list):
  3. self.data = data
  4. def sort(self):
  5. """
  6. 就地进行快速排序,不使用额外的空间
  7. """
  8. self.__sort(0, len(self.data) - 1)
  9. def __sort(self, l:int, r:int):
  10. if l >= r:
  11. return
  12. p = self.__partition(l, r)
  13. self.__sort(l, p - 1)
  14. self.__sort(p + 1, r)
  15. def __partition(self, l: int, r: int):
  16. # print(self.data,self.data[l])
  17. j = l
  18. # [l+1,j]< v [j+1,i-1]>v
  19. # 选择数组第一个元素后面的元素开始比较
  20. for i in range(l + 1, r + 1):
  21. if (self.data[i] - self.data[l]) < 0:
  22. # 小于参考值 需要把当前遍历的数据放到参考数据的左边
  23. j = j + 1
  24. self.data[i], self.data[j] = self.data[j], self.data[i]
  25. self.data[l], self.data[j] = self.data[j], self.data[l]
  26. return j
  27. def sort_by_new_arr(self):
  28. """
  29. 开辟新空间来存储数据
  30. """
  31. self.data = self.__sort_by_new_arr(self.data)
  32. def __sort_by_new_arr(self,data:list):
  33. if len(data) < 2:
  34. return data
  35. # 选取基准,随便选哪个都可以,选中间的便于理解
  36. # mid = data[len(data) // 2]
  37. mid = data[0]
  38. # 定义基准值左右两个数列
  39. left, right = [], []
  40. # 从原始数组中移除基准值
  41. data.remove(mid)
  42. for item in data:
  43. # 大于基准值放右边
  44. if item >= mid:
  45. right.append(item)
  46. else:
  47. # 小于基准值放左边
  48. left.append(item)
  49. # 使用迭代进行比较
  50. return self.__sort_by_new_arr(left) + [mid] + self.__sort_by_new_arr(right)

以上是基于开辟新空间和就地排序的两个不同版本。

优化方案

数据有序

  1. def __partition(self, l: int, r: int):
  2. """
  3. 对于完全有序的数据来讲,每次排序之后右边的数组只比上次排序前的数组少了一个元素
  4. 以此类推递时间复杂度为O(n^2) 递归深度变成O(n)
  5. 优化方案:
  6. 在待处理的数据中随机选择分界点
  7. """
  8. import random
  9. # 随机下标
  10. p = random.randint(l, r) # l-r之前的随机值
  11. self.data[l],self.data[p] = self.data[p],self.data[l]
  12. # print(self.data,self.data[l])
  13. j = l
  14. # [l+1,j]< v [j+1,i-1]>v
  15. # 选择数组第一个元素后面的元素开始比较
  16. for i in range(l + 1, r + 1):
  17. if (self.data[i] - self.data[l]) < 0:
  18. # 小于参考值 需要把当前遍历的数据放到参考数据的左边
  19. j = j + 1
  20. self.data[i], self.data[j] = self.data[j], self.data[i]
  21. self.data[l], self.data[j] = self.data[j], self.data[l]
  22. return j

二路快排

  1. def sort_two_ways(self):
  2. """
  3. 双路快速排序
  4. """
  5. self.__sort_two_ways(0, len(self.data) - 1)
  6. def __sort_two_ways(self, l, r):
  7. if l >= r:
  8. return
  9. p = self.__sort_two_ways_partition(l, r)
  10. self.__sort_two_ways(l, p - 1)
  11. self.__sort_two_ways(p + 1, r)
  12. def __sort_two_ways_partition(self, l: int, r: int):
  13. import random
  14. # 随机下标
  15. p = random.randint(l, r) # l-r之前的随机值
  16. self.data[l], self.data[p] = self.data[p], self.data[l]
  17. # [l+1,i-1] <= v [j+1,r]>=v
  18. j = r
  19. i = l + 1
  20. while (True):
  21. while (i <= j and self.data[i] - self.data[l] < 0):
  22. i += 1
  23. while (j >= i and self.data[j] - self.data[l] > 0):
  24. j -= 1
  25. if (i >= j):
  26. break
  27. self.data[i], self.data[j] = self.data[j], self.data[i]
  28. i += 1
  29. j -= 1
  30. self.data[l], self.data[j] = self.data[j], self.data[l]
  31. return j

三路快排

  1. def sort_three_ways(self):
  2. """
  3. 三路快速排序
  4. """
  5. self.__sort_three_ways(0, len(self.data) - 1)
  6. def __sort_three_ways(self, l, r):
  7. if l >= r:
  8. return
  9. import random
  10. # 随机下标
  11. # p = random.randint(l, r) # l-r之前的随机值
  12. # self.data[l], self.data[p] = self.data[p], self.data[l]
  13. # [l+1,i-1] <= v [j+1,r]>=v
  14. lt = l
  15. i = l + 1
  16. gt = r + 1
  17. while (i < gt):
  18. if self.data[i] - self.data[l] < 0:
  19. lt += 1
  20. self.data[i], self.data[lt] = self.data[lt], self.data[i]
  21. i+=1
  22. elif self.data[i] - self.data[l] > 0:
  23. gt -= 1
  24. self.data[i], self.data[gt] = self.data[gt], self.data[i]
  25. else:
  26. i += 1
  27. self.data[l], self.data[lt] = self.data[lt], self.data[l]
  28. self.__sort_three_ways(l,lt-1)
  29. self.__sort_three_ways(gt,r)

时间复杂度

  • 最坏情况下 O(n^2) 概率极低
  • 复杂度期望值 O(Nlogn) 层数的期望 O(logn)