排序算法中有稳定排序和不稳定排序之分,当相同的元素在排序之后仍保持之前的顺序则是稳定排序。常见的排序算法的时间复杂度为O(n2)、O(nlogn)和线性的。本片文章中,我们先来介绍一下常用的时间复杂度为O(n2)的排序算法

冒泡排序

冒泡排序是最常见的排序算法之一,排序方式简单粗暴。切冒泡排序是一种稳定的排序方式。
冒泡排序将元素两两比较,将较大的一个后移。
在这里插入图片描述
冒泡排序实现的方式多种多样,主要思想就是其中的data[n], data[n+1] = data[n+1], data[n]以及两次循环。

def bubbling(data):
    loop = len(data)
    while loop > 0:
        loop -= 1
        n = 0
        while n < loop:
            if data[n] > data[n+1]:
                data[n], data[n+1] = data[n+1], data[n]
            n += 1

冒泡算法虽然简单粗暴,但是有很多不足之处,比如:

  1. 上述图示中,当第一轮比较完成之后,后三位数以及成为有序排列,但是之后还是将其再次对比
  2. 而且当列表中在循环还未结束前就已经完成排序,但循环还是会继续下去不会停止。
    优化思路:
  3. 第一个问题的原因主要出现在有序区的定义上,我们可以将每次元素交换的位置将其记录,并将最后一次交换位置的地方设为有序区的边界。
  4. 问题二则只需记录循环是否有元素交换,如果没有元素交换则跳出循环即可解决。
# 经过优化的冒泡排序
def bubble(data):
    # 获得列表尾部位置
    loop = len(data) - 1
    while loop > 0:
        # change(改变):用来判断本次循环是否有所改变
        change = True
        n = 0
        while n < loop:
            if data[n] > data[n+1]:
                data[n], data[n+1] = data[n+1], data[n]
                record = n
                change = False
            n += 1
        # 判断是否已经完成循环可以跳出
        if change:
            break
        # 每次循环后将尾部移动到最后一次交换的位置
        loop = record

鸡尾酒排序

鸡尾酒排序可以算作为冒泡排序的一种变种和优化,在冒泡排序中,我们进行元素比较都是单向的,元素会根据自身大小一点一点向一侧移动,而鸡尾酒排序的不同之处就是将这种单向排序优化成双向排序,当冒泡排序在正方向上循环一次后,会在逆方向上再次比较循环。在一些特殊的情况下大幅度减少计算量,比如在2,3,4,5,6,7,8,1中,我们使用冒泡排序,大循环将要循环9次,但是鸡尾酒排序大循环只需循环两次。鸡尾酒排序在一组数据只有个别数据需要排序时非常实用。鸡尾酒排序只需在大循环中加入反向循环即可。
在这里插入图片描述

# 鸡尾酒排序
def bubble(data):
    # 获得列表尾部位置
    loop = len(data) - 1
    while loop > 0:
        # change(改变):用来判断本次循环是否有所改变
        change = True
        # n用来记录当前指向的列表元素位置
        n = 0
        # 正向循环
        while n < loop:
            if data[n] > data[n + 1]:
                data[n], data[n + 1] = data[n + 1], data[n]
                record = n
                change = False
            n += 1
        # 判断是否已经完成循环可以跳出
        if change:
            break
        # 反向循环
        while loop > 0:
            if data[loop] < data[loop - 1]:
                data[loop], data[loop - 1] = data[loop - 1], data[loop]
            loop -= 1
        # 每次循环后将尾部移动到最后一次交换的位置
        loop = record

选择排序

选择排序同样也是一种简单直接的排序方法,选择排序是一种完全依靠交互进行排序的算法,使用选择排序的时候我们同样会将列表分为有序区和无序区,同时我们需要找到本次循环中出现的最小值,然后将其放入有序区尾部。在这里插入图片描述

# 选择排序
# 方法1
def selection(data):
    # 记录有序区位置
    n = 0
    while n < len(data):
        # 找最小值
        i = n
        # 初始化最小值
        mix = i
        while i < len(data):
            if data[mix] > data[i]:
                # 记录最小值位置
                mix = i
            i += 1
        data[n], data[mix] = data[mix], data[n]
        n += 1
# 方法二        
def selection_sort(li):
    """选择排序"""
    n = len(li)
    for i in range(n-1): # 0-7
        # 记录最小位置
        min_index = i
        for j in range(min_index, n):
            # print(min_index)
            if li[j] < li[min_index]:
                min_index = j
        li[i], li[min_index] = li[min_index], li[i]

selection_sort(li)
print(li)

插入排序

插入排序同样是将序列分为有序区和无序区,每次在有序区中添加添加一个元素进行排序。在这里插入图片描述

def insertion(data):
    # 记录有序区位置
    n = 1
    # 取到的新元素
    i = n
    while n < len(data):
        while i > 0:
            if data[i] < data[i-1]:
                data[i], data[i-1] = data[i-1], data[i]
            i -= 1
        n += 1
        i = n

希尔排序

希尔排序是在插入排序的基础上改进的一种排序,相对于普通的插入排序更加的高效。希尔排序是把记录按下标的一定增量分量,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
在这里插入图片描述
通俗的解释希尔排序就是将一组数字分成数组长度相同小组,在对比每个小组对应角标的元素将其排序,然后缩小分组的长度,直到每个元素都成为一组为止。的从上图可以看出整个排序过程进行了四次替换,相对于插入排序有一定的优化。

def shell_sort(data):
    # 选择希尔排序默认步长
    gap = len(data) // 2
    # 判断步长是否足够
    while gap > 0:
        # 指向每列元素
        i = gap
        # 步长所对应的每列元素进行排序
        # 判断是否已经指向末尾
        while i < len(data):
            while data[i] < data[i-gap] and i > 0:
                data[i], data[i-gap] = data[i-gap], data[i]
                i -= 1
            print(i)
            i += 1

        gap = gap // 2