JavaScript实现常见查找算法

108 阅读3分钟

JavaScript实现查找算法及适用场景

下面是几种常见查找算法的JavaScript实现及其适用场景分析。

1. 顺序查找 (Sequential Search)

function sequentialSearch(arr, target) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === target) {
            return i; // 返回找到的索引
        }
    }
    return -1; // 未找到
}

适用场景

  • 适用于无序列表或小规模数据集
  • 实现简单,不需要预处理
  • 当数据量很小时,可能是最有效的查找方法
  • 适用于链表等顺序存储结构

2. 二分查找 (Binary Search)

function binarySearch(arr, target) {
    let left = 0;
    let right = arr.length - 1;
    
    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        
        if (arr[mid] === target) {
            return mid;
        } else if (arr[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    
    return -1;
}

适用场景

  • 必须是有序数组
  • 适用于静态数据集(不频繁插入/删除)
  • 数据量较大时效率高(时间复杂度O(log n))
  • 常用于数据库索引、查找表等场景

3. 哈希查找 (Hash Search)

class HashTable {
    constructor(size = 32) {
        this.size = size;
        this.table = new Array(size).fill(null).map(() => []);
    }

    _hash(key) {
        let hash = 0;
        for (let i = 0; i < key.length; i++) {
            hash = (hash << 5) + key.charCodeAt(i);
            hash = hash & hash; // Convert to 32bit integer
            hash = Math.abs(hash);
        }
        return hash % this.size;
    }

    set(key, value) {
        const index = this._hash(key);
        const bucket = this.table[index];
        const found = bucket.find(item => item[0] === key);
        
        if (found) {
            found[1] = value;
        } else {
            bucket.push([key, value]);
        }
    }

    get(key) {
        const index = this._hash(key);
        const bucket = this.table[index];
        const found = bucket.find(item => item[0] === key);
        
        return found ? found[1] : undefined;
    }
}

// 使用示例
const hashTable = new HashTable();
hashTable.set('name', 'Alice');
hashTable.set('age', 25);
console.log(hashTable.get('name')); // 输出: Alice

适用场景

  • 需要快速查找、插入和删除操作(平均O(1)时间复杂度)
  • 适用于缓存实现(如Memcached、Redis)
  • 字典、对象属性的快速访问
  • 不适合需要有序遍历数据的场景
  • 需要处理哈希冲突

4. 二叉搜索树查找 (BST Search)

class TreeNode {
    constructor(value) {
        this.value = value;
        this.left = null;
        this.right = null;
    }
}

class BinarySearchTree {
    constructor() {
        this.root = null;
    }

    insert(value) {
        const newNode = new TreeNode(value);
        
        if (!this.root) {
            this.root = newNode;
            return this;
        }
        
        let current = this.root;
        while (true) {
            if (value === current.value) return undefined;
            
            if (value < current.value) {
                if (!current.left) {
                    current.left = newNode;
                    return this;
                }
                current = current.left;
            } else {
                if (!current.right) {
                    current.right = newNode;
                    return this;
                }
                current = current.right;
            }
        }
    }

    find(value) {
        if (!this.root) return false;
        
        let current = this.root;
        while (current) {
            if (value === current.value) return true;
            
            if (value < current.value) {
                current = current.left;
            } else {
                current = current.right;
            }
        }
        
        return false;
    }
}

// 使用示例
const bst = new BinarySearchTree();
bst.insert(10);
bst.insert(5);
bst.insert(15);
bst.insert(2);
bst.insert(7);
console.log(bst.find(7)); // 输出: true
console.log(bst.find(99)); // 输出: false

适用场景

  • 数据需要频繁插入/删除,同时保持查找效率
  • 需要有序的数据结构(中序遍历可以得到有序序列)
  • 适合动态数据集
  • 在最坏情况下(树退化为链表)性能会下降到O(n),因此实际中常用平衡二叉搜索树(如AVL树、红黑树)

5. 插值查找 (Interpolation Search)

function interpolationSearch(arr, target) {
    let low = 0;
    let high = arr.length - 1;
    
    while (low <= high && target >= arr[low] && target <= arr[high]) {
        // 计算插值位置
        const pos = low + Math.floor(
            ((target - arr[low]) * (high - low)) / (arr[high] - arr[low])
        );
        
        if (arr[pos] === target) {
            return pos;
        }
        
        if (arr[pos] < target) {
            low = pos + 1;
        } else {
            high = pos - 1;
        }
    }
    
    return -1;
}

适用场景

  • 数据必须是有序且均匀分布的
  • 对于大型且分布均匀的有序数据集,比二分查找效率更高
  • 适用于电话号码、ID等均匀分布的数字查找
  • 数据分布不均匀时性能可能比二分查找差

算法选择建议

  1. 数据是否有序?

    • 有序 → 考虑二分查找或插值查找
    • 无序 → 顺序查找或先排序后使用高效查找
  2. 数据量大小?

    • 小数据 → 顺序查找可能足够
    • 大数据 → 二分查找、哈希查找或树查找
  3. 是否需要频繁插入/删除?

    • 是 → 哈希表或二叉搜索树
    • 否 → 可以考虑排序后使用二分查找
  4. 是否需要范围查询或有序遍历?

    • 是 → 二叉搜索树
    • 否 → 哈希表可能更高效
  5. 内存限制?

    • 严格 → 顺序查找或二分查找(空间复杂度低)
    • 宽松 → 哈希表(空间换时间)

实际应用中,JavaScript内置的对象和Map已经实现了高效的哈希查找,对于大多数场景都是最佳选择。只有在特定需求下(如需要有序数据、范围查询等)才需要考虑实现其他查找算法。