用Python实现十大经典排序算法

在这里插入图片描述

插入排序

思路

  1. 从第一个元素开始,该元素可以认为已经被排序;
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  3. 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
  5. 将新元素插入到该位置;
  6. 重复步骤2~5。

代码

def insertSort(arr):
    length = len(arr)
    for i in range(length-1):
        for j in range(length-1-i):
            if arr[j] > arr[j+1]:
                temp = arr[j+1]
                arr[j+1] = arr[j]
                arr[j] = temp
    return arr

图示

图片不见啦

平均时间复杂度

O(n^2)

希尔排序

前言

希尔排序是插排的升级,先将待排序的元素进行分组,在分组的基础上进行插排,从而降低整体上的时间复杂度。
这里面设计到一个增量的概念,我们依据增量来决定分组的跨度。常用的增量有三种:

  1. 希尔增量 [1,2,4,8,…,2^(k-1)]
  2. 海巴德增量 [1,3,7,15,…,2^k-1]
  3. 塞基维克增量 [1,5,19,41,…,4k-3*2k+1]

一般情况下希尔增量带来的时间复杂度小于O(n2)*,但在极坏情况下可能效果不明显甚至超过这个值。海巴德增量可以将时间复杂控制在*O(n(3/2))以下,而塞基维克增量该项参数为O(n^(4/3))

思路

  1. 择定增量
  2. 分组
  3. 组内比较
  4. 重复步骤2,3直到跨度为1

图示

在这里插入图片描述

代码

def shellSort(arr):
    length=len(arr)
    gap=int(length/2)
    while gap>0:
        for i in range(gap,length):
            j=i
            current=arr[i]
            while(j-gap>=0 and current<arr[j-gap]):
                arr[j]=arr[j-gap]
                j=j-gap
            arr[j]=current
        gap=int(gap/2)
    return arr

选择排序

思路

  1. 选出数组中最大(最小)的元素放到开头
  2. 在剩下的元素中选中最大(最小)元素放到上个被选元素之后
  3. 重复2步骤

图示

图片不见啦

代码

def selectSort(arr):
    length = len(arr)
    minIndex, temp = 0, ""
    for i in range(length-1):
        minIndex = i
        for j in range(i+1, length):
            if arr[j] < arr[minIndex]:
                minIndex = j
        temp = arr[i]
        arr[i] = arr[minIndex]
        arr[minIndex] = temp
    return arr

平均时间复杂度

O(2^n)

堆排序

前言

堆排序,顾名思义,就是基于堆。因此先来介绍一下堆的概念。
堆分为最大堆和最小堆,其实就是完全二叉树。最大堆要求节点的元素都要大于其孩子,最小堆要求节点元素都小于其左右孩子,两者对左右孩子的大小关系不做任何要求,其实很好理解。有了上面的定义,我们可以得知,处于最大堆的根节点的元素一定是这个堆中的最大值。其实我们的堆排序算法就是抓住了堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。

思路

  1. 把堆顶的最大数取出
  2. 将剩余的堆继续调整为最大堆
  3. 重复步骤1,2

图示

图片不见啦

代码

from collections import deque


def swap(L, i, j):
    L[i], L[j] = L[j], L[i]
    return L

def heap(L, start, end):
    temp = L[start]
    i = start
    j = 2 * i
    while j <= end:
        if (j < end) and (L[j] < L[j + 1]):
            j += 1
        if temp < L[j]:
            L[i] = L[j]
            i = j
            j = 2 * i
        else:
            break
    L[i] = temp

def sort(L):
    L_length = len(L) - 1
    first_sort_count = int(L_length / 2)
    for i in range(first_sort_count):
        heap(L, first_sort_count - i, L_length)
    for i in range(L_length - 1):
        L = swap(L, 1, L_length - i)
        heap(L, 1, L_length - i - 1)
    return [L[i] for i in range(1, len(L))]

def heapSort(nums):
    L = deque(nums)
    L.appendleft(0)
    return sort(L)

平均时间复杂度

O(n)

冒泡排序

思路

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

图示

在这里插入图片描述

代码

def bubbleSort(arr):
    length=len(arr)
    for i in range(length-1):
        for j in range(length-1-i):
            if arr[j]>arr[j+1]:
                temp=arr[j+1]
                arr[j+1]=arr[j]
                arr[j]=temp
    return arr

平均时间复杂度

O(n^2)

快速排序

思路

  1. 先从集合中取出一个数作为“哨兵”
  2. 将集合中比哨兵大的元素和比哨兵小的元素分列两侧
  3. 再对左右区间重复第二步,直到各区间只有一个数

图示

在这里插入图片描述

代码

def quickSort(nums):
    return qSort(nums, 0, len(nums) - 1)

def qSort(nums, left, right):
    if left < right:
        pivot = partition(nums, left, right)
        qSort(nums, left, pivot - 1)
        qSort(nums, pivot + 1, right)
    return nums

def partition(nums, left, right):
    pivotkey = nums[left]
    while left < right:
        while left < right and nums[right] >= pivotkey:
            right -= 1
        nums[left] = nums[right]
        while left < right and nums[left] <= pivotkey:
            left += 1
        nums[right] = nums[left]
    nums[left] = pivotkey
    return left

平均时间复杂度

O(nlogn)

归并排序

思路

  1. 将列表拆分成两个有序子模块
  2. 递归拆分
  3. 子模块内部进行排序并合并成大的模块
  4. 递归合并

图示

在这里插入图片描述

代码

def mergeSort(elements):
    if len(elements) <= 1:  # 子序列
        return elements
    mid = int(len(elements) / 2)
    left = mergeSort(elements[:mid])  # 递归的切片操作
    right = mergeSort(elements[mid:len(elements)])
    result = []
    while len(left) > 0 and len(right) > 0:
        if (left[0] <= right[0]):
            result.append(left.pop(0))
        else:
            result.append(right.pop(0))
    if (len(left) > 0):
        result.extend(mergeSort(left))
    else:
        result.extend(mergeSort(right))
    return result

平均时间复杂度

O(nlogn)

计数排序

思路

  1. 找出集合中最小数m和最大数n
  2. 建一个长为(m-n+1)的列表count_list,所有元素初始化为0
  3. 遍历集合,元素减去n得到的结果作为index,将count_list该位上的元素加1。
  4. 初始化空列表result。
  5. 将count_list序列化,用索引值减去n,得到的结果追加到result中,索引值对应的位元素值减1,直到它为0。
  6. 重复步骤5。

图示

在这里插入图片描述

代码

def countSort(nums):
    min_num = min(nums)
    max_num = max(nums)
    count_list = [0]*(max_num-min_num+1)
    for i in nums:
        count_list[i-min_num] += 1
    result=[]
    for ind,i in enumerate(count_list):
        while i != 0:
            result.append(ind + min_num)
            i -= 1
    return result

平均时间复杂度

O(n)

桶排序

前言

桶排序是将待排序集合中处于同一个值域的元素存入同一个桶中,也就是根据元素值特性将集合拆分为多个区域,则拆分后形成的多个桶,从值域上看是处于有序状态的。对每个桶中元素进行排序,则所有桶中元素构成的集合是已排序的。

思路

  1. 根据待排序集合中最大元素和最小元素的差值范围和映射规则,确定申请的桶个数;
  2. 遍历待排序集合,将每一个元素移动到对应的桶中;
  3. 对每一个桶中元素进行排序,并移动到已排序集合中。

图示

图片不见啦

代码

def bucketSort(elements):
    mex_element = max(elements)
    bucket = [0]*(mex_element+1)
    for i in elements:
      bucket[i] += 1
    result = []
    for j in range(len(bucket)):
      if bucket[j] != 0:
        for count in range(bucket[j]):
          result.append(j)
    return result

平均时间复杂度

O(n^2)

基数排序

思路

  1. 首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶中;
  2. 接下来将这些桶中的数值重新串接起来,成为以下的数列。接着再进行一次分配,这次是根据十位数来分配;
  3. 接下来将这些桶中的数值重新串接起来,持续进行以上的动作直至最高位数为止。

图示

图片不见啦

代码

def RadixSort(arr):
    begin = 0               
    min_num = 1             
    max_num = max(arr)      
    while max_num > 10**min_num:
        min_num += 1
    while begin < min_num:
        bucket = {}             
        for x in range(10):
            bucket.setdefault(x, [])
        for x in arr:               
            radix =int((x / (10**begin)) % 10)
            bucket[radix].append(x) 
        j = 0
        for k in range(10):
            if len(bucket[k]) != 0: 
                for y in bucket[k]: 
                    arr[j] = y      
                    j += 1
        begin += 1
    return arr

平均时间复杂度

O(d2n)
这里的d是数值位数

猜你喜欢

转载自blog.csdn.net/qq_42229092/article/details/105163133