目录
二分查找 插入排序 1 - javascript的原始实现 2 - javascript的原始实现 —— 优化 3 - 抛开原始实现。更好的算法实现 4 - 完整的插入并排序的计算过程 冒泡排序 归并排序二分查找
二分查找(Binary search)也称折半查找,是一种效率较高的查找方法。但是要求数组必须是有序的。
最好 时间复杂度是: O(1) ,最好情况下只需要进行1次比较就能找到目标元素 最坏**时间复杂度是: O(log2n) ,最坏情况下查找至最后一个元素,或查找不到目标元素 平均**时间复杂度是: O(log2n)while循环写法:
function bSearch(arr, tar) { let l = 0, // left 查找范围左边界 r = arr.length - 1, // right 查找范围右边界 g // guess 猜想位置 while (l <= r) { g = Math.floor((l + r) / 2) // 循环不变式 if (arr[g] === tar) return g else if (arr[g] > tar) r = g - 1 else l = g + 1 } return -1 } const A = [3, 5, 19, 22, 25, 33, 45, 47, 57, 66, 71, 78] console.log(bSearch(A, 88)) console.log(bSearch(A, 68)) console.log(bSearch(A, 22))
二分查找递归写法的递归树写法:
function binarySearch(A, p, r, x) { const guess = Math.floor((r + p) / 2) if (p >= r) return -1 if (A[guess] === x) return guess return A[guess] > x ? binarySearch(A, p, guess - 1, x) : binarySearch(A, guess + 1, r, x) } const A = [3, 5, 19, 22, 25, 33, 45, 47, 57, 66, 71, 78] console.log(binarySearch(A, 0, A.length - 1, 8)); console.log(binarySearch(A, 0, A.length - 1, 19));
插入排序
插入排序是一种比较原始的排序方法,接近于人的理解。时间复杂度是: O(n^2)
1 - javascript的原始实现
function insertOrigin(arr, num) { const tmp = arr.find(a => a > num) // tmp代表第一个大于 num 的数字 if (tmp === undefined) { // 代表所有元素都比num小 arr.push(num) } else { const idx = arr.indexOf(tmp) arr.splice(idx, 0, num) } console.log(arr) } const A = [2, 4, 7, 9, 13] // 原数组 const x = 8 // 需要插入的元素 insertOrigin(A, x)
2 - javascript的原始实现 —— 优化
function insertOriginOpti(arr, num) { const tmp = arr.find(a => a > num) const idx = arr.indexOf(tmp) arr.splice(idx === -1 ? arr.length : idx, 0, num) console.log(arr) } const B = [2, 4, 7, 9, 13] // 原数组 const x = 8 // 需要插入的元素 insertOriginOpti(B, x)
3 - 抛开原始实现。更好的算法实现
function insertBetter(arr, num) { let p = arr.length - 1 // p 指向下一个需要比较的元素,p+1指向空位 while (p >= 0 && arr[p] > num) { arr[p + 1] = arr[p] p-- } arr[p + 1] = x console.log(arr); } const A = [2, 4, 7, 9, 13] // 原数组 const x = 8 // 需要插入的元素 insertBetter(A, x)
4 - 完整的插入并排序的计算过程
常见问题:如何在一个有序数组中插入一个新值,新数组仍保持有序?
function insertion_sort(A) { for (let i = 1; i < A.length; i++) { insert(A, i, A[i]) } } function insert(A, i, x) { let p = i - 1 while (p >= 0 && A[p] > x) { console.log(p + 1, p, A[p + 1], A[p]); A[p + 1] = A[p] p-- } A[p + 1] = x } const A = [5, 8, 1, 3, 2, 4, 9] insertion_sort(A) console.log(A)
冒泡排序
冒泡排序(bubble sort)也称作下沉排序(sinking sort),它重复比较相邻的两个元素,直到整个数组都没有数字可以在进行交换,时间复杂度是: O(n^2)
// 交换 function swap(A, i, j) { const t = A[i] A[i] = A[j] A[j] = t } // 第一种写法 function bubble_sort(A) { for (let i = 0; i < A.length - 1; i++) { for (let j = 0; j < A.length - i - 1; j++) { A[j + 1] < A[j] && swap(A, j + 1, j) } } } // 第二种写法 function bubbleSort(A) { for (let i = A.length - 1; i >= 1; i--) { for (let j = 1; j <= i; j++) { A[j - 1] > A[j] && swap(A, j - 1, j) } } } const A = [5, 8, 1, 4, 6, 2, 3] const B = [5, 8, 1, 4, 6, 2, 3] bubble_sort(A) bubbleSort(B) console.log(A); console.log(B);
归并排序
归并排序也叫合并排序,将原数组拆分成若干个子数组,然后合并,目前应用的越来越广泛了,常见问题就是如何合并两个有序数组?,它可以保证:
最坏情况的时间复杂度是: O(nlgn) ,最好情况的时间复杂度是: O(nlgn) ,空间复杂度: O(n)
O(nlgn)的解释是:将一个数据集分成两半,然后将分开的每一半再分成两半,依此类推,在此过程中同时遍历每一半数据
首先要能够归并两个有序数组,换句话说就是合并两个有序数组为一个有序数组。
// A:数组 // p:左半边开始位置 // q:左半边结束,右半边开始位置 // r:右半边结束 function merge_sort(A, p, q, r) { let A1 = A.slice(p, q) // 存放左半边的临时空间 let A2 = A.slice(q, r) // 存放右半边的临时空间 // 追加哨兵 A1.push(Number.MAX_SAFE_INTEGER) A2.push(Number.MAX_SAFE_INTEGER) for (let k = p, i = 0, j = 0; k < r; k++) { // 循环不变式 // k: 下一个写入位置 // i: A1中获回写位置 // j: A2中回写位置 A[k] = A1[i] < A2[j] ? A1[i++] : A2[j++] } } const A = [1, 3, 5, 2, 4, 6] const B = [2, 4, 6, 1, 3, 5] const C = [1, 2] merge_sort(A, 0, 3, 6) merge_sort(B, 1, 3, 5) merge_sort(C, 1, 2) console.log(A, B, C);
而归并排序就是先使用递归将数组中元素进行拆分,直至拆分得到单个元素作为一个数组,此时就可以将其看作一个有序数组(只有一个元素自然是有序的)进行归并。最终将所有元素归并得到一个有序数组。
归并排序主要涉及两个部分:一个是递归问题,另一个就是有序数组进行归并(也就是第一部分的合并的代码内容)
function merge_sort(A, p, r) { if (r - p < 2) { return } const q = Math.ceil((p + r) / 2) // 拆分得到单个元素 merge_sort(A, p, q) // 实现左半边的排序 merge_sort(A, q, r) // 实现右半边的排序 merge(A, p, q, r) } function merge(A, p, q, r) { let A1 = A.slice(p, q) let A2 = A.slice(q, r) A1.push(Number.MAX_SAFE_INTEGER) A2.push(Number.MAX_SAFE_INTEGER) for (let k = p, i = 0, j = 0; k < r; k++) { A[k] = A1[i] < A2[j] ? A1[i++] : A2[j++] } } const A = [39, 27, 43, 3, 9, 82, 10] merge_sort(A, 0, A.length) console.log(A);
查看更多关于常见的算法浅学一下,二分查找、插入冒泡归并排序的详细内容...