排序:按照某种顺序排列数据。
例如:一组单词按照字母顺序排序;一组单词按照单词长度进行排序。
排序的条件:
- 元素之间可以按某种规则比较大小;
- 明确是否违反顺序
假设要求切片数组[10, 1, 5, 3]数据按照升序排列, 以冒泡排序算法作为排序算法:
- 冒泡排序多次遍历切片数组。它比较相邻的元素,将不合顺序元素交换位置。
- 每一轮遍历都将下一个最大值放到正确的位置上。本质上,每个元素通过“冒泡”找到自己所属的位置。
- 在按升序的顺序排序中,把大的元素不断的往后移动,这样每次遍历结束,大的数据都放到了正确的位置。
第一轮遍历时,需要遍历所有的元素,具体见下图(带颜色方框的表示正在比较的元素):
- 首先从0号元素开始遍历,0号元素即值为10和1号元素即值为1进行比较,因为10大于1,所以需要互相交换位置;
- 此时,切片数组为[1, 10, 5, 3],现在遍历到了1号元素,把1号元素即值为10和2号元素即值为5进行比较,因为10大于5,所以需要互相交换位置;
- 此时,切片数组为[1, 5, 10, 3],现在遍历到了2号元素,把2号元素即值为10和3号元素即值为3进行比较,因为10大于3,所以需要互相交换位置;
- 此时,切片数组为[1, 5, 3, 10],第一轮遍历结束,最大的数字已经位于正确的位置。
第二轮遍历时,因为最后一个元素已经处于正确的位置,所以只需要遍历0号元素到倒数第二个元素即可,即[1, 5, 3],具体见下图(带颜色方框的表示正在比较的元素):
- 此时,切片数组为[1, 5, 3, 10], 首先从0号元素开始遍历,0号元素即值为1和1号元素即值为5进行比较,因为1小于10,无需交换位置;
- 此时,切片数组为[1, 5, 3, 10],现在遍历到了1号元素,把1号元素即值为5和2号元素即值为3进行比较,因为5大于3,所以需要互相交换位置;
- 此时,切片数组为[1, 3, 5, 10],第二轮遍历结束,第二大的数值已处于正确的位置。
第三轮遍历时,因为经过前两轮的排序,目前只需遍历[1, 3]即可,具体见下图(带颜色方框的表示正在比较的元素):
- 此时,切片数组为[1, 3, 5, 10],首先从0号元素开始遍历,0号元素即值为1和1号元素即值为3进行比较,因为1小于3,无需交换位置;
- 此时,切片数组为[1, 3, 5, 10], 第三轮遍历结束。
整个切片数值已经按升序排序完毕为[1, 3, 5, 10]。
时间复杂度: O(n²)
从上面的排序过程中,给n个元素的切片数值冒泡排序需要经过n-1次遍历,然后每次遍历的比较次数依次为n-1、n-2、n-3、...、2、1,所以是1+2+3+...+n-2+n-1的和,即½n²-½n,即O(n²)。
使用Golang实现的冒泡排序代码如下:
package main
import (
"fmt"
)
func bubbleSort(numList []int) {
for needToSortNums := len(numList); needToSortNums > 0; needToSortNums-- {
// 标记内部循环是否发生了元素交换
swap := false
for idx := 0; idx < needToSortNums-1; idx++ {
if numList[idx] > numList[idx+1] {
temp := numList[idx]
numList[idx] = numList[idx+1]
numList[idx+1] = temp
swap = true
}
}
// 如果没有发生元素交换,说明已经是正确的顺序,函数退出
if !(swap) {
return
}
}
}
func main() {
//numList := []int{10, 1, 5, 3}
numList := []int{10, 1, 5, 3, 2, 7}
//numList := []int{10, 1, 5, 3}
fmt.Println(numList)
// [10 1 5 3]
bubbleSort(numList)
fmt.Println(numList)
// [1 3 5 10]
}
选择排序为在冒泡排序基础上进行优化后的一种排序算法。