基于Go语言实现插入排序算法及优化

基于Go语言实现插入排序算法及优化攻略

插入排序算法

插入排序是一种简单直观的排序方法,主要思路是将未排序部分的第一个元素插入到已排序部分合适的位置。具体实现方式如下:

func InsertionSort(arr []int) {
    n := len(arr)
    for i := 1; i < n; i++ {
        // 寻找arr[i]合适的插入位置
        for j := i; j > 0 && arr[j] < arr[j-1]; j-- {
            // 交换arr[j]和arr[j-1]
            arr[j], arr[j-1] = arr[j-1], arr[j]
        }
    }
}

其中,循环内的 for 语句用于寻找当前元素在已排序列表中合适的位置,并将元素插入该位置。如此迭代,最终得到一个有序的数组。值得注意的是,该算法最坏时间复杂度为 $O(n^2)$,因为每个元素都需要与已排序列表中的元素进行比较,并且可能需要不断交换位置。

插入排序算法优化

在实践中,插入排序可以针对特定数据集进行一些优化,以提高性能。以下是三种常见的优化方法:

1. 减少赋值操作

对于优化过的算法,我们常常尽可能减少比较和交换操作,因为对于大规模的数据,这些操作所耗费的时间是惊人的。因此,我们可以将需要比较和交换的元素复制一份,这样每次交换操作就会少半,从而提高算法的效率。

func InsertionSort2(arr []int) {
    n := len(arr)
    for i := 1; i < n; i++ {
        temp := arr[i]
        j := i
        // 寻找temp合适的插入位置
        for ; j > 0 && temp < arr[j-1]; j-- {
            // 将较大的元素后移一位
            arr[j] = arr[j-1]
        }
        // 插入temp
        arr[j] = temp
    }
}

2. 二分查找插入位置

由于插入排序算法的主要瓶颈在于需要不断比较和移动元素,我们可以考虑将寻找插入位置的方式从顺序查找改为二分查找。这样一来,每次寻找插入位置的时间复杂度可以降为 $O(\log n)$。

func binarySearch(arr []int, value int, left, right int) int {
    for left <= right {
        mid := left + (right-left)/2
        if arr[mid] == value {
            return mid
        } else if arr[mid] > value {
            right = mid - 1
        } else {
            left = mid + 1
        }
    }
    return left
}

func InsertionSort3(arr []int) {
    n := len(arr)
    for i := 1; i < n; i++ {
        // 寻找arr[i]合适的插入位置
        index := binarySearch(arr, arr[i], 0, i-1)
        // 将arr[i]插入index处,并后移后面的元素
        for j := i; j > index; j-- {
            arr[j], arr[j-1] = arr[j-1], arr[j]
        }
    }
}

3. 序列分组

对于近乎有序的数据集合,可以考虑将序列分为多个子序列进行排序,以减少插入操作所涉及的元素数量。例如,下面的代码中,我们将数组按照一定的步长分为若干小组,然后对每个小组进行排序,最后合并为一个有序的数组。

func ShellSort(arr []int) {
    n := len(arr)
    for gap := n / 2; gap >= 1; gap /= 2 {
        // 对每个小组进行插入排序
        for i := gap; i < n; i++ {
            temp := arr[i]
            j := i - gap
            for ; j >= 0 && temp < arr[j]; j -= gap {
                arr[j+gap] = arr[j]
            }
            arr[j+gap] = temp
        }
    }
}

示例说明

示例1:优化二分查找插入位置

package main

import (
    "fmt"
)

// 二分查找arr数组中第一个大于等于value的数的下标
func binarySearch(arr []int, value int, left, right int) int {
    for left <= right {
        mid := left + (right - left) / 2
        if arr[mid] >= value {
            if mid == 0 || arr[mid - 1] < value {
                return mid
            } else {
                right = mid - 1
            }
        } else {
            left = mid + 1
        }
    }
    return left
}

func InsertionSort2(arr []int) {
    n := len(arr)
    for i := 1; i < n; i++ {
        temp := arr[i]
        j := i
        // 寻找temp合适的插入位置
        index := binarySearch(arr, temp, 0, i-1)
        // 将较大的元素后移一位
        for ; j > index; j-- {
            arr[j] = arr[j - 1]
        }
        // 插入temp
        arr[index] = temp
    }
}

func main() {
    arr := []int{5, 2, 4, 6, 1, 3}
    InsertionSort2(arr)
    fmt.Println(arr)
}

输出结果:

[1 2 3 4 5 6]

上面的代码中,我们将插入算法优化为二分查找插入位置的方式,并且对原始的 InsertionSort 函数进行了一定的重构。运行该示例后,输出结果表明排序成功。

示例2:优化序列分组

package main

import (
    "fmt"
)

func InsertionSortWithStep(arr []int, step int) {
    n := len(arr)
    for i := step; i < n; i++ {
        temp := arr[i]
        j := i - step
        for ; j >= 0 && temp < arr[j]; j -= step {
            arr[j+step] = arr[j]
        }
        arr[j+step] = temp
    }
}

func ShellSort(arr []int) {
    n := len(arr)
    step := n / 2 // 初始步长
    for step > 0 {
        for i := 0; i < step; i++ {
            InsertionSortWithStep(arr[i:n], step) // 对每个小组进行插入排序
        }
        step /= 2 // 步长缩小一半
    }
}

func main() {
    arr := []int{3, 6, 1, 8, 2, 9, 0}
    ShellSort(arr)
    fmt.Println(arr)
}

输出结果:

[0 1 2 3 6 8 9]

上面的代码中,我们使用序列分组的方式对插入排序进行了优化,并且将算法实现封装为了两个函数,使得语义更加清晰。运行该示例后,输出结果表明排序成功。

总结

优化算法并非易事,而插入排序的优化也是一个很有趣的课题。我们可以从多个方面考虑优化策略,以逐步提升算法的性能。不过也要注意,性能并非永恒追求的目标,对于不同的场景,我们可能更需要的是代码易读、易维护等方面的优化。因此,优化算法时,一定要结合具体情况,不要只是一味地追求更高的性能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于Go语言实现插入排序算法及优化 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Javascript排序算法之合并排序(归并排序)的2个例子

    下面我将详细讲解“Javascript排序算法之合并排序(归并排序)的2个例子”的完整攻略。该攻略包含以下内容: 合并排序算法的原理介绍 归并排序实现流程 两个例子的具体实现及演示 合并排序算法的原理介绍 合并排序是一种基于分治思想的排序算法。它的基本思路是将待排序序列分成若干个子序列,对每个子序列递归地进行排序,最后合并所有子序列,得到最终的排序结果。 具…

    算法与数据结构 2023年5月19日
    00
  • python快速排序代码实例

    Python 快速排序 (Quick Sort) 是一种排序算法,它利用分治思想来快速排序一个数组或序列。该算法的时间复杂度为 O(nlogn)。 要理解快速排序算法,我们需要掌握以下概念: 基准值 (pivot):排序过程中用于比较的值。在每一轮的排序过程中,基准值会将数组或序列分成两部分。 子数组 (subarray):对于一个数组或序列,它的一部分就是…

    算法与数据结构 2023年5月19日
    00
  • C语言排序方法(冒泡,选择,插入,归并,快速)

    下面是关于C语言排序方法冒泡、选择、插入、归并、快速的详细攻略: 冒泡排序 冒泡排序是一种最简单的排序算法,它的核心思想是从左到右依次比较相邻的两个元素,如果前一个元素大于后一个元素,就交换它们的位置,这样一遍比较后,最大的元素就会被“冒泡”到最右边。然后再对剩余的元素重复同样的操作,这样一直迭代直到整个序列排序完成。 下面是标准的C语言冒泡排序代码示例: …

    算法与数据结构 2023年5月19日
    00
  • Java实现快速排序和堆排序的示例代码

    Java实现快速排序和堆排序是经常被面试官提问的面试题目之一。下面是一份攻略,来帮助大家快速掌握这两种排序算法。 快速排序 快速排序(Quick Sort)是一种基于分治思想实现的排序算法,其主要思路是通过分区(Partition)操作将一个数组分成两个子数组,再分别对子数组进行排序,从而达到整个数组有序的目的。 以下是Java实现快速排序的示例代码: pu…

    算法与数据结构 2023年5月19日
    00
  • C语言实现快速排序算法实例

    下面是“C语言实现快速排序算法实例”的完整攻略: 快速排序算法简介 快速排序是一种高效的排序算法,属于比较排序中的一种,采用分治策略,通过将原序列划分为若干个子序列依次排序,最终得到有序序列。该算法的平均时间复杂度为O(nlogn),最坏情况下的时间复杂度为O(n^2),因此在实际应用中要根据数据规模和数据分布情况选择合适的算法。 C语言快速排序实现示例 下…

    算法与数据结构 2023年5月19日
    00
  • java插入排序 Insert sort实例

    下面我将详细讲解如何实现Java的插入排序算法。 插入排序 Insert Sort 插入排序是一种简单直观的排序算法,它的基本思想是将未排序的数据依次插入到已排序数据中的合适位置,使得插入后序列仍然有序。 插入排序的算法步骤如下: 从第一个元素开始,该元素可以认为已经被排序; 取出下一个元素,在已经排序的元素序列中从后向前扫描; 如果该元素(已排序)大于新元…

    算法与数据结构 2023年5月19日
    00
  • java排序算法图文详解

    Java排序算法图文详解 在Java编程中,排序算法是非常重要且常见的一部分。本文将详细讲解Java中的各种排序算法及其实现,帮助读者了解不同算法的特点和使用场景,提高程序的效率和可读性。 排序算法分类 在Java中,常用的排序算法主要可以分为以下几类: 冒泡排序 选择排序 插入排序 快速排序 归并排序 堆排序 冒泡排序 冒泡排序是一种简单的排序算法,其原理…

    算法与数据结构 2023年5月19日
    00
  • PHP简单选择排序(Simple Selection Sort)算法学习

    PHP简单选择排序(Simple Selection Sort)算法学习 算法介绍 简单选择排序,也称直接选择排序,是一种简单直观的排序算法,其基本思想是:每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。 选择排序的时间复杂度为 $O(n^2)$,不适用于大规模数据排序。但选择排序的思想被很多高级排序…

    算法与数据结构 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部