03_2排序算法:快速排序、归并排序

简介: 03_2排序算法:快速排序、归并排序

快速排序概念

快速排序(Quicksort),又称为交换排序,通过一趟排序将要排序的数据分割为独立的两部分。假设要排序的列表是A[0]...A[N-1],首先任意选取一个数据(通常选用列表的第一个数)作为基准数据,一般我们都选择第一个数作为基准数据,然后将所有比它小的数都放到它的左边,所有比它大的数都放到它的右边,这个过程称为快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变化。

算法步骤

  1. 设置两个low、high,排序开始的时候:low=0,high=N-1
  2. 以第一个列表元素作为基准数据,赋值给mid,即mid=A[0]
  3. 从high开始向前搜索,即由后开始向前搜索(high--),找到第一个小于mid的值A[high],将A[high]和A[low]的值交换
  4. 从low开始向后搜索,即向前开始向后搜索(low++),找到大于mid的A[low],将A[low]和A[high]的值交换。
  5. 重复第3、4步,直到low=high;

时间复杂度

  • 最优时间复杂度:O(nlogn) #每次分成两半,要分logn次,再乘遍历的n次
  • 最坏时间复杂度:O(n2) #每次只分出一个元素出来,要分n次,再乘遍历的n次
  • 稳定性:不稳定

算法实现

1. def quick_sort(alist,start,end):
2. """
3.     :param alist:
4.     :return:alist.sort
5.     快速排序首先要选择一个基准,将其他数据与这个基准比较,比它大的放右边,比它小的放左边,循环这个过程,完成排序
6.     定义两个指针,一个low一个high,
7.     开始是high先做比较,如果high对应的元素比基准大就不懂,high--,如果比基准小,则与low对应的元素交换,然后low++
8.     直到low==high说明一趟快速排序已经完成,再将基准添加到序列中
9.     上面已经完成一次快速排序,再将左序列和右序列进行递归,注意设置一个出口,即可完成整个遍历
10.     以alist = [5,1,3,2,8,7,6,4]为例
11.     以alist = [4,1,3,2,8,7,6,4]为例
12.     """
13. # 递归的出口
14. if start >= end:
15. return
16.     mid = alist[start]  # 定义基准 5
17.     low = start  # 左指针
18.     high = end  # 右指针 7
19. # 判断high是不是大于mid,大于的话就不用交换,之间high--,直到小于的时候进行交换
20. while low <high:
21. while alist[high] >= mid and high > low:  #7>0
22.             high -=1
23.         alist[low] = alist[high]
24. #判断low是不是小于mid, 小于的话就不用交换,之间low++,直到大于的时候进行交换
25. while alist[low] < mid and high>low:
26.             low += 1
27.         alist[high] = alist[low]
28.     alist[low] = mid
29.     quick_sort(alist,0,low-1)
30.     quick_sort(alist,low+1,end)
31. return alist

总结

主要是两个指针的交替变化,可以用while循环来执行,判断high是不是大于mid,大于的话就不用交换,之间high--,直到小于的时候进行交换;判断low是不是小于mid, 小于的话就不用交换,之间low++,直到大于的时候进行交换;最后再加上基准,这样就完成一次快速排序,之后再从外面用一个while循环,里面用递归思想不断对左序列和右序列进行操作,记得写一个出口,start >= end,这样快速排序算法就结束了。


归并排序概念

归并排序(Merge sort)是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。将数组分解最小之后,然后合并两个有序数组,基本思想是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就向后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。

算法步骤

先分再合

时间复杂度

  • 最优时间复杂度:O(nlogn)
  • 最坏时间复杂度:O(nlogn)
  • 稳定性:稳定

程序实现

1. def Merge_sort(alist):
2. """
3.     主要思想就是分治法,先拆分再合并
4.     整个框架是递归算法,既包括拆解成一个一个的列表,也包列表的缝合
5.     以为[5,1,3,2,8,7,6,4]例,拆解成[5],[1],[3],[2],[8],[7],[6],[4]
6.     第一次合并成[1,5],[2,3],[7,8],[4,6]
7.     第二次合并成[1,2,3,5],[4,6,7,8]
8.     第三次合并成[1,2,3,4,5,6,7,8]
9.     :param alist:
10.     :return: alist.sort
11.     """
12.     n = len(alist)
13.     mid = n //2
14. if n <= 1:
15. return alist
16.     left_list = Merge_sort(alist[0:mid])
17.     right_list = Merge_sort(alist[mid::])
18.     left_p = 0 # 定义左指针
19.     right_p = 0 # 定义右指针
20.     result_list =[]
21. while left_p < len(left_list) and right_p < len(right_list):
22. if left_list[left_p] < right_list[right_p]:
23.             result_list.append(left_list[left_p])
24.             left_p += 1
25. else:
26.             result_list.append(right_list[right_p])
27.             right_p += 1
28.     result_list.extend(left_list[left_p::])
29.     result_list.extend(right_list[right_p::])
30. 
31. return result_list

总结

主要思想就是分治法,先拆分再合并,整个框架是递归算法,既包括拆解成一个一个的列表,也包列表的缝合。定义两个指针,一个左指针,一个右指针,先比较两个指针指向的的元素大小,将小的元素添加到目标序列中,然后该指针+1继续比较,直到某一个指针走到头,此时将另一个指针指向元素的后面元素全部添加到目标序列中。


相关文章
|
7天前
|
搜索推荐 算法 Java
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
该博客文章通过UML类图和Java源码示例,展示了如何使用适配器模式将QuickSort类和BinarySearch类的排序和查找功能适配到DataOperation接口中,实现算法的解耦和复用。
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
|
5天前
|
算法 搜索推荐
算法设计 (分治法应用实验报告)基于分治法的合并排序、快速排序、最近对问题
这篇文章是关于分治法应用的实验报告,详细介绍了如何利用分治法实现合并排序和快速排序算法,并探讨了使用分治法解决二维平面上的最近对问题的方法,包括伪代码、源代码实现及时间效率分析,并附有运行结果和小结。
|
1月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
【7月更文挑战第12天】归并排序是高效稳定的排序算法,采用分治策略。Python 实现包括递归地分割数组及合并已排序部分。示例代码展示了如何将 `[12, 11, 13, 5, 6]` 分割并归并成有序数组 `[5, 6, 11, 12, 13]`。虽然 $O(n log n)$ 时间复杂度优秀,但需额外空间,适合大规模数据排序。对于小规模数据,可考虑其他算法。**
57 4
|
1月前
|
算法 搜索推荐 编译器
算法高手养成记:Python快速排序的深度优化与实战案例分析
【7月更文挑战第11天】快速排序是编程基础,以O(n log n)时间复杂度和原址排序著称。其核心是“分而治之”,通过选择基准元素分割数组并递归排序两部分。优化包括:选择中位数作基准、尾递归优化、小数组用简单排序。以下是一个考虑优化的Python实现片段,展示了随机基准选择。通过实践和优化,能提升算法技能。**
32 3
|
1月前
|
算法 搜索推荐 C#
|
2月前
|
搜索推荐 算法 Java
Java中的快速排序、归并排序和堆排序是常见的排序算法。
【6月更文挑战第21天】Java中的快速排序、归并排序和堆排序是常见的排序算法。快速排序采用分治,以基准元素划分数组并递归排序;归并排序同样分治,先分割再合并有序子数组;堆排序通过构建堆来排序,保持堆性质并交换堆顶元素。每种算法各有优劣:快排平均高效,最坏O(n²);归并稳定O(n log n)但需额外空间;堆排序O(n log n)且原地排序,但不稳定。
30 3
|
1月前
|
算法 搜索推荐 C#
|
2月前
|
搜索推荐 C语言
【C/排序算法】:快速排序和归并排序的非递归实现
【C/排序算法】:快速排序和归并排序的非递归实现
17 0
|
2月前
|
搜索推荐 算法
【C/排序算法】:归并排序和计数排序
【C/排序算法】:归并排序和计数排序
20 0
|
2月前
|
机器学习/深度学习 搜索推荐 算法
【C/排序算法】:快速排序和冒泡排序
【C/排序算法】:快速排序和冒泡排序
24 0