常见算法(以Python实现)

目录

冒泡排序

选择排序

插入排序

快速排序

归并排序

堆排序


冒泡排序

冒泡排序是一种简单的比较排序算法,其核心思想是不断地比较相邻的两个元素并交换它们的位置,将较大(或较小)的元素逐渐“浮”到数组的一端(冒泡到顶部或底部),从而实现排序。冒泡排序的名字来源于像气泡一样从底部冒到顶部或相反。

def bubble_sort(arr):
    n = len(arr)
    # 外层循环控制需要比较的轮数
    for i in range(n):
        # 标记是否发生过交换,如果某一轮没有发生交换,则说明数组已经有序
        swapped = False
        # 内层循环比较相邻元素并交换
        for j in range(0, n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]  # 交换位置
                swapped = True
        # 如果这一轮没有发生交换,说明数组已经有序,可以提前退出
        if not swapped:
            break

# 示例
arr = [64, 34, 25, 12, 22, 11, 90]
bubble_sort(arr)
print("排序后的数组:", arr)

冒泡排序是稳定的排序,上述示例中,外层循环控制需要比较的轮数,内层循环用于比较相邻元素并进行交换。每轮内层循环都将较大的元素“冒泡”到数组的末尾,因此排序完成后,数组中的元素按升序排列。冒泡排序的时间复杂度为O(n^2),不适合大规模数据排序,但是它是一种容易理解和实现的排序算法。

选择排序

一种简单的排序算法,其核心思想是不断地选择最小(或最大)的元素并将其放置在已排序部分的末尾。这个过程不断重复,直到整个数组被排序完成。

以下是选择排序的实现步骤:

  1. 在未排序部分中找到最小(或最大)的元素。
  2. 将找到的最小(或最大)元素与未排序部分的第一个元素交换位置。
  3. 将已排序部分的末尾扩展,未排序部分减小。
  4. 重复步骤1至3,直到整个数组被排序。
def selection_sort(arr):
    n = len(arr)
    for i in range(n):
        # 假设当前位置的元素是最小的
        min_index = i
        # 在未排序部分找到最小的元素
        for j in range(i + 1, n):
            if arr[j] < arr[min_index]:
                min_index = j
        # 将找到的最小元素与当前位置交换
        arr[i], arr[min_index] = arr[min_index], arr[i]

# 示例
arr = [64, 34, 25, 12, 22, 11, 90]
selection_sort(arr)
print("排序后的数组:", arr)

选择排序不断地在未排序部分中寻找最小的元素,并将其交换到已排序部分的末尾。通过重复这个过程,数组逐渐被排序。选择排序的时间复杂度为O(n^2),因此它不适合用于大规模数据的排序,但它是一种容易理解和实现的排序算法。 

选择排序是不稳定的算法,例如43,89,21,43,28,15,经过选择第一遍排序时候会将第一个43跟最后15对调位置,原来第一个43位置放到第二个43的后面,而后面的排序步骤也不会修改两个43的相对顺序。

插入排序

逐步将未排序的元素插入到已排序的部分中,直到整个数组都有序。插入排序是一种稳定排序。

  1. 从第二个元素开始,将其与前面的已排序部分进行比较。
  2. 将未排序元素逐步向前移动,直到找到合适的位置插入,使得插入后的部分仍然保持有序。

实现步骤:

  1. 从第二个元素开始,将当前元素保存为"待插入元素"。
  2. 与已排序部分的最后一个元素进行比较,如果待插入元素比最后一个元素小,则将最后一个元素向后移动,为待插入元素腾出位置。
  3. 继续与前一个已排序元素比较,直到找到合适的位置,插入待插入元素。
  4. 重复以上步骤,直到所有元素都有序。
def insertion_sort(arr):
    for i in range(1, len(arr)):  # 从第二个元素开始
        current_element = arr[i]  # 待插入的元素
        j = i - 1  # 已排序部分的最后一个元素的索引

        while j >= 0 and current_element < arr[j]:
            arr[j + 1] = arr[j]  # 将较大的元素向后移动
            j -= 1

        arr[j + 1] = current_element  # 插入待插入元素到正确的位置

# 测试插入排序
arr = [5, 2, 9, 3, 6]
insertion_sort(arr)
print("排序后的数组:", arr)

插入排序是一种稳定的排序算法,适用于小型数组或部分有序的数组。它的时间复杂度为O(n^2),因此在大型数据集上不太高效,但对于小规模数据集来说,它是一个简单而有效的排序算法。

快速排序

思想:分治法,即将一个大问题分割成若干个小问题,解决小问题,最终将小问题的解整合起来获得大问题的解。

快速排序的基本思想可以概括为以下步骤:

  1. 选择基准元素(Pivot):从待排序的数组中选择一个基准元素。通常选择第一个元素、最后一个元素或者随机选择一个元素作为基准。
  2. 分割阶段:将数组中的元素分为两部分,一部分小于或等于基准元素,一部分大于基准元素。这个过程称为分割(Partitioning)。
  3. 递归排序:分割阶段之后,将分割得到的两个子数组分别进行快速排序,这是递归的过程。递归的终止条件是子数组的大小为1或0,因为已经有序。
  4. 合并:在递归排序结束后,就可以将子数组合并在一起,得到完整的有序数组。

快速排序是一种高效的排序算法,平均情况下的时间复杂度为O(n log n),最坏情况下为O(n^2),但最坏情况很少发生,通常情况下表现非常出色。快速排序不需要额外的存储空间,是一种原地排序算法。需要注意的是,快速排序的性能与选取的基准元素有关,如果选择的基准元素不合适,可能导致性能下降。因此,一些变种的快速排序算法对基准元素的选择进行了优化。

下面是以Python实现的代码:

def quick_sort(arr):
    if len(arr) <= 1:
        return arr

    base_num = arr[0]  # 选择第一个元素作为基准
    less_than_base = [x for x in arr[1:] if x <= base_num]
    greater_than_base = [x for x in arr[1:] if x > base_num]

    return quick_sort(less_than_base) + [base_num] + quick_sort(greater_than_base)

# 示例用法
arr = [3, 6, 8, 10, 1, 2, 9]
sorted_arr = quick_sort(arr)
print(sorted_arr)

快速排序通常是不稳定的排序算法。 例如43,89,21,43,28,15, 选择第一个43位基准,经过第一次分组,对于<=43放到左边组,>43组放到右边组,整组变为[21,43,28,15]+[43]+[89]。 可以看出第一个43已经放到后面的位置,所以是不稳定的算法。

归并排序

基于分治思想的排序算法,它的主要思想是将一个数组分割成若干子数组,分别对子数组进行排序,然后将它们合并为一个有序数组。以下是归并排序的思想

  1. 将原始数组分割成若干子数组,直到每个子数组都只包含一个元素,这些单元素数组可以看作是有序的。
  2. 逐步合并相邻的子数组,同时保持合并后的子数组有序,一直重复这个过程,直到整个数组都有序。

实现步骤:

  1. 分割:将原始数组分成两个子数组,递归地将这两个子数组分割成更小的子数组,直到子数组中只包含一个元素。
  2. 合并:将两个有序的子数组合并为一个更大的有序数组,重复这一过程直到所有子数组都合并完成。
def merge_sort(arr):
    if len(arr) > 1:
        mid = len(arr) // 2
        left_half = arr[:mid]
        right_half = arr[mid:]

        merge_sort(left_half)  # 递归地对左半部分排序
        merge_sort(right_half)  # 递归地对右半部分排序

        i = j = k = 0

        # 合并两个子数组
        while i < len(left_half) and j < len(right_half):
            if left_half[i] < right_half[j]:
                arr[k] = left_half[i]
                i += 1
            else:
                arr[k] = right_half[j]
                j += 1
            k += 1

        # 检查是否有剩余的元素
        while i < len(left_half):
            arr[k] = left_half[i]
            i += 1
            k += 1

        while j < len(right_half):
            arr[k] = right_half[j]
            j += 1
            k += 1

# 测试归并排序
arr = [38, 27, 43, 3, 9, 82, 10]
merge_sort(arr)
print("排序后的数组:", arr)

归并排序是稳定的,上述代码演示了如何使用归并排序对整数数组进行排序。它递归地将数组分割成两个子数组,然后合并这些子数组,保持它们有序。运行示例代码后,您将看到排序后的数组。归并排序是一种稳定的排序算法,它的时间复杂度为O(n log n),适用于大型数据集的排序。

堆排序

堆排序(Heap Sort)是一种高效的排序算法,它的思想基于堆数据结构。堆是一种特殊的树形数据结构,具有以下特点:

  • 堆是一个完全二叉树。
  • 每个节点的值大于或等于(最大堆)或小于或等于(最小堆)其子节点的值。

堆排序的基本思想是将待排序的元素构建成一个堆,然后逐步将堆顶元素取出,再重新调整堆,不断重复这个过程,直到整个数组排序完成。以下是堆排序的实现步骤:

  1. 构建最大堆:将待排序数组视为一个完全二叉树,从最后一个非叶子节点开始,依次向前构建最大堆。
  2. 排序:不断将堆顶元素(最大值)与数组末尾元素交换,然后将数组范围缩小,重新调整堆,直到数组完全有序。
def heapify(arr, n, 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[i], arr[0] = arr[0], arr[i]  # 交换堆顶元素和当前元素
        heapify(arr, i, 0)  # 调整剩余元素的堆

# 测试堆排序
arr = [38, 27, 43, 3, 9, 82, 10]
heap_sort(arr)
print("排序后的数组:", arr)

堆排序是一种不稳定的排序算法,其时间复杂度为O(n log n),适用于大型数据集的排序。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值