关键词
- 链表
- 数组
- 选择排序
常数省略
随着排序的进行,每次需要检查的元素数在逐渐减少,最后一次需要检查的元素都只有一 个。既然如此,运行时间怎么还是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]
小结
- 数组是连续的存储空间,读取数据快,支持随机访问,但是插入,删除操作比较麻烦。
- 链表是非连续的存储空间,读取只能从头开始逐个遍历查找,但是插入,删除操作就比较方便。