常见排序算法(冒泡排序、选择排序、插入排序、快速排序)

1.冒泡排序

冒泡排序(英语:Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。

"""
冒泡排序
"""
# 第一轮,依次取索引0和1、1和2,...,n-2和n-1两两比较,小的在前大的在后。一轮结束最大的在最后
# 第二轮,依次取索引0和1、1和2,...,n-3和n-2两两比较,小的在前大的在后。二轮结束次大的在倒数第二
# 第n-1轮,取索引0和1比,最小值放最前面


def bubble_sort(li):
    n = len(li)
    for i in range(0, n-1):
        for j in range(0, n-1-i):  # 每轮结束,已排序列增加,未排序列减少
            if li[j] > li[j+1]:
                li[j], li[j+1] = li[j+1], li[j]


li = [55, -2, 43, 91, 22, 1, 44, 90, 34]
bubble_sort(li)
print(li)

时间复杂度

  • 最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。)
  • 最坏时间复杂度:O(n2)
  • 稳定性:稳定

2.选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

"""
选择排序
"""
# 第一轮,假设min_index=0,从索引1开始往后依次取值与索引0处比较,小于索引0,则最小值索引位置设置为当前索引。
# 每轮比较结束,判断min_index是否改变,改变则交换这一轮中实际的min_index和初始的min_index的值。最小值在最前面。

# 第二轮,假设min_index=1,从索引2开始依次往后取值与1处比较,找到次小值。交换次小值与本轮初始min_index=1的位置

# 重复n-1轮。


def select_sort(li):
    n = len(li)

    for i in range(0, n-1):
        min_index = i

        for j in range(i+1, n):
            if li[j] < li[min_index]:
                min_index = j
        if min_index != i:
            li[min_index], li[i] = li[i], li[min_index]


li1 = [55, -2, 43, 91, 22, 1, 44, 90, 34]
select_sort(li1)
print(li1)

时间复杂度

  • 最优时间复杂度:O(n2)
  • 最坏时间复杂度:O(n2)
  • 稳定性:不稳定(考虑升序每次选择最大的情况)

3.插入排序

插入排序(英语:Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

"""
插入排序
"""
# 第一轮,假设索引0有序,则取索引1与0比较,大于不交换进行下一轮,小于则交换索引0和1

# 第二轮,假设索引0和1有序,则取索引2依次与索引1和索引0比,小于交换,大于进入下一轮

# 第n-1轮,假设0,1,...,n-2有序,取索引n-1依次与n-2,n-3,...,1,0比较,小于交换,大于结束


def insert_sort(li):
    n = len(li)
    for i in range(0, n-1):    # 循环比较n-1轮
        for j in range(i+1, 0, -1):
            if li[j] < li[j-1]:
                li[j], li[j-1] = li[j-1], li[j]
            else:
                break


li1 = [55, -2, 43, 91, 22, 1, 44, 90, 34]
insert_sort(li1)
print(li1)

时间复杂度

  • 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
  • 最坏时间复杂度:O(n2)
  • 稳定性:稳定

4.快速排序

快速排序(英语:Quicksort),又称划分交换排序(partition-exchange sort),通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

步骤为:

从数列中挑出一个元素,称为"基准"(pivot),
重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。

"""
快速排序
"""


# 先假设索引0是中间值,mid = li[0],记录下来这个中间值mid
# 创建两个游标left=0,right=列表长度-1
# 取最后面的right与mid进行比较,大于mid,则right向左移,直到小于mid,这个时候,设置li[left]=li[right],
# 此时right停止移动,转而left开始比较。最后一个的元素位置空出来可以复制操作

# 即比较li[left]和mid,如果小于mid,则left向右移动,如果大于mid,则设置li[right]=li[left]
# 此时left停止移动,right开始移动,left位置又空出来允许赋值操作

# 这样一轮比较之后,left和right相遇,left=right,可以li[left]=mid,那么mid左侧都是<mid的值,右侧均>mid

# 接着left_list = li[:mid],右侧列表:right_list = li[mid:],再对其进行递归快速排序
def quick_sort(alist, start, end):
    """快速排序"""

    # 递归的退出条件
    if start >= end:
        return

    # 设定起始元素为要寻找位置的基准元素
    mid = alist[start]

    # low为序列左边的由左向右移动的游标
    low = start

    # high为序列右边的由右向左移动的游标
    high = end

    while low < high:
        # 如果low与high未重合,high指向的元素不比基准元素小,则high向左移动
        while low < high and alist[high] >= mid:
            high -= 1
        # 将high指向的元素放到low的位置上
        alist[low] = alist[high]

        # 如果low与high未重合,low指向的元素比基准元素小,则low向右移动
        while low < high and alist[low] < mid:
            low += 1
        # 将low指向的元素放到high的位置上
        alist[high] = alist[low]

    # 退出循环后,low与high重合,此时所指位置为基准元素的正确位置
    # 将基准元素放到该位置
    alist[low] = mid

    # 对基准元素左边的子序列进行快速排序
    quick_sort(alist, start, low-1)

    # 对基准元素右边的子序列进行快速排序
    quick_sort(alist, low+1, end)


alist = [54,26,93,17,77,31,44,55,20]
quick_sort(alist,0,len(alist)-1)
print(alist)

时间复杂度

  • 最优时间复杂度:O(nlogn)
  • 最坏时间复杂度:O(n2)
  • 稳定性:不稳定
发布了146 篇原创文章 · 获赞 66 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_38923792/article/details/96867862
今日推荐