简单选择排序
原理阐述:从未排序的数组序列中,选择最大或者最小元素添加入已排序数组 最开始已排序数组为空
import (
"fmt"
)
//简单选择排序
func simpleSelectSort(nums []int) {
for i := 0; i < len(nums); i++ {
min := i
for j := i + 1; j < len(nums); j++ {
if nums[min] > nums[j] {
min = j
}
}
if min != i {
tmp := nums[min]
nums[min] = nums[i]
nums[i] = tmp
}
}
}
//test
func main()
{
var nums = []int{7, 8, 11, 4, 9, 3, 15}
fmt.Println("nums before insertSort:%s", nums)
simpleSelectSort(nums)
fmt.Println("nums after insertSort:%s", nums)
}
直接插入排序
原理阐述:从未排序的数组元素中,取数据填写到以排序的数组中,并且形成已排序数组,数组长度为1的数组为以排序数组
import (
"fmt"
)
//插入排序
func insertSort(nums []int) {
for i := 1; i < len(nums); i++ {
for j := 0; j < i; j++ {
if nums[i] < nums[j] {
tmp := nums[i]
nums[i] = nums[j]
nums[j] = tmp
}
}
}
}
//test
func main()
{
var nums = []int{7, 8, 11, 4, 9, 3, 15}
fmt.Println("nums before insertSort:%s", nums)
insertSort(nums)
fmt.Println("nums after insertSort:%s", nums)
}
冒泡排序
原理阐述:相邻两个元素进行对比,顺序相反则互换。经过一轮的对比后,最大或者最小的元素“浮”到顶端,经过len(nums)-1轮后,nums变为有序数组
import (
"fmt"
)
//冒泡排序
func bubbleSort(nums []int) {
for i := 1; i < len(nums); i++ { //经过了len(nums)-1轮冒泡
for j := 0; j < len(nums)-i; j++ {
if nums[j] > nums[j+1] {
tmp := nums[j]
nums[j] = nums[j+1]
nums[j+1] = tmp
}
}
}
}
//test
func main()
{
var nums = []int{7, 8, 11, 4, 9, 3, 15}
fmt.Println("nums before insertSort:%s", nums)
bubbleSort(nums)
fmt.Println("nums after insertSort:%s", nums)
}
快速排序
原理阐述:分而治之
实现步骤:
- 先从数列中取出一个数作为基准数。
- 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
- 再对左右区间重复第二步,直到各区间只有一个数(各个区间都为有序)
import (
"fmt"
)
//快速排序
func quickSort(nums []int, start int, end int) {
//结束条件
if start >= end {
return
}
tmp := nums[start] //选择第一个数为分区标志
left := start
right := end
//调整结构
for left < right {
for tmp < nums[right] && left < right {
right = right - 1
}
//here,tmp<=nums[right] ---> tmp == nums[left]
nums[left] = nums[right]
//now, nums[right] is empty
for tmp > nums[left] && left < right {
left = left + 1
}
//here, tmp >=nums[left] ---> tmp = nums[right]
nums[right] = nums[left]
//now, nums[left] is empty
}
nums[left] = tmp
quickSort(nums, start, left-1) //left array sort
quickSort(nums, left+1, end) //right array sort
}
//test
func main()
{
var nums = []int{7, 8, 11, 4, 9, 3, 15}
fmt.Println("nums before insertSort:%s", nums)
quickSort(nums, 0, lens(nums))
fmt.Println("nums after insertSort:%s", nums)
}
合并排序
原理阐述:分而治之
实现步骤:
- 将数组对分至若干有序数组(数组元素为一个的数组为有序数组)
- 将有序数组逐次两两合并为有序数组,直至合并为一个数组
import (
"fmt"
)
//合并排序
func mergeSort(nums []int, start int, boundce int, end int) {
if start >= end { //结束边界
return
}
mergeSort(nums, start, start+(boundce-start)/2, boundce) //数组拆分前半部分
mergeSort(nums, boundce+1, boundce+(end-boundce)/2, end) //数组拆分后半部分
var tmp = make([]int, end-start+1, end-start+1)
i := 0
//拷贝数组
for i <= end-start {
tmp[i] = nums[i+start]
i = i + 1
}
//数组合并过程
i = 0 //左半部分数组的起始地址
j := boundce - start + 1 //右半部分的起始地址
ii := start //终选数组的起始地址
for i <= boundce-start && j <= end-start { //结束条件
/*在左半部分选取较小元素填充目标数组*/
for i <= boundce-start && tmp[i] <= tmp[j] {
nums[ii] = tmp[i]
ii = ii + 1
i = i + 1
}
//here --> tmp[i] > tmp[j]
/*在右半部分选取较小数据填充目标数组*/
for j <= end-start && tmp[j] <= tmp[i] {
nums[ii] = tmp[j]
ii = ii + 1
j = j + 1
}
}
//结束判断
//左数组先结束
if i == boundce-start+1 {
for j <= end-start {
nums[ii] = tmp[j]
ii = ii + 1
j = j + 1
}
}
//右数组先结束
if j == end-start+1 {
for i <= boundce-start {
nums[ii] = tmp[i]
ii = ii + 1
i = i + 1
}
}
}
//test
func main()
{
var nums = []int{7, 8, 11, 4, 9, 3, 15}
fmt.Println("nums before insertSort:%s", nums)
mergeSort(nums, 0, len(nums)/2-1, len(nums)-1)
fmt.Println("nums after insertSort:%s", nums)
}
堆排序
原理
堆排序的几个操作: 1. 建堆 2. 堆调整 3. 堆排序
具体原理参见《白话经典算法系列之七 堆与堆排序》
package main
import (
"fmt"
)
//调整方式:当父节点的数据变化时,子节点的数据必须做相应调整
//2*n + 1 左子节点, 2*n + 2 右子节点
func adjust(nums []int, pos int, len int) {
tmp := pos
j := 2*pos + 1
for j < len {
//寻找较大子节点
if j+1 < len {
if nums[j+1] > nums[j] {
j++
}
if nums[tmp] < nums[j] {
nums[tmp], nums[j] = nums[j], nums[tmp]
}
} else {
if nums[tmp] < nums[j] {
nums[tmp], nums[j] = nums[j], nums[tmp]
}
}
//遍历此节点的子节点,调整
tmp = j
j = j*2 + 1
}
}
//建立堆栈
func buildHeap(nums []int) {
len := len(nums)
for i := len/2 - 1; i >= 0; i-- { //可以理解为先为子树构建“堆”,再在子树“堆”上构建父堆, len/2 为第一个非叶子节点,叶子节点肯定是“堆”
adjust(nums, i, len) //每次都为全局调整
}
}
/**
* 堆排序
*/
func heapSort(nums []int) {
tmp := len(nums)
if tmp == 0 {
return
}
buildHeap(nums)
for i := 0; i < len(nums); i++ {
nums[tmp-1], nums[0] = nums[0], nums[tmp-1] //提取堆顶
tmp--
adjust(nums, 0, tmp) //数组尾部是已经排序部分,不再做调整
}
}
//test
func main() {
var nums = []int{7, 8, 11, 4, 9, 3, 15}
fmt.Println("nums before insertSort:%s", nums)
heapSort(nums)
fmt.Println("nums after insertSort:%s", nums)
}