一、基本排序
(1)基于Big-O(n^2)的排序
①选择法排序 空间复杂度O(1), 不稳定
选择数组最小的元素,与数组第一个元素交换,然后选择剩余的数组元素中最小的元素,与数组第二个元素交换,一直重复上述操作,直到数组有序。
func selectionSort(arr []int){
for i := 0; i < len(arr) - 1; i++ {
minIndex := i
for j := i + 1; j < len(arr); j++ {
if arr[minIndex] > arr[j] {
minIndex = j
}
}
swap(arr, i, minIndex)
}
}
func swap(arr []int, i int, j int){
temp := arr[i]
arr[i] = arr[j]
arr[j] = temp
}
②冒泡法排序 空间复杂度O(1), 稳定
冒泡排序是一种比较简单的排序算法,它是一种基于比较的算法,是一种稳定的排序算法。从第一个元素开始,每次比较相邻元素,如果元素顺序不正确,则进行交换,否则,比较下一对相邻元素。重复上述过程,一直到所有元素都有序。
func bubbleSort(arr []int){
for e := len(arr) - 1; e > 0; e-- {
for i := 0; i < e; i++ {
if arr[i] > arr[i + 1]{
swap(arr []int, i, i + 1)
}
}
}
}
③插入法排序
func insertSort(arr []int){
for i := 1; i < len(arr); i++ {
for j := i - 1; j >= 0; j-- {
if arr[j] > arr[j + 1]{
swap(arr, j, j + 1)
}
}
}
}
(2)基于Big-O(n * log(n))的排序
①快速排序 空间复杂度O(log n), 不稳定
① quickSort(arr []int, L int, R int); 运用了分而治之的思想 ,对partition操作之后对返回的数组的左边和右边继续分而治之,从局部有序到整体有序的过程。
② partition(arr []int, L int, R int ) 思想就是比较,有less区域和more区域,less区 域都是小于参考值的,more区域都是大于参考值的。所以可以这样操作: 移动 L 和 more,L 从0 开始,满足条件往右移动, more从R开始满足条件往左移动。当 L < more 时 :(1)若 arr [L] < arr[R] { less++, swap(arr, less, L), L++} (2) 若arr [L] > arr[R] { more-- , swap(arr, more, L)} (3) 若arr[L] == arr[R] {L++}; ,最后返回partition的数组的下标。
import (
"fmt"
"math/rand"
"time"
)
func quickSort(arr []int, L int, R int) {
if(L < R){
lF, rF := float32(L), float32(R)
rand.Seed(time.Now().UnixNano())
randomIndex := int(lF + rand.Float32() * (rF - lF + 1))//数组中随机获取下标
swap(arr, randomIndex, R)
var p []int = partition(arr, L, R) //partition操作返回p[0]和p[1]
quickSort(arr, L, p[0] - 1) //p[0]-1为随机下标对应的值的左边
quickSort(arr, p[1] + 1, R) //p[1]+1为随机下标对应的值的右边
}
}
func partition(arr []int, L int, R int) []int {
less, more := L - 1, R //less区域为小于随机下标对应的值,more区域为大于随机下标对应的值
for L < more {
if arr[L] < arr[R] {
less++
swap(arr, less, L)
L++
} else if arr[L] > arr[R]{
more--
swap(arr, more, L)
} else {
L++
}
}
swap(arr, more, R)
return []int {less + 1, more}
}
②归并排序 空间复杂度O(n),稳定
① process(arr []int, L int, R int); 递归使用了二分思想,即 (L, Mid) 进行merge,(Mid + 1, R)进行merge,最后整体(L, R) 进行merge 。
② merge(arr []int, L int, Mid int, R int) 借助辅助空间,(L, Mid)和(Mid + 1, R)中谁小谁进辅助空间,辅助空间就形成局部有序,最后到整体有序。
func mergeSort(arr []int, L int, Mid int, R int) {
if len(arr) < 2 {
return
}
help := make([]int, 0, R - L + 1)
p1, p2 := L, Mid + 1
for p1 <= Mid && p2 <= R {
if arr[p1] <= arr[p2] {
help = append(help, arr[p1])
p1++
} else {
help = append(help, arr[p2])
p2++
}
}
for p1 <= Mid {
help = append(help, arr[p1])
p1++
}
for p2 <= R {
help = append(help, arr[p2])
p2++
}
for i := 0; i < len(help); i++ {
arr[L + i] = help[i]
}
}
③堆排序(优先队列)
①heapInsert(arr []int, index int) 建立大根堆,(index * 2) + 1为该节点左孩子,(index * 2) + 2 为该节点右孩子,(index - 1) / 2 为该节点的父节点。若该节点大于父节点,就交换,并且index = (index - 1) / 2。
②heapify(arr []int, index int, heapSize int), 找到最后一个节点lastNode,该节点与当前根节点交换,同时heap--,即最后位置上为最大值,根节点为极小值。此时从根结点出发,继续heapify的过程(左孩子右孩子较大者与根节点交换, lastNode节点 来到孩子节点较大者位置,继续左右孩子较大者比较,直至没有左右孩子)
func heapInsert(arr []int, index int){
for arr[index] > arr[(index - 1) / 2] {
swap(arr, index, (index - 1) / 2)
index = (index - 1) / 2
}
}
//index * 2 + 1 左孩子节点
//index * 2 + 2 右孩子节点
//(index - 1) / 2 父节点
func heapify(arr []int, index int, heapSize int){
var largestIndex int
leftNode := index * 2 + 1
for leftNode < heapSize {
if leftNode + 1 < heapSize && arr[leftNode + 1] > arr[leftNode] {
largestIndex = leftNode + 1
} else {
largestIndex = leftNode
}
if arr[largestIndex] < arr[index] {
largestIndex = index
}
if largestIndex == index {
break
}
swap(arr, largestIndex, index)
index = largestIndex
leftNode = index * 2 + 1
}
}
二、基本查找
(1)基于Big-O(log(n))的查找
①二分查找
func binarySearch(nums []int, target int) int {
left, right := 0, len(nums) - 1
for left <= right {
Mid := left + (right - left) >> 1
if nums[Mid] == target {
return Mid
} else if nums[Mid] > target {
right = Mid - 1
} else {
left = Mid + 1
}
}
return left
}