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)包含自組織方式的順序查找
使用自組織(數(shù)據(jù)的位置并非由程序員在執(zhí)行之前就組織好,而是在程序運(yùn)行過程中由程序自動組織的)數(shù)據(jù)
通過將頻繁查找到的元素置于數(shù)據(jù)集的起始位置來最小化查找次數(shù)。
a. 包含自組織方式的seqSearch(1):不斷檢查確認(rèn)已找到的數(shù)據(jù)是否已經(jīng)排在最前面。
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):將找到的元素移動到數(shù)據(jù)集的起始位置,但是如果這個元素已經(jīng)很接近起始位置,則不會對它的位置進(jìn)行交換。
80-20原則:對某一數(shù)據(jù)集執(zhí)行的80%的查找操作都是對其中20%的數(shù)據(jù)元素進(jìn)行查找。
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)) {
// 僅當(dāng)數(shù)據(jù)位于數(shù)據(jù)集的前20%元素之外時(shí),該數(shù)據(jù)才需要被重新移動到數(shù)據(jù)集的起始位置。
[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. 二分查找算法【已排序數(shù)據(jù)】
算法描述:
(1)將數(shù)組的第一個位置設(shè)置為下邊界(0)
(2)將數(shù)組最后一個元素所在的位置設(shè)置為上邊界(數(shù)組的長度減1)
(3)若下邊界等于或小于上邊界,則做如下操作:
a. 將中點(diǎn)設(shè)置為(上邊界加上下邊界)除以2
b. 如果中點(diǎn)的元素小于查詢的值,則將下邊界設(shè)置為中點(diǎn)元素所在下標(biāo)加1
c. 如果中點(diǎn)的元素大于查詢的值,則將上邊界設(shè)置為中點(diǎn)元素所在下標(biāo)減1
d. 否則中點(diǎn)元素即為要查找的數(shù)據(jù),可以進(jìn)行返回
實(shí)現(xiàn):
function binSearch(arr, target) {
const len = arr.length
let upperBound = len - 1
let lowBound = 0
while (lowBound <= upperBound) {
// 將中點(diǎn)設(shè)置為 (上邊界 + 下邊界) / 2
let mid = Math.floor((lowBound + upperBound) / 2)
console.log(`當(dāng)前的中點(diǎn)值:${arr[mid]}`)
if (arr[mid] < target) {
// 如果中點(diǎn)的元素小于查詢的值,則將下邊界設(shè)置為中點(diǎn)元素所在的下標(biāo)加一
lowBound = mid + 1
} else if (arr[mid] > target) {
// 如果中點(diǎn)的元素大于查詢的值,則將上邊界設(shè)置為中點(diǎn)元素所在的下標(biāo)減一
upperBound = mid - 1
} else {
// 否則中點(diǎn)元素即為要查找的數(shù)據(jù),可以進(jìn)行返回
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)
// 當(dāng)前的中點(diǎn)值:59
// 當(dāng)前的中點(diǎn)值:77
// 當(dāng)前的中點(diǎn)值:78
// 8
示例:計(jì)算一個數(shù)組中某個數(shù)的重復(fù)次數(shù)
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++
// 向下(左)遍歷數(shù)組,統(tǒng)計(jì)找到的值出現(xiàn)的次數(shù),當(dāng)下一個值與要查找的值不匹配時(shí)停止計(jì)數(shù)
for (let i = pos - 1; i > 0; i--) {
if (arr[i] === target) {
count++
} else {
break
}
}
// 向上(右)遍歷數(shù)組,統(tǒng)計(jì)找到的值出現(xiàn)的次數(shù),當(dāng)下一個值與要查找的值不匹配時(shí)停止計(jì)數(shù)
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(`重復(fù)次數(shù)為:${result7}次`)
// 當(dāng)前的中點(diǎn)值:59
// 當(dāng)前的中點(diǎn)值:77
// 當(dāng)前的中點(diǎn)值:72
// 重復(fù)次數(shù)為:2次