zoukankan      html  css  js  c++  java
  • 常见排序算法之python实现

    1. 冒泡排序

    时间复杂度为O(n^2), 稳定的排序算法

    思路:一开始比较的区间是【0,n-1】,依次比较相邻两数,哪个数大哪个数就放在后面,这样一次遍历数组后,最大的数会在数组的最后一个位置,然后比较区间从【0,n-1】缩小到了【0,n-2】,在进行一次遍历下来,第二大的数会被放在数组倒数第二的位置,依次类推。直到把范围缩小到一个数的时候,数组就有序了。

    def bubbleSort(arr):
        
      length
    = len(arr) for i in range(length-1): #趟数 for j in range(length-i-1): #每趟元素数 if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr

     2. 选择排序

    时间复杂度为O(n^2),不稳定的排序算法

    思路:一开始从【0,n-1】选出一个最小值放在位置0上;第二次从【1,n-1】上选择一个最小值放在位置1上;依次类推;直到数组访问剩下一个元素时,数组有序了。

    def selectionSort(arr):
        """选择排序
        """
        length = len(arr)
    
        for i in range(length):
            min_i = i # 最小值索引
            for j in range(i, length):
                if arr[min_i] > arr[j]:
                    min_i = j
    
            arr[min_i], arr[i] = arr[i], arr[min_i]
    
        return arr

    3. 插入排序*

    时间复杂度为O(n^2),稳定的排序算法

    :当数组几乎有序的情况下,时间复杂度为O(n*k),k为最多移动的距离;当数组逆序时,时间复杂度最大为O(n^2)

    思路:把n个待排序的元素看成是一个有序表和一个无序表,开始时有序表只有一个元素,无序表有n-1个元素。排序过程中每次从无序表中取出一个元素,把它的排序码依次与有序表中元素比较(后->前),将它插入有序表的适当位置,使之成为新的有序表。

    def insertSort(arr):
        """插入排序
        """
        length = len(arr)
    
        for i in range(length-1):
            o_i = i # 有序表最后一个元素索引
            u_v = arr[o_i+1] # 无序表的元素值
            
            while o_i >= 0 and arr[o_i] > u_v:
                arr[o_i+1] = arr[o_i]
                o_i -= 1
            arr[o_i+1] = u_v # 带插入元素合适位置,+1是因为前面-1
    
        return arr

    4. 归并排序*

    时间复杂度为O(nlogn),稳定的排序算法

    思路:首先让数组每一个元素成为长度为1的有序区间;然后将两个长度为1的有序区间进行合并,生成长度为2的有序区间;然后再将两个长度为2的有序区间进行合并,生成长度为4的有序区间;依次类推,直至数组有序。1合2,2合4,4合8,8合16,……

    def mergerSort(arr):
        """归并排序
    
            划分成左右两部分; 两两合并,成有序数组
        """
        if len(arr) <= 1:
            return arr
    
        mid = len(arr) // 2
        # 左右划分, 生成长度为1的有序数组时开始返回
        leftArr = mergerSort(arr[:mid])
        rightArr = mergerSort(arr[mid:])
        # 两两合并
        return merger(leftArr, rightArr)
    
    def merger(left, right):
        """合并两个有序数组,形成新的有序数组返回
        """
        res = []
        l, r = 0, 0
        while l < len(left) and r < len(right):
            if left[l] <= right[r]:
                res.append(left[l])
                l += 1
            else:
                res.append(right[r])
                r += 1
    
        res += left[l:]
        res += right[r:]
        return res

    5. 快速排序**

    时间复杂度为O(nlogn), 不稳定的排序算法

    :在数组完全无序的情况下,快排效果最好,为O(nlogn);在有序情况下效果最差,为O(n^2)。

    思路:随机排序 - 在数组中随机选择一个数,使得数组中大于它的数放在它的右边、小于等于它的数放在它的左边,然后左右两边的数递归的调用快排的过程。

    快排的一次划分过程  -  时间复杂度为O(n):

      首先,我们随机选择数组中的一个作为划分值;然后把划分值与数组的最后一个元素进行交换,使得划分值放到数组的最后一个位置(如b);然后我们定义一个小于等于区间,初始时,小于等于区间为空,放在数组的最左边(如c);然后开始遍历数组,如果元素大于划分值,继续遍历下一个元素,如果元素值小于等于划分值,就让该元素与小于等于区间的下一个元素进行交换,扩增小于等于区间(如d,e);依次执行这个过程,直到数组中只剩一个数;然后数组最后一个数(划分值)与小于等于区间的下一个数进行交换,快排的一次划分过程就结束了(如f,g)。

         

    def quickSort(arr, left, right):
        """快速排序
    
            对left到right区间上的数组进行快排
        """
        if left >= right:
            return None
    
        midValue = arr[(left+right)//2] # 划分值
        l, r = left, right
        while l < r:
            while arr[l] < midValue: l += 1
            while arr[r] > midValue: r -= 1
    
            if l >= r: break
    
            arr[l], arr[r] = arr[r], arr[l]
            r -= 1
            l += 1
    
        if l == r:
            l += 1
            r -= 1
    
        if left < r: quickSort(arr, left, r)
        if right > l: quickSort(arr, l, right)
    
        return None

     6. 堆排序*

    时间复杂度:O(nlogn),不稳定的排序算法,常用于查找top x

    思路:首先将数组【0,n-1】区间上的所有元素构建大根堆,然后将堆顶元素与数组最后一个元素进行交换,这样数组最后一个元素为最大值,作为数组有序部分存在下来;然后将数组【0,n-2】区间上的所有元素构建大根堆,然后执行堆顶元素与数组的倒数第二个元素进行交换,这样数组后两位元素分别是数组的最大值和第二大的值存在下来;然后将数组区间【0,n-3】区间构建大根堆,交换;重复以上过程直到数组有序。

    def heapSort(arr):
        """堆排序
        """
        arr = buildMaxHeap(arr)
    
        for i in list(range(len(arr)))[::-1]:
            arr[0], arr[i] = arr[i], arr[0]
            adjustHeap(arr, 0, i) # n表示数组的大小(不是堆)
    
        return arr
    
    def buildMaxHeap(arr):
        """建立大根堆
    
            从下向上构建
        """
        for i in list(range(len(arr)//2))[::-1]:
            adjustHeap(arr, i, len(arr))
    
        return arr
    
    def adjustHeap(arr, start, size):
        """将数组[start:]调整成堆结构
    
            参数
            ---
                start: int
                    数组起始index
                size:int
                    数组大小
        """
        lChild = 2 * start + 1
        rChild = 2 * start + 2
    
        maxi = start
    
        if maxi < size//2: # 说明有孩子
            if lChild < size and arr[lChild] > arr[maxi]:
                maxi = lChild
            if rChild < size and arr[rChild] > arr[maxi]:
                maxi = rChild
    
            if maxi != start: # == 说明已经是最大堆了,所以这里不是
                arr[maxi], arr[start] = arr[start], arr[maxi]
                adjustHeap(arr, maxi, size)

     7. 希尔排序

    时间复杂度为O(nlogn),不稳定的排序算法

    思路:希尔排序是插入排序的改良,希尔排序相比于插入排序区别在于步长是逐步调整的,也就是希尔排序在执行完指定步长的插入排序后,逐渐调整步长,直至执行步长为1的插入排序为止。一般来说,初始步长gap=length/2,然后不断以gap=gap/2减小步长,直至降为1。希尔排序的成败和步长的选取相关,步长选取越优时间复杂度越低,步长选取越劣时间复杂度越是接近O(n^2)。

    def shellSort(arr):
        """希尔排序
    
            使用希尔增量
        """
        n = len(arr)
        gap = n // 2 # 初始化步长
        while gap >= 1:
            for i in range(gap, n):
                index = i
                while index >= gap:
                    if arr[index-gap] > arr[index]:
                        arr[index-gap], arr[index] = arr[index], arr[index-gap]
                        index -= gap
                    else:
                        break
    
            gap //= 2 # 缩减步长
        return arr
  • 相关阅读:
    c语言判断最大数
    c语言复制字符
    C语言简单小问题
    c语言实现用指针遍历二维数组
    C语言有趣小程序
    C语言实现输入一个数,输出这个数的立方根
    C语言实现输入一个数,输出这个数的sin值
    c语言实现输出10000内所有素数,5个换一行
    输出10000内所有素数
    判断素数
  • 原文地址:https://www.cnblogs.com/lianyingteng/p/7729462.html
Copyright © 2011-2022 走看看