js数据结构与算法_15_基于快排的二分查找

二分查找加快速排序

了解二分查找

二分查找大家应该都比较熟悉,每次去除一半的的查找范围,平均时间复杂度O(log n);
搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半;
二分查找的数组一定得是有序的,所以这次我的标题是基于快排的二分查找,当然你也可以基于插入排序、计数排序、选择排序等等,这里我们用经典的快排,
步骤:
(1) 将数组的第一个位置设置为下边界(0)。
(2) 将数组最后一个元素所在的位置设置为上边界(数组的长度减 1)。
(3) 若下边界等于或小于上边界,则做如下操作。
a. 将中点设置为(上边界加上下边界)除以 2。
b. 如果中点的元素小于查询的值,则将下边界设置为中点元素所在下标加 1。
c. 如果中点的元素大于查询的值,则将上边界设置为中点元素所在下标减 1。
d. 否则中点元素即为要查找的数据,可以进行返回。
快排的实现我往期文章里有,这里就不细说了;

实现二分查找

有时候我们不希望改变原数组的排列顺序,所以我加了个参数orderly,为true的时候,传入的原始数组就会变为有序数组,为false的时候,就不会改变原数组,一样为进行查找,但是得到的结果index会有问题,因为它是基于有序数组的,我打算的是orderly为false时接入顺序查找;

// 快排
function quickSort(array) {
  function swap(array, m, n) {
    let temp = array[m];
    array[m] = array[n];
    array[n] = temp;
  }
  function getPivot(array, left, right) {
    let center = Math.floor((left + right) / 2);

    // 排序
    if (array[left] > array[center]) {
      swap(array, left, center);
    }
    if (array[left] > array[right]) {
      swap(array, left, right);
    }
    if (array[center] > array[right]) {
      swap(array, center, right);
    }

    swap(array, center, right - 1);

    return array[right - 1];
  }
  function recursion_quickSort(array, left, right) {
    // 结束条件
    if (left >= right) return;
    // 获取枢纽
    let pivot = getPivot(array, left, right);

    // 记录开始位置
    let bigIndex = left;
    let smallIndex = right - 1;

    // 循环查找位置
    while (true) {
      while (array[++bigIndex] < pivot) {}
      while (array[--smallIndex] > pivot) {}
      if (bigIndex < smallIndex) {
        // 表示没重叠,交换两指针指向的元素
        swap(array, bigIndex, smallIndex);
      } else {
        break;
      }
    }

    if (bigIndex != right) swap(array, bigIndex, right - 1);
    // 递归——分而治之
    recursion_quickSort(array, left, bigIndex - 1);
    recursion_quickSort(array, bigIndex + 1, right);
  }

  recursion_quickSort(array, 0, array.length - 1);
  return array;
}
// 使用二分查找,找82
function binSearch(array, num, orderly = true) {
  // 如果orderly为true说明,希望序列发生改变成为有序数组
  newArry = orderly ? quickSort(array) : quickSort([...array]);
  let upperBound = newArry.length - 1;
  let lowerBound = 0;

  while (upperBound >= lowerBound) {
    let mid = ~~((upperBound + lowerBound) / 2);
    if (num > newArry[mid]) {
      lowerBound = mid + 1;
    } else if (num < newArry[mid]) {
      upperBound = mid - 1;
    } else {
      return mid;
    }
  }

  return -1;
}

有没有细心的兄弟发现我这个二分查找的问题,那就是 当查找的是有相同的值的元素时,这只会返回一个索引,那怎么办呢?
but我们得到是索引是在其他相同值的左边或右边,换句话说,从返回的索引向左向右遍历收集相同值的索引,最后返回索引数组即可;
所以这里封装了个indexArray函数,如果没有要查询的值返回-1,有一个或多个返回值都返回索引数组:

function indexArray(array, num) {
  let indexArray = [];
  let position = binSearch(array, num);
  if (position == -1) return -1;
  indexArray.push(position);
  for (let i = position - 1; i >= 0; i--) {
    if (array[i] === num) {
      indexArray.push(i);
    } else {
      break;
    }
  }
  for (let i = position + 1; i < array.length; i++) {
    if (array[i] === num) {
      indexArray.push(i);
    } else {
      break;
    }
  }
  return indexArray;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值