【算法】二分查找,冒泡排序

目录
二分法查找
需求...在有序数组中插入新成员后,仍然是一个有序的数组
冒泡排序
url编码

二分法查找

二分法查找

- 条件:适用于有序的数组 ( 有序 )
- 原理
1. 从 ( 有序数组 ) 的中间元素开始搜索,如果正好是目标元素就返回该元素位置,否则下一步
2. 如果目标元素大于或者小于中间元素,则在数组大于  小于中间元素的那一半数组搜索,然后重复第一步
3. 如果某一步数组为空,表示找不到目标元素,返回 -1
- 单词
  - binary 一半
  - closure 闭包
  - recursive 递归
  - heap 堆
  - stack 栈


- 代码
(1) 非递归算法
const arr = [1, 2, 3, 4, 5, 6]
function binary_search (arr, value) {
  let low = 0
  let heigh = arr.length
  while (low <= heigh) {
    const mid = Math.floor((low + heigh) / 2)
    // - 1. 注意:这里用 Math.floor 或者 Math.ceil 或者 parseInt 都没有影响
    //           因为条件不成立时,都会跳到对应的一半的部分继续寻找
    // - 2. parseInt() 当有小数点的时候,会取整数,舍弃掉小数部分
    if (low === heigh && arr[mid] !== value) {
      return -1 // 当low和height相等,arr[mid]还不等于value,说明value在数组中不存在,返回-1
    }
    switch (true) {
      case arr[mid] === value:
        return mid // 结束掉整个函数,即binary_search, 并且返回mid的值
      case arr[mid] > value:
        heigh = mid  - 1 // 数组中间值大于value,则在前一半的数组中查找,其实这里也可以不减去1,直接 height = mid
        break
      case arr[mid] < value:
        low = mid + 1 // 后一半查找
        break
      default:
        return -1 // 没找到
    }
  }
}
const res = binary_search(arr, 5)
console.log(res)



------
(2) 递归算法1
// 闭包加递归
// 通过闭包改变low和heigh
const arr = [1, 2, 3, 4, 5, 6]
function binary_search (arr, value) {
  let low = 0
  let heigh = arr.length - 1

  const binary_search_closureAndRecursive = function (value) { // 闭包和递归函数,改变low和heigh
    let mid = parseInt((low + heigh) / 2)  // 每次调用重新计算mid
    if ( low > heigh) {
      return -1 // 递归调用结束条件
    }
    switch (true) {
      case arr[mid] === value:
        return mid
      case arr[mid] < value:
        low = mid + 1
        return binary_search_closureAndRecursive(value) //闭包递归函数
      case arr[mid] > value:
        heigh = mid - 1
        return binary_search_closureAndRecursive(value)
      default:
        return -1
    }
  }

  return binary_search_closureAndRecursive(value)
}
const res = binary_search (arr, 5)
console.log(res)


------
(2) 递归算法2
// 通过参数改变low和heigh
const arr = [1, 2, 3, 4, 5, 6]
function binary_search_recursive (arr, value, low, heigh) {
  if (low > heigh) {
    return -1 // 递归结束条件
  }
  const mid = Math.floor((low + heigh) / 2)

  if (arr[mid] === value) {
    return mid
  }
  if (arr[mid] < value) {
    low = mid + 1
    return binary_search_recursive(arr, value, low, heigh)
  }
  if (arr[mid] > value) {
    heigh = mid - 1
    return binary_search_recursive(arr, value, low, heigh)
  }
}
const res = binary_search_recursive(arr, 5, 0, arr.length - 1)
console.log(res)

https://juejin.im/post/5c62dbdfe51d45015a21f32a



如何在有序数组中插入新值,仍然是一个数组?

  • 要返回新插入的成员的下标
sortedIndex([10, 20, 30], 25); // 2


版本一:
function sortedIndex (arr, value) {
  let low = 0
  let heigh = arr.length - 1
  while (low < heigh) {
    // 当low < heigh时,移动low或者height到对应区间的一半
    const mid = parseInt((low + heigh) / 2)
    if (arr[mid] < value) low = mid + 1
    else if (arr[mid] > value) heigh = mid - 1
  }
  if (low === heigh) {
    // 当low和height相当时,需要判断插入和值,和hight或者low位置对应的值
    if (arr[low] > value) {
      // 如果插入值小,说明要插入low或者height位置的前面
      return heigh
    } else {
      // 如果插入大,说明要插入low或者height位置的后面
      return heigh + 1
    }
  }
  return heigh // 当low=heigh时,都还没有确定到位置,说明
}
const res = sortedIndex([10, 20, 30], 15);
console.log(res)
















冒泡排序 (Bubble-Sort)

冒泡排序 (bubble-sort)

1. 趟数 和 每一趟比较的次数
  - 趟数 = 数组长度 - 1
  - 每一趟比较的次数 = 数组长度 - 当前趟数
    // 注意,之所以减去趟数,是因为第一趟确定了一个最大值,第二次确定了第二大的值,不需要再做无畏的比较
2. 
第一趟比较完:即得出最大值,且冒泡到数组末尾 ------------------------------------ 执行次数:数组长度 - 当前趟数
第二趟比较完:即得出第二大的值,且冒泡到数组倒数第二个位置,依次类推 -------------- 执行次数:数组长度 - 当前趟数



3.代码
第一版
// 第一趟
//   第一次 1432 --------------------- 1432
//   第二次 1432 --------------------- 1342
//   第三次 1342 --------------------- 1324 ------------ 趟数1,执行次数 arr.length - 趟数1 = 3
// 第二趟
//   第一次 1324 --------------------- 1324
//   第二次 1324 --------------------- 1234 ------------ 趟数2,执行次数 arr.length - 趟数2 = 2
//   第三次不用再比较了,因为第一次时,已经找到了最大值。
// 第三趟
//   第一次 1234 --------------------- 1234  ------------ 趟数3,执行次数 arr.length - 趟数3 = 1
//   剩下的不用再比较了,因为前面一次已经找到对应的第二大的值了
const arr = [1, 4, 3, 2]
function bubble_sort (arr) {
  // const Arr = JSON.parse(JSON.stringify(arr)) 复制一份不改变原数组
  const len = arr.length - 1
  for (let i = 0; i < len; i++) { ---------------- 趟数 = 数组长度 - 1
    for (let j = 0; j < len - i; j++) { ---------- 每趟比较的次数 = 数组长度 - 当前趟数
      if (arr[j] > arr[j+1]) { ------------------- 如果两两比较的前成员,前 > 后,就交换位置,大的冒泡的后面
        const temp = arr[j]
        arr[j] = arr[j+1]
        arr[j+1] = temp
      }
    }
  }
  return arr // 排好序后,返回
}
const res = bubble_sort(arr)
console.log(res)
console.log(arr, '原数组') ------------------------- 注意,这样的写法会改变原数组





-------
第二版
1. 可以优化的点
  - 每趟的次数
    - 最原始:每趟比较 length -1 次
    - 第一版:每趟比较 length -1 - i 次
    //(第一趟确定一个最大值,第二趟则无需再比较length - 1的最后一次)
    //(第二趟确定一个第二大的值,则第三趟无需再比较length -2的倒数两次....)
  - 趟数
    - 如果一共有7趟,再第6趟的时候就已经全部排好了,那最后一趟就无需再比较
2. 在第一版中已经优化了每趟比较的次数,现在可以可以多余的趟数了
3. 如何找到某趟已经排好了?
  - 用一个标志位,进入 (趟数的循环) 默认为true,假设这趟已经排好了
  - 在(每趟次数的循环)中,比较相邻大小时,进入了判断,说明没有排好,标志位设置为 false
  - 在趟数循环的末尾,判断是不是标志位为true,为true表示该趟拍好了,break掉外层的趟数循环
const arr = [1,4,2,3,8,6,7,5]
let outTimes = 0 // 记录外层循环的次数
let inTimes = 0 // 记录内层循环的次数
function bubble_sort (arr) {
  const Arr = JSON.parse (JSON.stringify (arr))
  const len = arr.length
  for (let i = 0; i < len - 1; i++) {
    let isSortOk = true //------------------------------ 标志位,假设该趟已经排好
    outTimes++
    for (let j = 0; j < len - i - 1; j++) {
      inTimes++
      if (Arr[j] > Arr[j+1]) {
        isSortOk = false // ---------------------------- 进入该判断,表示该趟还未排序好
        const temp = Arr[j]
        Arr[j] = Arr[j+1]
        Arr[j+1] = temp
      }
    }
    if (isSortOk) {
      break
      // 如果该趟标志位为true,表示该趟其实已经排好了,剩下的趟数都不用在比较了,直接breck整个趟数循环
    }
  }
  return Arr
}

interview 对于冒泡排序,如何通过添加一个参数(函数),来控制升序和降序

const arrs = [1, 3, 2, 5, 4]
function bubbling_sort (arr, compareFn) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = 0; j < arr.length - i; j++) {
      if (compareFn(arr[j], arr[j+1]) > 0) {
        const temp = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = temp
      }
    }
  }
  return arr
}
const res = bubbling_sort(arrs, (a, b) =>  b - a)
// 即通过传入一个函数,比较这个函数中两个参数的大小来判断是升序还是降序
// 如果是 (a, b) => a - b 说明 前 > 后 ------------------------------- 升序
// 如果是 (a, b) => b - a 说明 后 > 前 ------------------------------- 降序
console.log(res)















(1)encodeURIComponent() 和 decodeURIComponent

(2)encodeURI() 和 decodeURI

(3)escape() 和 unescape()

1. 区别 encodeURIComponent() 和 encodeURI()
  - encodeURI 用于整个url  
  - encodeURIComponent用于对 url的某一段进行编码 (component嘛)
  - encodeURIComponent编码的返回更大

2.
编码:encode
解码:decode 

3. escape encodeURI encodeURIComponent
  - 共同点:都不会对字母和数字编码
  - 区别
    - escape:用于字符串 -------------------------------------- 过时产物,尽量不要使用
    - encodeURIComponent 和 encodeURI 用于 url

4. encodeURIComponent(URIstring)
  - encodeURIComponent()函数可以把字符串作为 URI组件 进行编码
  - 返回值的某些字符将被十六进制的转义序列进行替换

  - 注意:
    - encodeURIComponent() 不会对 ASCII字母和数字进行编码
    - 不会编码: -_.*~( )'!   ---------------- (刚刚电信拨了小括号,还有 ' 不要忘了)
    - 会编码:: / ? = & # @ + $ , ;  --------- ( 用于分隔URI组件的标点符号 ),替换为一个或者多个十六进制转义序列
5.实例


A页面


 componentWillMount() {
   const _token = window.localStorage.getItem('access_token');
   const href = window.encodeURIComponent(window.location.href);
   if (_token) {
     this.props.getUserInfo(_token);
     return ;
   } 
   window.location.href = `http://localhost:40004/login?redirect_url=${href}`;
 }

说明:
window.location.href = `http://localhost:40004/login?redirect_url=${href}`;
地址栏跳转到 (B页面) 并且携带当前完整的href地址 (A页面)
该href就需要编码,因为在B页面要拿到search就只能有一个?




----------------------------------------------------------------------------------------
B页面


function * watchLogin() {
 yield takeEvery(constants.LOGIN, function * login(action) {
   try {
     const query = qs.parse(window.location.search.slice(1));  // 去掉search的问号,并转成对象
     const redirect = query['redirect_url'] ;  // 拿到对象redirect_url属性对应的值
     const redirectHref = window.decodeURIComponent(redirect);   // 再反解码
     yield call(() => window.location.href = redirect);  // 再跳回A页面
   } catch (err) {
     yield call(() => swal('错误', '用户名或密码错误', 'error'));
   }
 });
}
【算法】二分查找,冒泡排序_第1张图片
image.png

https://aotu.io/notes/2017/06/15/The-mystery-of-URL-encoding/?o2src=juejin&o2layout=compat

https://juejin.im/post/582e3bc4da2f600063e697ab

把cookie聊清楚 https://juejin.im/post/59d1f59bf265da06700b0934

编码 https://juejin.im/post/59cd8420518825276f49f921




你可能感兴趣的:(【算法】二分查找,冒泡排序)