排序算法

本文总结数据结构中的几大排序算法,从原理、复杂度、稳定性和代码来逐步阐述。
首先明确一个概念:
稳定性:如果一个排序算法是稳定的,当有两个相等键值的记录S和R,且在原本的列表中R是出现在S之前,则在排序过后的列表中R也将会是在S之前。

一、冒泡排序

原理:对于列表任意相邻的两个元素进行比较,若前一个大于后一个,则两者进行交换,否则不交换。一趟冒泡下来,最大元素处在最后位置上,然后对前(n-1)个元素进行类似的操作,重复此过程,直到列表成为有序为止。
总共需要(n-1)次冒泡,第k次冒泡需要的比较次数为(n-k)
最优时间复杂度为:O(n)
最坏时间复杂度为:O(n^2)
稳定性:稳定

def bubble_sort(a_list):
    for j in range(len(a_list) - 1, 0, -1):  # 冒泡n-1次,每次两两进行比较
        for i in range(j):
            if a_list[i] > a_list[i + 1]:
                a_list[i], a_list[i + 1] = a_list[i + 1], a_list[i]
二、选择排序

原理:在未排序列中找最大元素,将其放到序列末尾,然后在从余下元素中继续寻找在大元素,将其移到末尾,以此类推,直到所有元素排完。
n个元素进行排序总共进行最多(n-1)次交换。
如果某元素位于正确的最终位置,则它不会被移动。
在多有依靠交换移动元素的排序方法中,选择排序属于非常好的一种。
最优时间复杂度:O(n^2)
最坏时间复杂度为:O(n^2)
空间复杂度:O(1)
稳定性:不稳定

def select_sort(a_list):
  for i in range(len(a_list) - 1, 0, -1):  # 最多进行n-1次交换
      max_index = i  # 假设末尾是最大元素
      for j in range(i):  # 在末尾以前的所有元素中选择最大元素,将其下标赋给j
          if a_list[j] > a_list[max_index]:
              max_index = j
      if max_index != i:  # 若最大元素不是最后一个,则和最大元素进行交换
          a_list[i], a_list[max_index] = a_list[max_index], a_list[i]
三、插入排序

原理:对于未排序数据,从第一个位置起,在已排序序列中从后向前扫描,找到相应位置并插入。
最优时间复杂度为:O(n)
最坏时间复杂度为:O(n^2)
稳定性:稳定

def insert_sort(a_list):
    for i in range(1, len(a_list)):
        for j in range(i, 0, -1):  # 从后往前进行比较
            if a_list[j] < a_list[j - 1]:  # 若小于前面的,则进行交换
                a_list[j], a_list[j - 1] = a_list[j - 1], a_list[j]
四、快速排序

原理:一趟排序将数据分割成独立的两部分,一部分的所有数据都比另外的一部分所有数据都小,按此方法对这两部分递归快速排序,以此达到整个数据成为有序序列。
具体操作:应用两个游标i和j,找一个基准(一般选第一个数据,i=0),从右往左找小于基准的值j,将其放在i的位置,然后从左往右找大于基准的值i,将其放在j的位置。直到i>=j为止,将基准赋给第i个位置,然后对基准的左右两部分进行快速排序递归,直到整个序列有序。
最优时间复杂度为:O(nlogn)
最坏时间复杂度为:O(n^2)
空间复杂度:O(nlogn)
稳定性:不稳定

def quick_sort(a_list, start, end):
    if start >= end:  # 递归结束标志
        return
    mid = a_list[start]  # 将开始数据作为基准
    low = start
    high = end
    while low < high:
        while low < high and a_list[high] >= mid:  # 大于基准前移
            high -= 1
        a_list[low] = a_list[high]  # 小于基准元素放在左指针位置
        while low < high and a_list[low] < mid:  # 小于基准后移
            low += 1
        a_list[high] = a_list[low]  # 大于基准元素放在右指针位置
    a_list[low] = mid  # 基准放在中间位置
    quick_sort(a_list, start, low - 1)  # 递归左
    quick_sort(a_list, low + 1, end)  # 递归右
五、希尔排序

原理:把数组按下标的一定增量分组,对每组使用直接插入算法排序,逐渐减少增量至1时,整个数组完成排序。
最优时间复杂度为:根据增量不同而不同
最坏时间复杂度为:O(n^2)
稳定性:不稳定

def shell_sort(alist):
    n = len(alist)
    # 初始步长
    gap = n // 2
    while gap > 0:
        # 按步长进行插入排序
        for i in range(gap, n):
            j = i
            # 插入排序
            while j >= gap and alist[j - gap] > alist[j]:
                alist[j - gap], alist[j] = alist[j], alist[j - gap]
                j -= gap
        # 得到新的步长
        gap = gap // 2
六、归并排序

原理:比较两个数组最前面的数,谁小先取谁,取后相应的指针往后移一位,再比较,直到一个数组为空,最后把另一个数组余下的复制过来即可。
最优时间复杂度为:O(nlogn)
最坏时间复杂度为:O(nlogn)
空间复杂度:O(n)
稳定性:稳定

def merge_sort(a_list):
    if len(a_list) <= 1:  # 递归结束条件
        return a_list
    # 二分分解
    num = len(a_list) // 2
    left = merge_sort(a_list[:num])  # 左递归
    right = merge_sort(a_list[num:])  # 右递归
    return merge(left, right)


# 按从小到大合并两个列表
def merge(left, right):
    l, r = 0, 0
    ans = []
    while l < len(left) and r < len(right):
        if left[l] < right[r]:
            ans.append(left[l])
            l += 1
        else:
            ans.append(right[r])
            r += 1
    ans += left[l:]
    ans += right[r:]
    return ans
参考来源:
未完、待续……
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值