Python常见排序法

1、插入排序法

def inster_sort(arr):
    # 排序n个数要进行n-1次排序,且要从第二个元素开始
    for i in range(1, len(arr)):
        # 在后面while循环会改变列表中元素的顺序,导致arr[i]的值与最初不一样
        # 因此将要插入的元素提前存储起来并且不去改变它
        temp = arr[i]
        # 从arr[i]的前一个元素开始与后面元素进行比较
        j = i - 1

        # 如果arr[j]大于要插入的数,将其向后移动
        while j >= 0 and arr[j] > temp:
            # 将自己的值赋予后一个元素,以达到向后移动的效果
            arr[j + 1] = arr[j]
            # 将自己的位置空出来,下一次循环时,如果有大于temp的数则重复上面的操作
            # 直到没有大于temp的数,最终跳出循环
            j = j - 1

        # 在空出来的位置插入temp
        arr[j + 1] = temp

         插入排序的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。具体来说,插入排序每次取出一个未排序的元素,与已排序序列中的元素从后向前扫描比较,如果该元素(已排序)大于新元素,将该元素移到下一位置,重复该步骤,直到找到已排序的元素小于或者等于新元素的位置。接着将新元素插入到该位置后。重复以上步骤,直至所有元素都排序完毕。因此,插入排序的时间复杂度为O(n^2),但对于小规模数据的排序,插入排序具有稳定且高效的性能。

2、选择排序法

def select_sort(arr):
    # 对n个数进行排序需要进行n-1次排序
    for i in range(len(arr) - 1):  
        # 找到未排序部分中的最小元素  
        min_idx = i
        for j in range(i+1, n):
            if arr[j] < arr[min_idx]:
                min_idx = j
        # 将最小元素放到已排序部分的末尾
        arr[i], arr[min_idx] = arr[min_idx], arr[i]
    return arr

        选择排序的工作原理是每次从未排序的序列中选择最小(或最大)的一个元素,存放在已排序序列的末尾。具体来说,选择排序每次从未排序的序列中选择一个最小的元素,然后与已排序序列的最后一个元素交换位置。然后对未排序序列中剩下的元素重复上述步骤,直到未排序序列为空。选择排序的时间复杂度为O(n^2),是一种简单但效率较低的排序算法,也是最不稳定的排序算法。(演示代码是升序排列,将 '<' 改为 '>' 可变为降序)

3、冒泡排序法

def bubble_sort(arr):  
    for i in range(len(arr)):  
        # 每一轮冒泡将最大值放到最后  
        for j in range(0, n-i-1):  
            if arr[j] > arr[j+1]:  
                arr[j], arr[j+1] = arr[j+1], arr[j]  
    return arr

         冒泡排序的工作原理是通过不断地比较相邻元素并交换顺序,将较大的元素逐步“浮”到数列的顶端。具体来说,冒泡排序会重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序错误就交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,即该元素列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。冒泡排序的时间复杂度是O(n^2),也是一种简单但效率较低的排序算法。

4、归并排序法

def merge_sort(arr):  
    # 归并排序递归结束条件:数组长度为1或0  
    if len(arr) <= 1:  
        return arr  
      
    # 将数组分成两部分  
    mid = len(arr) // 2  
    left_arr = arr[:mid]  
    right_arr = arr[mid:]  
      
    # 递归地对左右两部分进行归并排序  
    left_arr = merge_sort(left_arr)  
    right_arr = merge_sort(right_arr)  
      
    # 合并左右两部分  
    return merge(left_arr, right_arr)  
  
def merge(left_arr, right_arr):  
    # 合并两个有序数组  
    result = []  
    i = j = 0  
    # 将左右两部分依次比较,将较小的元素添加到结果数组中  
    while i < len(left_arr) and j < len(right_arr):  
        if left_arr[i] < right_arr[j]:  
            result.append(left_arr[i])  
            i += 1  
        else:  
            result.append(right_arr[j])  
            j += 1  
    # 将剩余的元素添加到结果数组中  
    result.extend(left_arr[i:])  
    result.extend(right_arr[j:])  
    return result

归并排序(Merge Sort)是一种采用分治法的排序算法。它的基本思路是将两个或两个以上的有序表合并成一个新的有序表。

归并排序的工作原理如下:

  1. 分解:首先需要将待排序的数组分割成两个或多个小数组,直到每个小数组只有一个元素。
  2. 解决:然后使用归并操作,将两个小数组合并成一个有序的数组。合并的过程中,我们会比较两个数组的首元素,将较小的元素放入新的数组,并移动相应的指针。重复这个过程,直到一个数组的所有元素都被放入新数组,然后将另一个数组剩下的元素也放入新数组。
  3. 合并:最终,所有的小数组都会被合并成一个大的有序数组,这就是我们的归并排序结果。

归并排序的时间复杂度是O(nlogn),在处理大量数据时,归并排序的优势就明显体现出来了。但它采用用递归调用的方式来进行排序,在减少了时间复杂度的的同时,空间复杂度达到了O(n),因此更加的占用内存空间。归并排序是一种稳定排序算法,这意味着相同元素在排序后不会改变它们原有的前后顺序。

注释说明:

  • merge_sort函数是归并排序的递归函数,它首先判断数组长度是否小于等于1,如果是,则直接返回数组本身,作为递归结束条件。否则,将数组分成两部分,递归地对左右两部分进行归并排序,并合并左右两部分。
  • merge函数用于合并两个有序数组。它首先创建一个空的结果数组,然后使用两个指针ij分别指向左右两个数组的开头,依次比较左右两个数组中的元素,将较小的元素添加到结果数组中。最后,将剩余的元素添加到结果数组中,并返回结果数组。

        归并排序对于前面的排序法而言更为复杂和难以理解,以下是一个归并排序过程的演示(以便更好地去理解该算法):

  1. 输入一个无序数组:[5, 3, 8, 6, 2, 7, 1, 4]
  2. 递归地将数组分成两部分:[5, 3, 8, 6][2, 7, 1, 4]
  3. 再次递归地将两部分分别分成两小部分:[5, 3][8, 6],以及[2, 7][1, 4]
  4. 继续递归地分,直到每个小部分只有一个元素为止:[5][3],以及[8][6]
  5. 开始合并,从最细分的部分开始,依次向上合并:[5, 3][8, 6][2, 7, 1, 4]
  6. 合并的过程中,将较小的元素移到右边,最后得到一个有序数组:[1, 2, 3, 4, 5, 6, 7, 8]

5、堆排序法

def heapify(arr, n, i):  
    """  
    以i为根节点,调整堆的结构  
    """  
    largest = i  # 初始化根节点最大  
    left = 2 * i + 1  # 左子节点  
    right = 2 * i + 2  # 右子节点  
  
    # 如果左子节点比根节点大,则更新最大值节点  
    if left < n and arr[left] > arr[largest]:  
        largest = left  
  
    # 如果右子节点比最大值节点大,则更新最大值节点  
    if right < n and arr[right] > arr[largest]:  
        largest = right  
  
    # 如果最大值节点不是根节点,则交换最大值节点和根节点的位置,继续调整堆  
    if largest != i:  
        arr[i], arr[largest] = arr[largest], arr[i]  
        heapify(arr, n, largest)  
  
def heap_sort(arr):  
    """  
    堆排序算法实现  
    """  
    n = len(arr)  
  
    # 构建最大堆  
    for i in range(n//2 - 1, -1, -1):  
        heapify(arr, n, i)  
  
    # 从最后一个元素开始,将最大值放到末尾,再重新调整堆  
    for i in range(n-1, 0, -1):  
        arr[0], arr[i] = arr[i], arr[0]  # 交换元素  
        heapify(arr, i, 0)  # 重新调整堆

堆排序法的工作原理如下:

  1. 建堆:将待排序序列构造成一个大顶堆(或小顶堆)。这样,整个序列的最大值(或最小值)就是堆的根节点。将其与末尾元素进行交换,此时末尾就为最大值(或最小值)。然后将剩余n-1个元素重新构造成一个堆。这样,新的根节点就是次大(或次小)的值。重复步骤2,直到整个序列都已排序。

例如,以大顶堆为例,步骤如下:

  • 首先将待排序序列建成一个大顶堆。
  • 将堆顶元素(最大值)与堆底元素交换。
  • 然后将除最后一个元素外的其它元素重新调整为大顶堆。
  • 重复步骤2和3,直到整个序列都已排序。

堆排序法在处理大数据集时效率较高,其时间复杂度为O(nlogn),空间复杂度为O(1)。堆排序的时间复杂度与归并排序都是O(nlogn),并且不需要额外的内存空间。在大部分情况下,堆排序的性能都高于归并排序。只有在处理极大的数据量时,堆排序的效率会低于归并排序。堆排序不是稳定的算法,相同元素的相对顺序可能会改变。

注释说明:

  1. heapify 函数是以某个节点为根节点,调整堆的结构,使其满足堆的性质(父节点的值大于或等于其子节点的值)。调整过程中,首先假设根节点最大,然后与其左右子节点比较,找出最大的节点,如果最大节点不是根节点,则交换根节点和最大节点的位置,然后递归地调整交换后的子树,使其仍然满足堆的性质。
  2. heap_sort 函数首先构建初始的最大堆(通过从中间节点开始向前遍历,对每个节点调用 heapify 函数),然后通过交换堆顶元素(最大值)和当前未排序部分的最后一个元素,将最大值放到正确位置,然后对剩余未排序部分重新调整堆的结构,重复此过程,直到整个数组都有序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值