数据结构与算法JavaScript描述(12) —— 检索算法(Search)

1. 顺序查找

(1)查找某值

function seqSearch(arr, target) {
    const len = arr && arr.length
    if (!len) return -1
    for (let i = 0; i < len; i++) {
        if (arr[i] === target) {
            return i
        }
    }
    return -1
}

// test
const arr1 = [72, 54, 59, 30, 31, 78, 2, 77, 82, 72]
const result1 = seqSearch(arr1, 82)
console.log(result1)    // 8

(2)查找最小值

function findMin(arr) {
    const len = arr && arr.length
    if (!len) return null
    let min = arr[0]
  for(let i = 1; i < len; i++) {
    if (arr[i] < min) {
        min = arr[i]
    }
  }
  return min
}

// test
const arr2 = [72, 54, 59, 30, 31, 78, 2, 77, 82, 72]
const result2 = findMin(arr2)
console.log(result2)    // 2

(3)查找最大值

function findMax(arr) {
    const len = arr && arr.length
    if (!len) return null
    let max = arr[0]
    for (let i = 1; i < len; i++) {
        if (arr[i] > max) {
            max = arr[i]
        }
    }
    return max
}

// test
const arr3 = [72, 54, 59, 30, 31, 78, 2, 77, 82, 72]
const result3 = findMax(arr3)
console.log(result3)    // 82

(4)包含自组织方式的顺序查找

使用自组织(数据的位置并非由程序员在执行之前就组织好,而是在程序运行过程中由程序自动组织的)数据
通过将频繁查找到的元素置于数据集的起始位置来最小化查找次数

a. 包含自组织方式的seqSearch(1):不断检查确认已找到的数据是否已经排在最前面。

function seqSearch(arr, target) {
    const len = arr.length
    for (let i = 0; i < len; i++) {
        if (arr[i] === target) {
            if (i > 0) {
                [arr[i - 1], arr[i]] = [arr[i], arr[i - 1]]
            }
            return true
        }
    }
    return false
}

// test
const arr4 =  [72, 54, 59, 30, 31, 78, 2, 77, 82, 72]
for(let i = 1; i <= 4; i++) {
    const result4 =  seqSearch(arr4, 77)
    console.log(arr4)
    // [72, 54, 59, 30, 31, 78, 77, 2, 82, 72]
    // [72, 54, 59, 30, 31, 77, 78, 2, 82, 72]
    // [72, 54, 59, 30, 77, 31, 78, 2, 82, 72]
    // [72, 54, 59, 77, 30, 31, 78, 2, 82, 72]
}

b. 包含自组织方式的seqSearch(2):将找到的元素移动到数据集的起始位置,但是如果这个元素已经很接近起始位置,则不会对它的位置进行交换。

80-20原则:对某一数据集执行的80%的查找操作都是对其中20%的数据元素进行查找。

function seqSearch(arr, target) {
    const len = arr.length
    for (let i = 0; i < len; i++) {
        if (arr[i] === target) {
            if (i > (arr.length * 0.2)) {
                // 仅当数据位于数据集的前20%元素之外时,该数据才需要被重新移动到数据集的起始位置。
                [arr[0], arr[i]] = [arr[i], arr[0]]
            }
            return true
        }
    }
    return false
}

// test
const arr5 =  [72, 54, 59, 30, 31, 78, 2, 77, 82, 72]
for(let i = 1; i <= 4; i++) {
    const result5 =  seqSearch(arr5, 77)
    console.log(arr5)
    // [77, 54, 59, 30, 31, 78, 2, 72, 82, 72]
    // [77, 54, 59, 30, 31, 78, 2, 72, 82, 72]
    // [77, 54, 59, 30, 31, 78, 2, 72, 82, 72]
    // [77, 54, 59, 30, 31, 78, 2, 72, 82, 72]
}

2. 二分查找算法【已排序数据】

算法描述:
(1)将数组的第一个位置设置为下边界(0)
(2)将数组最后一个元素所在的位置设置为上边界(数组的长度减1)
(3)若下边界等于或小于上边界,则做如下操作:
a. 将中点设置为(上边界加上下边界)除以2
b. 如果中点的元素小于查询的值,则将下边界设置为中点元素所在下标加1
c. 如果中点的元素大于查询的值,则将上边界设置为中点元素所在下标减1
d. 否则中点元素即为要查找的数据,可以进行返回

实现:

function binSearch(arr, target) {
    const len = arr.length
    let upperBound = len - 1
    let lowBound = 0
    while (lowBound <= upperBound) {
        // 将中点设置为 (上边界 + 下边界) / 2
        let mid = Math.floor((lowBound + upperBound) / 2)
        console.log(`当前的中点值:${arr[mid]}`)
        if (arr[mid] < target) {
            // 如果中点的元素小于查询的值,则将下边界设置为中点元素所在的下标加一
            lowBound = mid + 1
        } else if (arr[mid] > target) {
            // 如果中点的元素大于查询的值,则将上边界设置为中点元素所在的下标减一
            upperBound = mid - 1
        } else {
            // 否则中点元素即为要查找的数据,可以进行返回
            return mid
        }
    }
    return -1
}

// test
const arr6 = [2, 30, 31, 54, 59, 72, 72, 77, 78, 82]
const result6 = binSearch(arr6, 78)
console.log(result6)
// 当前的中点值:59
// 当前的中点值:77
// 当前的中点值:78
// 8

示例:计算一个数组中某个数的重复次数

function count(arr, target) {
    const len = arr.length
    let count = 0
    arr.sort((a, b) => { return a - b })
    let pos = binSearch(arr, target)
    if (pos > -1) {
        count++
        // 向下(左)遍历数组,统计找到的值出现的次数,当下一个值与要查找的值不匹配时停止计数
        for (let i = pos - 1; i > 0; i--) {
            if (arr[i] === target) {
                count++
            } else {
                break
            }
        }
        // 向上(右)遍历数组,统计找到的值出现的次数,当下一个值与要查找的值不匹配时停止计数
        for (let j = pos + 1; j < len; j++) {
            if (arr[j] === target) {
                count++
            } else {
                break
            }
        }
    }
    return count
}

// test
const arr7 = [72, 54, 59, 30, 31, 78, 2, 77, 82, 72]
const result7 = count(arr7, 72)
console.log(`重复次数为:${result7}次`)

// 当前的中点值:59
// 当前的中点值:77
// 当前的中点值:72
// 重复次数为:2次

你可能感兴趣的:(数据结构与算法JavaScript描述(12) —— 检索算法(Search))