基于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中的常见排序算法

    Javascript中的常见排序算法 在Javascript中,排序算法是非常基础和常见的算法之一,也是大多数编程语言都会涉及到的一部分。在实际应用场景中,常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序等。 冒泡排序 冒泡排序是一种简单易懂的排序算法,其中每一趟都按照从前往后的顺序比较两个相邻的元素,如果前一个元素大于后一个元素,则交换这…

    算法与数据结构 2023年5月19日
    00
  • java实现图形卡片排序游戏

    以下是“Java实现图形卡片排序游戏”的完整攻略。这个游戏的目标是将打乱的卡片,按顺序排好。具体的操作方法是通过拖拽卡片,让卡片位置移动进行排序。 技术栈 Java语言 Swing GUI库 排序算法 功能设计 加载卡片图片及绑定事件处理方法 卡片随机化处理 拖拽移动卡片 实现移动时的动画效果 判断拼图是否按顺序排好 记录游戏步骤、分数等信息 具体实现 加载…

    算法与数据结构 2023年5月19日
    00
  • python 如何在list中找Topk的数值和索引

    对于如何在Python的list中找Topk的数值和索引,可以采用以下方法: 方法一:使用sorted函数排序 可以使用Python内置的sorted函数对list进行排序,然后取前k个元素,同时得到它们的索引。具体代码如下: lst = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] k = 3 # 记录每个元素的索引和值 lst_wi…

    算法与数据结构 2023年5月19日
    00
  • python KNN算法实现鸢尾花数据集分类

    Python实现KNN算法对鸢尾花数据集进行分类 介绍 KNN(K-Nearest-Neighbor)算法是一种非常常用且简单的分类算法之一。它的基本思想是把未知数据的标签与训练集中最邻近的K个数据的标签相比较,得票最多的标签就是未知数据的标签。本文将介绍如何使用Python实现对鸢尾花数据集进行KNN分类。 步骤 加载数据 首先,我们需要加载鸢尾花数据集。…

    算法与数据结构 2023年5月19日
    00
  • C++ sort排序之降序、升序使用总结

    C++ sort排序之降序、升序使用总结 介绍 sort函数是C++ STL库提供的一种排序函数,可以快速方便地对数组或容器进行排序。本文将详细介绍sort函数的用法,包括排序方式、自定义比较函数和对容器的排序等内容。 基本用法 sort函数的声明如下: template <class RandomAccessIterator> void sor…

    算法与数据结构 2023年5月19日
    00
  • java ArrayList按照同一属性进行分组

    要按照同一属性进行分组,我们需要用到Java中的Collections类和Comparator接口。 首先,我们需要为ArrayList中的对象定义一个属性,以便按照该属性进行分组。例如,我们定义一个Person类,其中包含name和age两个属性,我们想要按照年龄进行分组。则代码如下: public class Person { private Strin…

    算法与数据结构 2023年5月19日
    00
  • 利用JavaScript在网页实现八数码启发式A*算法动画效果

    下面是利用JavaScript在网页实现八数码启发式A*算法动画效果的完整攻略: 简介 八数码问题是指在一个33的方格上,放置了1~8这八个数字,其中有一个空格可以移动,初态和目标态之间的变换最少需要几步。而启发式A算法是一种针对图形和网络中的路径规划问题的搜索算法。 利用JavaScript实现八数码启发式A*算法动画效果,可以帮助用户在屏幕上直观地看到计…

    算法与数据结构 2023年5月19日
    00
  • PHP 快速排序算法详解

    PHP 快速排序算法详解 算法原理 快速排序(Quick Sort)是一种高效的排序算法,它的核心思想是分而治之,在序列中选择一个基准元素,将小于基准元素的值放置在基准元素左边,大于基准元素的值放置在基准元素右边,然后再对左右子序列分别执行同样的操作,直到序列有序为止。 具体实现过程如下: 选择一个基准元素 $pivot$,可以随机选择一个元素,也可以选择第…

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