十大经典排序算法(python实现)

  • 知识站点
  • 时间复杂度
  • 1冒泡排序
  • 稳定性
  • 简介
  • 步骤
  • 可视化图
  • 代码实现
  • 2选择排序
  • 稳定性
  • 简介
  • 步骤
  • 可视化图
  • 代码实现
  • 3插入排序
  • 稳定性
  • 简介
  • 步骤
  • 可视化图
  • 代码实现
  • 4希尔排序
  • 稳定性
  • 简介
  • 可视化图
  • 代码实现
  • 5归并排序
  • 稳定性
  • 简介
  • 可视化图
  • 步骤
  • 代码实现
  • 6快速排序
  • 稳定性
  • 适用场景
  • 步骤
  • 可视化图
  • 代码实现


知识站点

时间复杂度

什么是时间复杂度呢?举个例子先让我们来想象一个场景:某一天,小黄和小蓝同时到一个公司应聘,他们分不出胜负。面试官给他们出了一道题目,保存员工编号。时间一到小黄和小蓝各自交付了代码,两端代码实现的功能都差不多。小黄的代码运行一次要花100豪秒,内存占用5MB。小蓝的代码运行一次要花100秒,内存占用500MB。
我,我们可知由此可见,衡量代码的好坏,有两个指标:
1.运行时间
2.占用空间
从现实的四件事来做比喻:
1,给小蓝一条长10寸的面包,小蓝每3天吃掉1寸,那么吃掉整个面包需要几天?
我们肯定会脱口而出:3 x 10 = 30(天)
如果面包的长度是 X 寸呢?
此时吃掉整个面包,需要 3 X n = 3n 天。
如果用一个函数来表达这个相对时间,可以记作 T(n)=3n。
2,给小蓝一条长16寸的面包,小蓝每5天吃掉面包剩余长度的一半,第一次吃掉8寸,第二次吃掉4寸,第三次吃掉2寸…那么小蓝把面包吃得只剩下1寸,需要多少天呢?
这个问题翻译一下,就是数字16不断地除以2,除几次以后的结果等于1?这里要涉及到数学当中的对数,以2位底,16的对数,可以简写为log(16)。
因此,把面包吃得只剩下1寸,需要 5 X log(16) = 5 X 4 = 20 天。
如果面包的长度是 N 寸呢?
需要 5 X logn =(5)logn天,记作 T(n)= (5)logn。
3,给蓝一条长10寸的面包和一个鸡腿,小蓝每2天吃掉一个鸡腿。那么小蓝吃掉整个鸡腿需要多少天呢?
答案自然是2天。因为只说是吃掉鸡腿,和10寸的面包没有关系 。
如果面包的长度是N寸呢?
无论面包有多长,吃掉鸡腿的时间仍然是2天,记作T(n)=2。
4,给小蓝一条长10寸的面包,小蓝吃掉第一个一寸需要1天时间,吃掉第二个一寸需要2天时间,吃掉第三个一寸需要3天时间…每多吃一寸,所花的时间也多一天。那
么小灰吃掉整个面包需要多少天呢?
答案是从1累加到10的总和,也就是55天。
如果面包的长度是 N 寸呢?
此时吃掉整个面包,需要 1+2+3+…+ n-1 + n = (1+n)*n/2 = 0.5n^2 + 0.5n。
记作T(n) = 0.5n^2 + 0.5n。
时间:
场景1:T(n) = 3n,执行次数是线性的。
场景2:T(n)= (5)logn,执行次数是对数的。
场景3:T(n)=2,执行次数是常量的。
场景4:T(n) = 0.5n^2 + 0.5n,执行次数是一个多项式。

1冒泡排序

稳定性

冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。
所以相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。

简介

冒泡排序是一种非常简单的排序方法。一直重复地检查数列直到顺序正确,每次检查都比较两个元素来经行对比,如果它前面比后面大就把它们交换,直到排序成功。

步骤

  1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个 的位置
  2. 对每一对相邻元素作同样的移动,从开始第一个到结尾的最后一个,这样在最后的元素是最大的数
  3. 对所有的元素重复1~2步骤,除了最后一个
  4. 重复步骤1~3,直到排序完成。

可视化图

python算法案例 python经典算法大全_python算法案例

代码实现

def bubble_sort(data):
    for j in range(len(data) + 1):
        for i in range(len(data) - (j + 1)):
            if data[i] > data[i + 1]:
                tmp = data[i + 1]
                data[i + 1] = data[i]
                data[i] = tmp
    print(data)

2选择排序

稳定性

选择排序稳定性不是很好,因为选择排序有一个弊端就是数字越多就有更大的可能

简介

从头至尾扫描数列,找出最小的一个元素,和第一个元素交换,接着从剩下的元素中继续这种选择和交换方式,最终得到一个有序数列

步骤

  1. 首先在未排序序列中找到最小(大)元素
  2. 存放到排序序列的起始位置
  3. 再从剩余未排序元素中继续寻找最小(大)元素
  4. 然后放到已排序序列的末尾
  5. 重复步骤1~3,直到排序完成

可视化图

python算法案例 python经典算法大全_python算法案例_02

代码实现

def quick_sort(ser):
    if len(ser) < 2:
        return
    p = ser[0]
    L = []
    E = []
    R = []
    while len(ser) > 0:
        if ser[-1] < p:
            L.append(ser.pop())
        elif ser[-1] == p:
            E.append(ser.pop())
        else:
            R.append(ser.pop())
    quick_sort(L)
    quick_sort(R)
    ser.extend(L)
    ser.extend(E)
    ser.extend(R)
if __name__ == '__main__':
    ser = [1, 7, 3, 5, 4]
    quick_sort(ser
    print(ser)

3插入排序

稳定性

插入排序的稳定性比较好因为碰见一个和插入元素相 等的,那么插入元素把想插入的元素放在相等元素的后面

简介

插入排序是一种很简单的排序算法,工作原理是通过创建有序数列,对于未排序数列,在已排序数列中从后向前扫描,找到相应位置并插入。

步骤

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

可视化图

python算法案例 python经典算法大全_python算法案例_03

代码实现

def insert_Sort(la):
    length = len(la)
    for i in range(1, length):
        x = la[i]
        for j in range(i, -1, -1):
            if x < la[j - 1]:
                la[j] = la[j - 1]
            else:
                break
        la[j] = x
    print(la)

4希尔排序

稳定性

由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

简介

是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。

可视化图

python算法案例 python经典算法大全_python算法案例_04

代码实现

def donald_shell(data):
    n = len(data)
    gap = n // 2
    while gap >= 1:
        for j in range(gap, n):
            while j - gap >= 0:
                if data[j] < data[j - gap]:
                    data[j], data[j - gap] = data[j - gap], data[j]
                    j -= gap
                else:
                    break
        gap //= 2
    print(data)

5归并排序

稳定性

因为我们在遇到相等的数据的时候必然是按顺序“抄写”到数组上的,所以,归并排序同样是稳定算法。

简介

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

可视化图

python算法案例 python经典算法大全_排序算法_05

步骤

  1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
  2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
  3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
  4. 重复步骤3直到某一指针到达序列尾
  5. 将另一序列剩下的所有元素直接复制到合并序列尾

代码实现

def merge(a, b):
    c = []
    h = j = 0
    while j < len(a) and h < len(b):
        if a[j] < b[h]:
            c.append(a[j])
            j += 1
        else:
            c.append(b[h])
            h += 1
    if j == len(a):
        for i in b[h:]:
            c.append(i)
    else:
        for i in a[j:]:
            c.append(i)
    return c
def merge_sort(lists):
    if len(lists) <= 1:
        return lists
    middle = len(lists) / 2
    left = merge_sort(lists[:middle])
    right = merge_sort(lists[middle:])
    return merge(left, right)

6快速排序

稳定性

快速排序并不是稳定的。这是因为我们无法保证相等的数据按顺序被扫描到和按顺序存放。

适用场景

快速排序在大多数情况下都是适用的,尤其在数据量大的时候性能优越性更加明显。但是在必要的时候,需要考虑下优化以提高其在最坏情况下的性能。

步骤

  1. 首先在未排序序列中找到最小(大)元素
  2. 存放到排序序列的起始位置
  3. 再从剩余未排序元素中继续寻找最小(大)元素
  4. 然后放到已排序序列的末尾
  5. 重复步骤1~3,直到排序完成

可视化图

python算法案例 python经典算法大全_代码实现_06

代码实现

def quick_sort(data):
    # 递归入口及出口
    if len(data) >= 2:
        # 选取基准值,也可以选取第一个或最后一个元素
        mid = data[0]
        # 定义基准值左右两侧的列表
        left, right = [], []
        # 从原始数组中移除基准值
        data.remove(mid)
       	#
        for num in data:
            if num >= mid:
                right.append(num)
            else:
                left.append(num)
        return quick_sort(left) + [mid] + quick_s

这是本人做的一些算法总结不喜勿喷