算法图解-- 学习笔记(选择排序)

98 阅读2分钟

关键词

  • 链表
  • 数组
  • 选择排序

常数省略

随着排序的进行,每次需要检查的元素数在逐渐减少,最后一次需要检查的元素都只有一 个。既然如此,运行时间怎么还是O(n2 )呢?这个问题问得好,这与大O表示法中的常数相关。 第4章将详细解释,这里只简单地说一说。

你说得没错,并非每次都需要检查n个元素。第一次需要检查n个元素,但随后检查的元素 数依次为n  1, n – 2, …, 2和1。平均每次检查的元素数为1/2 × n,因此运行时间为O(n × 1/2 × n)。 但大O表示法省略诸如1/2这样的常数(有关这方面的完整讨论,请参阅第4章),因此简单地写 作O(n × n)或O(n2 )。

对于省略常数可以理解,但是这个 1/2 x n 感觉不对。

练习

// 第一层循环从下标i=0开始,每一次确认一个数的排序位置,比如第一次遍历比较:
// 假设第一个数是最小的,记为curr = arr[i],currIndex = i
// 开始第二层循环j=0,从第一个数开始遍历比较
// 如果第二层循环遍历到的数比curr小,那么就需要重置curr=arr[j]数据和下标currIndex = j,
// 然后数据下标i,currIndex交换位置
// 再次回到第一层循环下标i=1
// 第二层循环下标j=i=1(这是一个关键点,因为第一次遍历已经确认第一个下标i=0的数已经是最小的了,不需要再从下标j=0开始)
// 重复上述步骤指定第一层循环遍历介绍,就是最终结果了
func selectOrder(arr []int) (err error, res []int) {
    for i := 0; i < len(arr); i++ {
        index := i
        for j := i; j < len(arr); j++ {
            if arr[index] > arr[j] {
                index = j 
            }
        }
        temp := arr[index]
        arr[index] = arr[i]
        arr[i] = temp
    }
    return nil, arr
}

func main() {
    arr         := []int{5, 6, 7, 18, 9, 1, 12, 3, 4} 
    _, results 	:= selectOrder(arr)
    fmt.Println("results", results)
}

// 输出
$ go run main.go
results [1 3 4 5 6 7 9 12 18]

小结

  • 数组是连续的存储空间,读取数据快,支持随机访问,但是插入,删除操作比较麻烦。
  • 链表是非连续的存储空间,读取只能从头开始逐个遍历查找,但是插入,删除操作就比较方便。