zoukankan      html  css  js  c++  java
  • 算法 ----- 快速排序

    快速排序 quick sort

    介绍:
      快速排序(Quicksort)是对冒泡排序的一种改进。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性。

    原理:

      通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列,最终完成整个数据排序的目的。 值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。

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

      注:在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的;若具有相同关键字的记录之间的相对次序发生改变,则称这种排序方法是不稳定的。要注意的是,排序算法的稳定性是针对所有输入实例而言的。即在所有可能的输入实例中,只要有一个实例使得算法不满足稳定性要求,则该排序算法就是不稳定的。 

    革新点:先从后扫描(比基准值)小的,再从前扫描(比基准值)大的!

    快速排序动画演示:

    算法实现:

    import random as rd
    import time
    import sys
    
    sys.setrecursionlimit(100000)
    
    def cal_time(func):
        """
    	装饰器打印执行时间
    	"""
    	def wrapper(*args, **kwargs):
            t1 = time.time()
            x = func(*args, **kwargs)
            t2 = time.time()
            print("%s running time %s secs." % (func.__name__, t2 - t1))
            return x
    		
        return wrapper
    
    def partition(data, left, right):
        """
    	区内数据排序处理
    	快速排序的核心代码。
    	其实就是将选取的tmp不断交换,将比它小的换到左边,将比它大的换到右边。
    	它自己也在交换中不断变换自己的位置,直到完成所有的交换为止。
    	但在函数调用的过程中,pivot_key的值始终不变。
    	:param low:左边界索引
    	:param high:右边界索引
    	:return:分完左右区后tmp所在位置的索引
    	"""
    	tmp = data[left]
        while left < right:
            while left < right and data[right]>=tmp:
                right-=1
            data[left]=data[right]
            while left < right and data[left]<=tmp:
                left+=1
            data[right]=data[left]
        data[left]=tmp
        return left
    	
    def _quick_sort(data, left, right):
    	"""
    	递归调用
    	"""
        if left < right:
            mid = partition(data, left, right)
            _quick_sort(data, left, mid - 1)
            _quick_sort(data, mid + 1, right)
    
    @cal_time
    def quick_sort(data):
    	"""
    	调用入口
    	"""
        return _quick_sort(data, 0, len(data)-1)
    	
    li = list(range(100000))
    rd.shuffle(li)
    quick_sort(li)	
    

      

    总结:

    • 快速排序的时间性能取决于递归的深度。
    • 当tmp恰好处于记录关键码的中间值时,大小两区的划分比较均衡,接近一个平衡二叉树,此时的时间复杂度为O(nlog(n))。
    • 当原记录集合是一个正序或逆序的情况下,分区的结果就是一棵斜树,其深度为n-1,每一次执行大小分区,都要使用n-i次比较,其最终时间复杂度为O(n^2)。
    • 在一般情况下,通过数学归纳法可证明,快速排序的时间复杂度为O(nlog(n))。
    • 但是由于关键字的比较和交换是跳跃式的,因此,快速排序是一种不稳定排序。
    • 同时由于采用的递归技术,该算法需要一定的辅助空间,其空间复杂度为O(logn)。
  • 相关阅读:
    matplotlib绘制常见统计图
    学习进度(14)
    hive的基本用法(2)
    hive的基本用法(1)
    进度日报表10
    进度日报表09
    进度日报表08
    进度日报表07
    第六周总结
    进度日报表06
  • 原文地址:https://www.cnblogs.com/zh605929205/p/7468389.html
Copyright © 2011-2022 走看看