912. 排序数组
给你一个整数数组 nums
,请你将该数组升序排列。
示例 1:
输入:nums = [5,2,3,1]
输出:[1,2,3,5]
示例 2:
输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]
提示:
1 <= nums.length <= 5 * 104
-5 * 104 <= nums[i] <= 5 * 104
冒泡排序,
比较交换,稳定算法,时间O(n^2), 空间O(1)
每一轮遍历,将该轮最大值放到后面,同时小的往前冒
从而形成后部是有序区
compare and swap
1 2 3 4 5 6 7 8 9 10 11
| func sortArray(nums []int) []int { for i:=0;i<len(nums);i++ { for j:=1;j<len(nums)-i;j++ { if nums[j-1] > nums[j] { nums[j-1], nums[j] = nums[j], nums[j-1] } } } return nums }
|
选择排序
比较交换,不稳定算法,时间O(n^2),空间O(1)
每一轮遍历,该轮的最小值前挪,从而形成前面部分是有序区
compare and swap
1 2 3 4 5 6 7 8 9 10 11
| func sortArray(nums []int) []int { for i:=0;i<len(nums);i++ { for j:=i+1;j<len(nums);j++ { if nums[i] > nums[j] { nums[i], nums[j] = nums[j], nums[i] } } } return nums }
|
插入排序
比较交换,稳定算法,时间O(n^2),空间O(1)
0->len方向,每轮从后往前比较,相当于找到合适位置,插入进去
数据规模小的时候,或基本有序,效率高
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| func sortArray(nums []int) []int { n := len(nums) for i := 1; i < n; i++ { tmp := nums[i] j := i - 1 for j >= 0 && nums[j] > tmp { nums[j+1] = nums[j] j-- } nums[j+1] = tmp } return nums }
|
希尔排序
比较交换,不稳定算法,时间O(nlog2n)最坏O(n^2), 空间O(1)
改进插入算法
每一轮按照间隔插入排序,间隔依次减小,最后一次一定是1
主要思想: 设增量序列个数为k,则进行k轮排序。每一轮中, 按照某个增量将数据分割成较小的若干组, 每一组内部进行插入排序;各组排序完毕后, 减小增量,进行下一轮的内部排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| func sortArray(nums []int) []int { gap := len(nums)/2 for gap > 0 { for i:=gap;i<len(nums);i++ { j := i for j-gap >= 0 && nums[j-gap] > nums[j] { nums[j-gap], nums[j] = nums[j], nums[j-gap] j -= gap } } gap /= 2 } return nums }
|
归并排序
基于比较,稳定算法,时间O(nlogn),空间O(logn) | O(n)
基于递归的归并-自上而下的合并,另有非递归法的归并(自下而上的合并)
都需要开辟一个大小为n的数组中转
将数组分为左右两部分,递归左右两块,最后合并,即归并
如在一个合并中,将两块部分的元素,遍历取较小值填入结果集
类似两个有序链表的合并,每次两两合并相邻的两个有序序列,直到整个序列有序
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| func sortArray(nums []int) []int { merge := func(left, right []int) []int { res := make([]int, len(left)+len(right)) var l,r,i int for l < len(left) && r < len(right) { if left[l] <= right[r] { res[i] = left[l] l++ } else { res[i] = right[r] r++ } i++ } copy(res[i:], left[l:]) copy(res[i+len(left)-l:], right[r:]) return res } var sort func(nums []int) []int sort = func(nums []int) []int { if len(nums) <= 1 { return nums } mid := len(nums)/2 left := sort(nums[:mid]) right := sort(nums[mid:]) return merge(left, right) } return sort(nums) }
func sortArray(nums []int) []int { if len(nums) <= 1 { return nums } merge := func(left, right []int) []int { res := make([]int, len(left)+len(right)) var l,r,i int for l < len(left) && r < len(right) { if left[l] <= right[r] { res[i] = left[l] l++ } else { res[i] = right[r] r++ } i++ } copy(res[i:], left[l:]) copy(res[i+len(left)-l:], right[r:]) return res } i := 1 res := make([]int, 0) for i < len(nums) { j := 0 for j < len(nums) { if j+2*i > len(nums) { res = merge(nums[j:j+i], nums[j+i:]) } else { res = merge(nums[j:j+i], nums[j+i:j+2*i]) } index := j for _, v := range res { nums[index] = v index++ } j = j + 2*i } i *= 2 } return nums }
|
快速排序
基于比较,不稳定算法,时间平均O(nlogn),最坏O(n^2),空间O(logn)
分治思想,选主元,依次将剩余元素的小于主元放其左侧,大的放右侧
取主元的前半部分和后半部分进行同样处理,直至各子序列剩余一个元素结束,排序完成
小规模数据(n<100),由于快排用到递归,性能不如插排
进行排序时,可定义阈值,小规模数据用插排,往后用快排
golang的sort包用到了快排
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| func sortArray(nums []int) []int { var quick func(nums []int, left, right int) []int quick = func(nums []int, left, right int) []int { if left > right { return nil } i, j, pivot := left, right, nums[left] for i < j { for i < j && nums[j] >= pivot { j-- } for i < j && nums[i] <= pivot { i++ } nums[i], nums[j] = nums[j], nums[i] } nums[i], nums[left] = nums[left], nums[i] quick(nums, left, i-1) quick(nums, i+1, right) return nums } return quick(nums, 0, len(nums)-1) }
|
堆排序
大根堆,升序排序,基于比较交换的不稳定算法,时间O(nlogn),空间O(1)-迭代建堆
遍历元素时间O(n),堆化时间O(logn),开始建堆次数多些,后面次数少
1.建堆,从非叶子节点开始依次堆化,注意逆序,从下往上堆化
建堆流程:父节点与子节点比较,子节点大则交换父子节点,父节点索引更新为子节点,循环操作
2.尾部遍历操作,弹出元素,再次堆化
弹出元素排序流程:从最后节点开始,交换头尾元素,由于弹出,end–,再次对剩余数组元素建堆,循环操作
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
| func sortArray(nums []int) []int { var heapify func(nums []int, root, end int) heapify = func(nums []int, root, end int) { for { child := root*2 + 1 if child > end { return } if child < end && nums[child] <= nums[child+1] { child++ } if nums[root] > nums[child] { return } nums[root], nums[child] = nums[child], nums[root] root = child } } end := len(nums)-1 for i:=end/2;i>=0;i-- { heapify(nums, i, end) } for i:=end;i>=0;i-- { nums[0], nums[i] = nums[i], nums[0] end-- heapify(nums, 0, end) } return nums }
|
桶排序
基于哈希思想的外排稳定算法,空间换时间,时间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 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| func sortArray(nums []int) []int { var bucket func(nums []int, bucketSize int) []int bucket = func(nums []int, bucketSize int) []int { if len(nums) < 2 { return nums } minAndMax := func(nums []int) (min, max int) { minNum := math.MaxInt32 maxNum := math.MinInt32 for i:=0;i<len(nums);i++ { if nums[i] < minNum { minNum = nums[i] } if nums[i] > maxNum { maxNum = nums[i] } } return minNum, maxNum } min_, max_ := minAndMax(nums) bucketCount := (max_-min_)/bucketSize + 1 buckets := make([][]int, bucketCount) for i:=0;i<bucketCount;i++ { buckets[i] = make([]int, 0) } for i:=0;i<len(nums);i++ { bucketNum := (nums[i]-min_) / bucketSize buckets[bucketNum] = append(buckets[bucketNum], nums[i]) } index := 0 for _, bucket := range buckets { sort.Slice(bucket, func(i, j int) bool { return bucket[i] < bucket[j] }) for _, num := range bucket { nums[index] = num index++ } } return nums } var bucketSize int = 2 return bucket(nums, bucketSize) }
|
计数排序
基于哈希思想的稳定外排序算法,空间换时间,时间O(n),空间O(n)
数据量大时,空间占用大
空间换时间,通过开辟额外数据空间存储索引号记录数组的值和数组额个数
1.找出待排序的数组的最大值和最小值
2.创建数组存放各元素的出现次数,先于[min, max]之间
3.统计数组值的个数
4.反向填充数组,填充时注意,num[i]=j+mi
j-前面需要略过的数的个数,两个维度,依次递增的数j++,一个是重复的数的计数j-不变
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
| func sortArray(nums []int) []int { if len(nums) == 0 { return nums } minAndMax := func(nums []int) (min,max int) { minNum := math.MaxInt32 maxNum := math.MinInt32 for i:=0;i<len(nums);i++ { if nums[i] < minNum { minNum = nums[i] } if nums[i] > maxNum { maxNum = nums[i] } } return minNum, maxNum } min_, max_ := minAndMax(nums) tmpNums := make([]int, max_-min_+1) for i:=0;i<len(nums);i++ { tmpNums[nums[i]-min_]++ } j := 0 for i:=0;i<len(nums);i++ { for tmpNums[j] == 0 { j++ } nums[i] = j + min_ tmpNums[j]-- } return nums }
|