排序算法
1. 快排
中点左边、右边分别小于(大于)中点值,
分治依次处理左子区域,右子区域
方法
1、挖坑填数
坑的概念:
临时空位,用来即将放左边index最靠近mid的一个小于mid的值或者右边index最靠近mid的一个大于mid的值。
右指针找到不合适的,直接与左指针的坑交换,右指针变为坑,
左指针找到不合适的,与右指针那个坑再交换,左指针变成坑
重复,直到左指针=右指针
func quickSort(arr,l,r) {
midval
while(lptr < rptr) {
while(lptr < rptr && arr[rptr] >= midval) {
rptr--
}
swap(arr[lptr],arr[rptr])
while(lptr < rptr && arr[lptr] <= midval) {
lptr++
}
swap(arr[lptr],arr[rptr])
}
quickSort(arr,l,lptr-1)
quickSort(arr,lptr+1,r)
}
2、左右交换法
在挖坑的基础上改造
双指针向中间收缩,右边、左边同时找第一个不满足的
如果lptr < rptr 则直接交换左右指针对应的值,这样两个指针的值就由同时不满足变为同时满足
临界:
两指针重合,则直接交换arr[l]与arr[lptr],因为:
重合必然是第一个子循环右指针往里缩的时候与左指针重合,此时重合点为上次循环中lptr的交换点,lptr对应的值小于mid,arr[l]必然大于arr[lptr],所以直接交换arr[l]与arr[lptr]即可
func quickSort(arr,l,r) {
midval
while(lptr < rptr) {
while(lptr < rptr && arr[rptr] >= midval) {
rptr--
}
// swap(arr[lptr],arr[rptr])
while(lptr < rptr && arr[lptr] <= midval) {
lptr++
}
swap(arr[lptr],arr[rptr])
}
swap(arr[l],arr[lptr])
quickSort(arr,l,lptr-1)
quickSort(arr,lptr+1,r)
}
2. 归并排序
先分治,再排序
func mergeSort(arr,l,r) {
if l >= r {
return
}
n = r - l + 1
midInd = (l + r) >> 1
mergeSort(arr,l,midInd)
mergeSort(arr,midInd+1,r)
// 注意:这里要用临时数组,而不能用原数组直接写,否则会被覆盖
tArr := []int(n)
p1 ,p2,p = l,midInd+1,0
while(p1 <= midInd && p2 <= r) {
if arr[p1] <= arr[p2] {
tArr[p++] = arr[p1++]
} else {
tArr[p++] = arr[p2++]
}
}
for i = p1; i <= midInd; ++i {
tArr[p++] = arr[i]
}
for i = p2; i <= r; ++i {
tArr[p++] = arr[i]
}
copy(tArr,arr[l,r])
}
二分
二分区域中等于target值的左边界
func split(arr[]int,l,r int, target int) int {
while l < r {
// 偏左的值
// [0,1] 中的0
mid = (l + r) >> 1
midval = arr[mid]
// 相同的值则由于mid偏左,所以r=mid=左移,也不会死循环
// 此时若相等,因为要验证左边界,所以剩下的区域只可能在左边,因此右边界可以确定下来是mid
if midval >= target {
r = mid
} else {
// 当前值过小,肯定不符,左边界直接在mid的基础上右移一个就好
l = mid + 1
}
}
// 退出循环,则l==r,此时直接判断arr[l]的值即可
if arr[l] == target {
// 找到左边界
return l
} else {
// arr中没有target值
return -1
}
}
二分区域中等于target值的右边界
func split(arr[]int,l,r int, target int) int {
while l < r {
// 注意:此处与上面求左边界不同,需要偏右
mid = (l + r + 1) >> 1
midval = arr[mid]
// 注意,此处与上面求左边界不同
if midval <= target {
l = mid
} else {
// 注意
r = mid - 1
}
}
// 退出循环,则l==r,此时直接判断arr[l]的值即可
if arr[l] == target {
// 找到右边界
return l
} else {
// arr中没有target值
return -1
}
}