二分插入合并有序数组
题目
两个从小到大有序的整型数组A和B,将其合并为C,仍保持从小到大有序
const [A, B] = [[1, 3, 5, 7],[2, 4, 6, 8]]
// 合并C = 【1, 2, 3, 4, 5, 6, 7, 8】
es6实现
const C = [...A, ...B].sort((a, b) => a - b)
二分法插入排序
要求:用二分法插入排序的方式实现
概念
二分法插入排序,简称二分排序,是在插入第i个元素时,对前面的0~i-1元素进行折半,先跟他们中间的那个元素比,如果小,则对前半再进行折半,否则对后半进行折半,直到left<right,然后再把第i个元素前1位与目标位置之间的所有元素后移,再把第i个元素放在目标位置上。
编码
1.编写函数merged(),遍历待插入数组,依次调用插入方法插入目标数组arr
function merged(a, b) {
const arr = [...a] //避免修改原数组
for (const num of b){
insertBtoA(arr, num) // 合并元素到数组的方法
}
return arr
}
2.编写insertBtoA函数,已知arr为有序数组,利用二分插入排序法将目标元素插入到数组中
function insertBtoA(arr, target) {
let left = 0
let right = arr.length - 1
let mid = Math.floor(arr.length - 1 / 2)
while(left <= right) { // 查找结束条件
mid = left + Math.floor((right - left) / 2)
if (arr[mid] === target) {
// 相等可直接插入
arr.splice(mid, 0, target)
return
} else if (arr[mid] > target) {
// 目标元素需插入到前半段
right = mid - 1
} else {
// 目标元素与需插入到后半段
left = mid + 1
}
}
arr.splice(left, 0, target)
}
3.调用merged方法
const C = merged(A,B)
console.log(C) // [1, 2, 3, 4, 5, 6, 7, 8]
优化
根据已知条件B也为有序数组,可知迭代插入的下一个目标元素都在本次目标元素的右侧,所以可以返回left当做下次迭代的初始left
编码
1.修改insertBtoA方法,返回left
function insertBtoA(arr, target, left) {
let right = arr.length - 1
let mid = Math.floor(arr.length - 1 / 2)
while(left <= right) { // 查找结束条件
mid = left + Math.floor((right - left) / 2)
if (arr[mid] === target) {
// 相等可直接插入
arr.splice(mid, 0, target)
return ++mid // 因为上一步已将target插入目标数组,且已知target所在数组为有序数组,故下一个target直接将mid+1作为初始left
} else if (arr[mid] > target) {
// 目标元素需插入到前半段
right = mid - 1
} else {
// 目标元素与需插入到后半段
left = mid + 1
}
}
arr.splice(left, 0, target)
return ++left //因为上一步已将target插入目标数组,且已知target所在数组为有序数组,故下一个target直接将left+1作为初始left
}
2.修改merged方法,获取返回left传入下次迭代调用insertBtoA中
function merged(a, b) {
const arr = [...a] //避免修改原数组
let left = 0
for (const num of b){
console.log('本次初始left:' + left)
left = insertBtoA(arr, num, left) // 合并元素到数组的方法
}
return arr
}
3.调用merged方法
const C = merged(A,B)
console.log(C)
// 本次初始left:0
// 本次初始left:2
// 本次初始left:4
// 本次初始left:6
// [1, 2, 3, 4, 5, 6, 7, 8]
如果是多个有序数组的合并排序呢
已知二维数组如下:
const D = [[1, 5, 9, 12],[2, 4, 4, 8],[0, 3, 11, 19]]
// 求 C = [0,1,2,3,4,4,5,8,9,11,12,19]
// es6
// const C = D.flat().sort((a, b) => a - b)
思路
借助es6数组方法reduce,将子元素数组依次调用前面二分插入合并的方法
编码
1.reduce迭代
const C = D.reduce((a, b) => {
return merged(a, b)
})
2.完整代码
const D = [[1, 5, 9, 12],[2, 4, 4, 8],[0, 3, 11, 19]]
function merged(a, b) {
const arr = [...a] //避免修改原数组
let left = 0
for (const num of b){
console.log('本次初始left:' + left)
left = insertBtoA(arr, num, left) // 合并元素到数组的方法
}
return arr
}
function insertBtoA(arr, target, left) {
let right = arr.length - 1
let mid = Math.floor(arr.length - 1 / 2)
while(left <= right) { // 查找结束条件
mid = left + Math.floor((right - left) / 2)
if (arr[mid] === target) {
// 相等可直接插入
arr.splice(mid, 0, target)
return ++mid // 因为上一步已将target插入目标数组,且已知target所在数组为有序数组,故下一个target直接将mid+1作为初始left
} else if (arr[mid] > target) {
// 目标元素需插入到前半段
right = mid - 1
} else {
// 目标元素与需插入到后半段
left = mid + 1
}
}
arr.splice(left, 0, target)
return ++left //因为上一步已将target插入目标数组,且已知target所在数组为有序数组,故下一个target直接将left+1作为初始left
}
const C = D.reduce((a, b) => {
return merged(a, b)
})
console.log(C) // [0, 1, 2, 3, 4, 4, 5, 8, 9, 11, 12, 19]