【Go】C++转Go:数据结构练习(一)排序算法
本专栏文章持续更新,新增内容使用蓝色表示。
每种排序方法都可以通过例子,手动模拟一遍,确定思路,再开始写代码。
持续更新中,预计1-2天内完善
冒泡排序
描述:
通过相邻元素的比较和交换,使较大的元素逐渐"浮"到数组的末尾,就像水中的气泡一样向上漂浮。
思路:
举一个实例,如有一个数组 {9,2,10,23,16,28,2} ,将它从小到大排序。
第一轮,从第0和第1个元素开始比较,9>2交换,9<10跳过,10<23跳过,23>16交换,23<28跳过,28>2交换,此时整个数组中最大的元素在末尾,再次遍历时就不需要和末尾的元素比较。末尾一个元素固定,此时的数组为{2,9,10,16,23,2,28} 。
第二轮,依旧从第0和第1个元素开始比较,2<9跳过 9<10跳过 10<16跳过 16<23跳过 23>2交换。末尾两个元素固定,此时的数组为{2,9,10,16,2,23,28} 。
第三轮,2<9跳过 9<10跳过 10<16跳过 16>2交换。末尾三个元素固定,此时的数组为{2,9,10,2,16,23,28} 。
第四轮,2<9跳过 9<10跳过 10>2交换。末尾四个元素固定,此时的数组为{2,9,2,10,16,23,28} 。
第五轮,2<9跳过 9>2交换 。末尾五个元素固定,此时的数组为{2,2,9,10,16,23,28} 。
第六轮,2==2跳过 。末尾六个元素固定,此时的数组为{2,2,9,10,16,23,28} 。
综上,整个过程中给7个元素排序,需要经过6轮。
如果是{1, 2, 3, 4, 5, 7, 6}呢?同样是7个元素,但是实际上在第2轮时,就已经有序,没有进行交换了。所以可以设置一个标志位flag,每轮进入时设为false,有交换时置为true,如果该轮结束该值为false,说明没有发生交换,数组已经有序,程序可以提前跳出循环。
package mainimport "fmt"func PrintNums(nums []int) {for i := 0; i < len(nums); i++ {fmt.Printf("%d ", nums[i])}fmt.Println()
}func main() {// 冒泡排序nums := []int{9, 2, 10, 23, 16, 28, 2}fmt.Printf("原数组:")PrintNums(nums)fmt.Printf("冒泡排序过程:\n")for i := 0; i < len(nums)-1; i++ {flag := falsefor j := 0; j < len(nums)-i-1; j++ {if nums[j] > nums[j+1] {flag = truetemp := nums[j]nums[j] = nums[j+1]nums[j+1] = temp}}PrintNums(nums)if flag == false {fmt.Println("本轮无交换,已提前结束!")break}}
}
时间复杂度最差为O(),最好为O(n),平均时间复杂度为O(
)。
空间复杂度为O(1),不需要借助额外数组。

选择排序
描述:
每轮选择一个最大或者最小的数,放在已排序元素的末尾。
思路:
还是数组 {9,2,10,23,16,28,2} ,将它从小到大排序。先尝试选择一个最小的数,放在已排序元素的末尾。假设已排序元素在前面,初始情况下已排序元素个数为0,已排序指针为0,数组指针为0。从0开始遍历。
第一轮,从0开始,到6结束,发现最小的是2,下标为1,进行交换,已排序元素为1。
以此类推,已排序元素逐渐增多,7个元素共经历6轮成为有序数组。
package mainimport "fmt"func PrintNums(nums []int) {for i := 0; i < len(nums); i++ {fmt.Printf("%d ", nums[i])}fmt.Println()
}func main() {nums := []int{9, 2, 10, 23, 16, 28, 2}fmt.Printf("原数组:")PrintNums(nums)fmt.Printf("选择排序过程:\n")for i := 0; i < len(nums)-1; i++ {minnum := ifor j := i; j < len(nums); j++ {if nums[minnum] > nums[j] {minnum = j}}temp := nums[i]nums[i] = nums[minnum]nums[minnum] = tempPrintNums(nums)}
}

插入排序
描述:
在已排序的数组中选择一个合适的位置插入进去,从后往前比较。
思路:
数组 {9,2,10,23,16,28,2} ,单独一个数字必然是有序的,所以跳过0号位置,从1号位置开始,依次和前面已有序的数组进行比较,若小于,则交换,否则跳过。
package mainimport "fmt"func PrintNums(nums []int) {for i := 0; i < len(nums); i++ {fmt.Printf("%d ", nums[i])}fmt.Println()
}func main() {nums := []int{9, 2, 10, 23, 16, 28, 2}fmt.Printf("原数组:")PrintNums(nums)fmt.Printf("插入排序过程:\n")for i := 0; i < len(nums)-1; i++ {for j := i + 1; j > 0; j-- {if nums[j] < nums[j-1] {temp := nums[j]nums[j] = nums[j-1]nums[j-1] = temp} else {break}}PrintNums(nums)}
}

剩下的后续更新
预计明天
希尔排序
插入排序的plus版本,将原始列表分成多个子列。
归并排序
描述:
分而治之
快速排序
描述:
选择一个基准元素与之比较,大于它的都放在后面,小于等于它的都放在前面,然后再递归的对前后进行处理。
