排序法:选择、冒泡、插入和快排

排序方法指的是对一个无序的数列,按照一定方法让其变得有序。排序法重点是思维过程,本文中的四种排序方法都较为基础,但其中蕴含的算法思维各不相同,适合作为算法入门学习内容。

  • 选择排序法
    我认为选择排序法是较符合一般人思维模式的排序法,它是指对于每个数列,从其中找出最小的一个数字,将其放至首位,然后再不断对剩余的无序数列重复此操作。当剩余无序数列的长度为0时,则完成排序。其python实现代码如下:
点击查看代码
def select_sort(my_list):  
    n= len(my_list)        # n为数列长度
    for i in range(n-1):   # 共进行n-1次选择(外循环),因为只要选出最小的n-1个数,最大的数就是剩下的,不需要进行额外操作天然已经位于数列末端
        min_i = i          # 初始化最小数字的索引为无序数列的第一个元素的索引,即假设第一个数字现在就是最小值。
        for j in range(i+1,n):  # 内循环处理无序数列中的每一个元素 
            if my_list[j]<my_list[min_i]:    #一旦无序数列中的数字比我们假设的初始值小,就将其索引记录下来
                min_i = j
        if min_i != i:     # 一次内循环完成后,已经将无序数列中最小值的索引赋值给了min_i,如果其不同于无序数列的最左端(第一个)数字,则将两者交换。交换完成后最小值已位于无序数列的最左段,此时可以将其视为有序数列的最右端,而不再是无序数列的一部分(通过外循环i的不断增加来实现)
            my_list[i],my_list[min_i] = my_list[min_i],my_list[i]
选择排序的时间复杂度O(n^2)
  • 冒泡排序法
    冒泡排序的过程是每次将最大的一个元素放至队列末尾,这听起来很像选择排序的反过程。但是冒泡排序的实现是完全不同的。每一次排序,都是将无序数列的每一位,依次与其右边的元素进行比较,并将其中较大的数字放在右边。如此操作,大的数字会不断被向右移,直至遇到比他更大的数字。这个更大的数字会接过其接力棒,再次向右进行比较,直到到达无序数列的最后一位。代码实现如下:
点击查看代码
def bubble_sort(my_list):
    listlen = len(my_list)
    for i in range(listlen-1):  # i 代表轮次,范围为0到n-2共n-1次(最大的n-1个数字排完无需再排第n个)
        for j in range(listlen-1-i):   # j 为每轮进行比较的第一个数字,因为最后的i个数字已经完成了排序,所以每次都是比较(n-1)-i个数字即可。对于第一轮
            if my_list[j]>my_list[j+1]: # 如果比右边数字大,则进行交换
                my_list[j],my_list[j+1]=my_list[j+1],my_list[j]
冒泡排序的时间复杂度O(n^2)
  • 插入排序
    插入排序是指将每个序列分为左右两个部分,左边是已经从小到大排序完成的数列,右边是无序数列,依次将无序数列的第一位插入至有序数列中。对于一个未经过排序的数列,可以将第一个数字视作有序的(很显然单独一个数字必然是有序的),而将第二个数字开始的剩余数字视为需要排序的无序数列。代码实现如下:
点击查看代码
def insert_sort(my_list):
    n = my_list
    for i in range(1,n):             # i 表示现在要处理第i个数字(第0)位不需要处理,在处理完这n-1个数字后它会天然出现在应该出现的位置
        for j in range(i+1,0,-1):    # j 指示要进行比较的数字,每次与左边的数字进行比较,如果小于左边数字说明应该左移
            if my_list[j]<my_list[j-1]:
                my_list[j],my_list[j-1] = my_list[j-1],my_list[j]
            else:
                break
插入排序的时间复杂度为O(n^2)
  • 快速排序
    快速排序的逻辑很简单,但是代码实现会稍微复杂一点。原理是:随便选取一个数字,将数列中比其小的数字都放到它左侧,比它大的数字都放在它右侧,以此来确定其在数列中的位置;之后,再对于每个没有确定下来的数列区间重复此操作,直至每个数字都位于正确的位置。快排使用了递归的方式去排序,代码实现如下:
点击查看代码
def quick_sort(my_list,start,end):
    """
    快速排序
    :param my_list: 要排序的列表
    :param start: 表示从哪个位置开始排序
    :param end: 表示到哪个位置结束排序
    :return: 如果start>=end,则表示排序完成,否则需要继续排序
    """
    if start >=end:  # 当一个区间的长度为1或0时,说明已经排好序,则直接返回
        return
    left = start  #左指针为区间的第一个元素
    right = end   #右指针
    mid = my_list[start]   # 选取第一个元素作为中间值(基准值)。此时左指针位置空出来了
    while left < right:    # 左右指针向中间移动,直到左右指针相遇
        while my_list[right]>=my_list and left <right:  # 右指针向左移动,直到遇到小于等于基准值的元素
            right-=1
        my_list[left] = my_list[right]   # 将小于等于基准值的元素放到左指针位置
        while my_list[left]<my_list and left <right:   # 左指针向右移动,直到遇到大于等于基准值的元素
            left+=1
        my_list[right] = my_list[left]   # 将大于等于基准值的元素放到右指针位置
    my_list[left] = mid   # 经过上述的两次交换之后,可能存在两种情况:1.左右指针相遇;2.左指针的值已经赋给了右指针的位置。无论哪种情况,都需要将基准值放到左指针的位置。
    # 递归左半区间。如果 start=left-1,说明这次排序完之后左半区只有一个元素,不需要再排序。如果start>left-1,说明左半区为空,不需要再排序。
    quick_sort(my_list,start,left-1)
    quick_sort(my_list,right+1,end)      # 递归右半区间
posted @ 2024-04-11 09:21  小丑与锁鸟  阅读(52)  评论(0)    收藏  举报