基础算法-排序|归并排序

374 阅读1分钟

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,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++;
        }
      });
    }
  }
}