「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」
三言两语
搞懂基础算法系列之排序算法-归并排序
关键点:时间复杂度 O(n*logn)。
一道算法题
首先从一个案例入手。
题目:两个有序数组,输出一个升序的数组
例子:ary1 = {4, 6, 7} , ary2 = {1, 3, 10, 19} 输出结果:{1, 3, 4, 6, 7, 10, 19}
通过分别取出数组值进行比较,因其已经是2个有序的数组,所以每个数组里要么升序要么降序,分别取出数组的值进行比较时,谁小就放入新的数组中newAry =[]
1、ary1[0] > ary2[0] , 则将数组ary2[0] 值放入新数组中,然后数组ary2位置往后移动一位,newAry = [1];
2、ary1[0] > ary2[1], 则将数组ary2[1] 值放入新数组中,然后数组ary2位置往后移动一位,newAry = [1, 3];
3、ary1[0] < ary2[2], 则将数组ary1[0] 值放入新数组中,然后数组ary1位置往后移动一位,newAry = [1, 3, 4];
4、ary1[1] < ary2[2], 则将数组ary1[1] 值放入新数组中,然后数组ary1位置往后移动一位,newAry = [1, 3, 4, 6];
5、ary1[2] < ary2[2], 则将数组ary1[2] 值放入新数组中,然后数组ary1位置往后移动一位,newAry = [1, 3, 4, 6,7];
6、ary1已全部都遍历完成,说明剩余ary2的值都是比ary1值大,所以可以将最后剩余的ary2值都放入新的数组,newAry=[1,3,4,6,7,10,19]
JavaScript实现上述过程
// 2个有序的数组合并成1个升序数组
function sortGuibing(ary1, ary2) {
let newAry = []
let i = 0, j = 0;
do {
if (ary1[i] >= ary2[j]) {
newAry.push(ary2[j]);
j++;
} else {
newAry.push(ary1[i]);
i++;
}
if (i == ary1.length && j < ary2.length) newAry = newAry.concat(ary2.slice(j, ary2.length))
if (j == ary2.length && i < ary1.length) newAry = newAry.concat(ary1.slice(i, ary1.length))
} while (i < ary1.length && j < ary2.length)
console.log(newAry)
}
Golang实现上述过程
// 2个有序的数组合并成1个升序数组
func sortGuibing(ary1, ary2 []int) {
newAry := make([]int, 0)
i := 0
j := 0
for i < len(ary1) && j < len(ary2) {
if ary1[i] > ary2[j] {
newAry = append(newAry, ary2[j])
j++
} else {
newAry = append(newAry, ary1[i])
i++
}
if i == len(ary1) && j < len(ary2) {
newAry = append(newAry, ary2[j:len(ary2)-1]...)
}
if j == len(ary2) && i < len(ary1) {
newAry = append(newAry, ary1[i:len(ary1)-1]...)
}
}
for _, v := range newAry {
fmt.Print(v, ",")
}
}
归并排序
归并排序,将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序
所以归并排序的前提是:需要已经排好序的子序列。
采用:分而治策略。
算法思路
题目:给某数组进行排序
解题思路:将数组拆分成2个数组,分别对2个数组进行排序,再归并成一个新的数组;如果拆分的2个数组无序,还可以继续分别对2个数组继续拆分再归并;就这样,重复递归这个过程,直到合并成一个有序的数组。
Golang实现
// 归并算法 -- 分而治(递归该过程)
func sortGuibing(ary []int) {
sortGuibing_sortAry(ary, 0, len(ary)-1)
for _, v := range ary {
fmt.Print(v, ",")
}
}
/**
* lary数组第一位
* rary数组最后一位
**/
func sortGuibing_sortAry(ary []int, lary int, rary int) {
if lary == rary { //只有一个元素,则直接返回
return
} else {
// 取中间值
mid := (lary + rary) / 2
sortGuibing_sortAry(ary, lary, mid) // 左边持续拆分
sortGuibing_sortAry(ary, mid+1, rary) // 右边持续拆分
sortGuibing_mergeAry(ary, lary, mid+1, rary)
}
}
func sortGuibing_mergeAry(ary []int, lary, mid, rary int) {
ldata := ary[lary:mid]
rdata := ary[mid+1 : rary]
i := 0
j := 0
k := lary
for i < len(ldata) && j < len(rdata) {
if ldata[i] > rdata[j] {
ary[k] = rdata[j]
j++
k++
} else {
ary[k] = ldata[i]
i++
k++
}
}
if i == len(ldata) && j < len(rdata) { //左边数组已遍历完,右边数据还有,剩余数据可直接添加到数组内
for _, v := range rdata[j:] {
ary[k] = v
k++
}
}
if j == len(ldata) && i < len(rdata) { //右边数组已遍历完,左边数据还有,剩余数据可直接添加到数组内
for _, v := range ldata[i:] {
ary[k] = v
k++
}
}
}
JavaScript实现
function sortGuibing(ary) {
sortGuibing_sort(ary, 0, ary.length - 1)
console.log(ary)
}
function sortGuibing_sort(ary, llen, rlen) {
if (llen == rlen) return;
let mid = Math.floor((llen + rlen) / 2 ,0);
sortGuibing_sort(ary, llen, mid);
sortGuibing_sort(ary, mid + 1, rlen);
sortGuibing_merge(ary, llen, mid+1, rlen);
}
function sortGuibing_merge(ary, llen, mid, rlen) {
let ldata = ary.slice(llen, mid);
let rdata = ary.slice(mid + 1, rlen);
let i = 0, j = 0;
let k = llen;
while (i < ldata.length && j < rdata.length) {
if (ldata[i] >= rdata[j]) {
ary[k] = rdata[j]
j++;
k++;
} else {
ary[k] = ldata[i]
i++;
k++;
}
if (i == ldata.length && j < rdata.length) {
rdata.forEach((v, m) => {
if (m >= j) {
ary[k] = v;
k++;
}
});
}
if (j == rdata.length && i < ldata.length) {
ldata.forEach((v, m) => {
if (m >= j) {
ary[k] = v;
k++;
}
});
}
}
}