zoukankan      html  css  js  c++  java
  • python数据结构与算法篇:排序

    1.冒泡排序(英语:Bubble Sort)

    它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

    冒泡排序算法的运作如下:

    • 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
    • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
    • 针对所有的元素重复以上的步骤,除了最后一个。
    • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

    首先,列表每两个相邻的数,如果前边的比后边的大,那么交换这两个数……

    def bubble_sort(alist):
        for j in range(len(alist)-1,0,-1):
            # j表示每次遍历需要比较的次数,是逐渐减小的
            for i in range(j):
                if alist[i] > alist[i+1]:
                    alist[i], alist[i+1] = alist[i+1], alist[i]

    时间复杂度

    • 最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。)
    • 最坏时间复杂度:O(n2)两个for循环
    • 稳定性:稳定

    2.选择排序(Selection sort)

    首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

    选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,它们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换。在所有的完全依靠交换去移动元素的排序方法中,选择排序属于非常好的一种。

    def selection_sort(alist):
        n = len(alist)
        # 需要进行n-1次选择操作
        for i in range(n-1):
            # 记录最小位置
            min_index = i
            # 从i+1位置到末尾选择出最小数据
            for j in range(i+1, n):
                if alist[j] < alist[min_index]:
                    min_index = j
            # 如果选择出的数据不在正确位置,进行交换
            if min_index != i:
                alist[i], alist[min_index] = alist[min_index], alist[i]
    
    alist = [54,226,93,17,77,31,44,55,20]
    selection_sort(alist)
    print(alist)

    时间复杂度

    • 最优时间复杂度:O(n2)
    • 最坏时间复杂度:O(n2)
    • 稳定性:不稳定(考虑升序每次选择最大的情况)

    3.插入排序(英语:Insertion Sort)

    列表被分为有序区和无序区两个部分。最初有序区只有一个元素。

    每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空。

    原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

    def insert_sort(li):
        # 从第二个位置,即下标为1的元素开始向前插入
        for i in range(1, len(li)):
            tmp = li[i]
            j = i - 1
            while j >= 0 and li[j] > tmp:
                li[j+1]=li[j]
                j = j - 1
            li[j + 1] = tmp

    时间复杂度

    • 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
    • 最坏时间复杂度:O(n2)
    • 稳定性:稳定

    4.快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort)

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

    步骤为:

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

    递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

    快排思路:

    取一个元素p(第一个元素),使元素p归位;

    列表被p分成两部分,左边都比p小,右边都比p大;

    递归完成排序。

    def qsort_rec(li,l,r):
        if l>=r:
            return
        i=l
        j=r
        pivot=li[i]
        while i<j:
            while i<j and li[j]>=pivot:
                j-=1
            if i<j:
                li[i]=li[j]
                i+=1
            while i<j and li[i]<=pivot:
                i=i+1
            if i<j:
                li[j]=li[i]
                j-=1
        li[i]=pivot
        qsort_rec(li,l,i-1)
        qsort_rec(li,i+1,r)
    
    @cal_time
    def quick_sort2(li):
        qsort_rec(li,0,len(li)-1)

    时间复杂度

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

    5.希尔排序

    希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

    首先取一个整数d1=n/2,将元素分为d1个组,每组相邻量元素之间距离为d1,在各组内进行直接插入排序;

    取第二个整数d2=d1/2,重复上述分组排序过程,直到di=1,即所有元素在同一组内进行直接插入排序。

    希尔排序每趟并不使某些元素有序,而是使整体数据越来越接近有序;最后一趟排序使得所有数据有序。

    def shell_sort(li):
        gap = int(len(li) // 2)
        while gap >= 1:
            for i in range(gap, len(li)):
                tmp = li[i]
                j = i - gap
                while j >= 0 and tmp < li[j]:
                    li[j + gap] = li[j]
                    j -= gap
                li[i - gap] = tmp
            gap = gap // 2
    • 最优时间复杂度:根据步长序列的不同而不同
    • 最坏时间复杂度:O(n2)
    • 稳定想:不稳定
  • 相关阅读:
    LeetCode 81 Search in Rotated Sorted Array II(循环有序数组中的查找问题)
    LeetCode 80 Remove Duplicates from Sorted Array II(移除数组中出现两次以上的元素)
    LeetCode 79 Word Search(单词查找)
    LeetCode 78 Subsets (所有子集)
    LeetCode 77 Combinations(排列组合)
    LeetCode 50 Pow(x, n) (实现幂运算)
    LeetCode 49 Group Anagrams(字符串分组)
    LeetCode 48 Rotate Image(2D图像旋转问题)
    LeetCode 47 Permutations II(全排列)
    LeetCode 46 Permutations(全排列问题)
  • 原文地址:https://www.cnblogs.com/ningxin18/p/7889296.html
Copyright © 2011-2022 走看看