冒泡排序
大的元素往上冒
1
2
3
4
5
6
7
8
9
  | 
func bubblingSort(nums []int) {
	for i := 0; i < len(nums); i++ {
		for j := 0; j < len(nums)-i-1; j++ {
			if nums[j] > nums[j+1] {
				nums[j], nums[j+1] = nums[j+1], nums[j]
			}
		}
	}
}
  | 
 
特点:稳定
选择排序
每次选择剩余元素的最小数,与剩余元素的第一个位置交换。
- 
从0,1,2…n-1位置中选择最小元素arr[minI]与arr[0]交换
 
- 
从1,2…n-1位置中选择最小元素arr[minI]与arr[1]交换
…
 
- 
从n-2,n-1位置中选择最小元素arr[minI]与arr[n-1]交换
 
- 
结束排序
 
特点:稳定
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  | 
func selectSort(nums []int) {
	for i := 0; i < len(nums); i++ {
		minI := i
		for j := i + 1; j < len(nums); j++ {
			if nums[minI] > nums[j] {
				minI = j
			}
		}
		nums[i], nums[minI] = nums[minI], nums[i]
	}
}
  | 
 
插入排序
将元素插入有序数列。
- 
有序列表arr[0:1] , 无序列表arr[1:n]
- 取arr[1]暂存到t,将t与arr[0]比较,若比t大,则将arr[0]=arr[1],空出位置0,arr[0] = t; 否则arr[1]=t
 
 
- 
有序列表arr[0:2] , 无序列表arr[2:n]
- 取arr[2]暂存到t,若t<arr[1],则arr[2]=arr[1],空出位置2,继续下一步操作;否则arr[2]=t,结束。
 
- 将t与arr[0]比较,若t<arr[0],则arr[1]=arr[0],空出位置0,arr[0] = t;否则arr[1]=t,结束。
 
…
 
- 
有序列表arr[0:n-1] , 无序列表arr[n-1:n]
- 
取arr[n-1]暂存到t, 若t<arr[n-2],则arr[n-1]=arr[n-2],空出位置n-2,继续下一步;否则arr[n-1]=t,结束操作
 
- 
若t<arr[n-3],则arr[n-2]=arr[n-3],空出位置n-3,继续下一步;否则arr[n-2]=t
…
 
- 
若t<arr[1],则arr[2]=arr[1],空出位置1,继续下一步;否则arr[2]=t,结束操作
 
- 
若t<arr[0],则arr[1]=arr[0],空出位置0,arr[0]=t,结束操作;否则arr[1]=t,结束操作
 
 
- 
结束。 有序列表arr[0:n] , 无序列表arr[n:n]。
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  | 
func insertSort(nums []int) {
	t := 0
	j := 0
	for i := 1; i < len(nums); i++ {
		t = nums[i]
		j = 0
		for j = i - 1; j >= 0; j-- {
			if nums[j] > t {
				nums[j+1] = nums[j]
			} else {
				break
			}
		}
		nums[j+1] = t
	}
}
  | 
 
希尔排序
跟插入相同,只不过加入了步长控制,
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  | 
func shellSort(nums []int) {
	for step := len(nums) >> 1; step > 0; step >>= 1 {
		for i := step; i < len(nums); i += step {
			t := nums[i]
			j := 0
			for j = i - step; j >= 0; j -= step {
				if t < nums[j] {
					nums[j+step] = nums[j]
				} else {
					break
				}
			}
			nums[j+step] = t
		}
	}
}
  | 
 
特点: 不稳定
归并排序
分治法。将两个有序的数列合并
- 复杂度为$$O(n+n/2+n/4….+1)$$   简略为 $$nlog_2n$$ ,
 
- 空间复杂度为 O(n)
 
- 递归消耗空间复杂度  $$ log_2n $$
 
- 稳定性: 否
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  | 
func mergeSort(nums []int) {
	if len(nums) <= 1 {
		return
	}
	mid := len(nums) / 2
	mergeSort(nums[0:mid])
	mergeSort(nums[mid:len(nums)])
  //merge
	tempArray := make([]int, len(nums))
	copy(tempArray, nums)
	left := 0
	right := mid
	i := 0
	for left < mid && right < len(nums) {
		if tempArray[left] <= tempArray[right] {
			nums[i] = tempArray[left]
			left++
		} else {
			nums[i] = tempArray[right]
			right++
		}
		i++
	}
	for left < mid {
		nums[i] = tempArray[left]
		i++
		left++
	}
	for right < len(nums) {
		nums[i] = tempArray[right]
		i++
		right++
	}
}
  | 
 
快速排序
分治法。每次循环pivot归位。pivot的选择会影响时间和递归空间
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  | 
func quickSort(nums []int) {
	if len(nums) <= 1 {
		return
	}
	pivot := nums[0]
	left := 0
	right := len(nums) - 1
	for left < right {
		for left < right && nums[right] > pivot {
			right--
		}
		if left < right {
			nums[left] = nums[right]
			left++
		}
		for left < right && nums[left] < pivot {
			left++
		}
		if left < right {
			nums[right] = nums[left]
			right--
		}
	}
	nums[left] = pivot
	quickSort(nums[0:left])
	quickSort(nums[left+1:])
}
  | 
 
堆排序
- 
什么是堆?
堆通常是一个可以被看做一棵完全二叉树的数组对象。
 
- 
最大堆、最小堆?
最大堆,父节点的值大于等于子节点。
最小堆,父节点的值小于等于子节点。
 
- 
如何维护某个节点子树的最大堆?
每次某个节点的值发生变化后,都要对其所在子树从上往下调整堆(序号小的到大的)。为什么是上往下?因为最大堆的某个节点换成较小值后只影响其子树的变化,故需要继续往下调整。
 
- 
如何建立堆?
从下往上即根节点递减调整每一个节点的堆,因为这才能保证下层的最堆的根节点小于其父节点。
 
- 
堆排序算法
如输入数组A[0…n]
 
- 建立最大堆,最大的元素在根节点
 
- 根节点的值与A[n]互换位置,即剩余最大元素归位
 
- n–,将A[n]从堆中移出
 
- 调整堆为最大堆,重复2~3,直到堆的长度为1,此时的元素全部归位
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  | 
func heapSort(nums []int) {
	buildMaxHeap(nums)
	heapSize := len(nums)
	for i := len(nums) - 1; i >= 1; i-- {
		nums[0], nums[i] = nums[i], nums[0]
		heapSize--
		maxHeapify(nums, 0, heapSize)
	}
}
//下往上建立堆
func buildMaxHeap(nums []int) {
	heapSize := len(nums)
	for i := heapSize>>1 - 1; i >= 0; i-- {
		maxHeapify(nums, i, heapSize)
	}
}
//上往下调整堆
func maxHeapify(nums []int, i int, heapSize int) {
	for {
		maxI := i
		leftChildI := i<<1 + 1
		rightChildI := leftChildI + 1
		if leftChildI < heapSize && nums[leftChildI] > nums[maxI] {
			maxI = leftChildI
		}
		if rightChildI < heapSize && nums[rightChildI] > nums[maxI] {
			maxI = rightChildI
		}
		if i == maxI {
			break
		}
		nums[i], nums[maxI] = nums[maxI], nums[i]
		i = maxI
	}
}
  | 
 
计数排序
顾名思义,就是统计元素个数,然后填充列表。如 [1,2,4,1,3],1的个数为2,2的个数为1,4的个数为1,3的个数为1,后依次填充列表。为了保证稳定性,需要有所处理
为了化简,输入限制为非负数。
- 复杂度为O(n*2+k*2) ,n为元素个数,k为数组长度
 
- 稳定性:是(需要特殊处理)
 
- 空间复杂度:O(n+k)
 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  | 
func countingSort(nums []int) {
	max := nums[0]
	for i := 1; i < len(nums); i++ {
		if max < nums[i] {
			max = nums[i]
		}
	}
	countTable := make([]int, max+1)
	for i := 0; i < len(nums); i++ { //整数范围k
		countTable[nums[i]]++
	}
  // 为了保证稳定
	for i := 1; i < len(countTable); i++ { //整数范围k
		countTable[i] += countTable[i-1]
	}
	copyNums := append([]int{}, nums...)
	for i := len(nums) - 1; i >= 0; i-- { //输出长度n
		nums[countTable[copyNums[i]]-1] = copyNums[i]
		countTable[copyNums[i]]--
	}
}
  | 
 
桶排序
基数排序