分块查找(索引表查找)

分块查找是一种基于分治思想的搜索算法,适用于顺序存储的有序数据
它通过将数据分成若干,再对这些块进行二分查找,从而提高查找效率。

🧩 分块查找的思路

  1. 数据分块:将数据划分为大小相等的块(一般为 √n 大小),并创建一个索引数组(称为块索引)来存储每个块的最大值。

  2. 定位块:首先在块索引数组中进行二分查找,找到目标值所在的块。

  3. 块内查找:然后在找到的块内进行线性查找二分查找,确定目标值的位置。


🚀 代码实现(分块查找)

public class BlockSearchUnordered {
    // 定义索引表类,包含块的最小值和最大值
    static class Index {
        int minValue;   // 块中的最小值
        int maxValue;   // 块中的最大值
        int startIndex; // 块的起始索引

        Index(int minValue, int maxValue, int startIndex) {
            this.minValue = minValue;
            this.maxValue = maxValue;
            this.startIndex = startIndex;
        }
    }

    // 块查找函数
    public static int blockSearch(int[] arr, int key, Index[] indexTable, int blockSize) {
        if (arr == null || arr.length == 0 || indexTable == null) {
            return -1;
        }

        // 第一步:在索引表中找到目标值可能的块
        int blockIndex = -1;
        for (int i = 0; i < indexTable.length; i++) {
            // 检查 key 是否在当前块的范围内(minValue <= key <= maxValue)
            if (key >= indexTable[i].minValue && key <= indexTable[i].maxValue) {
                blockIndex = i;
                break;
            }
            // 如果 key 超出了当前块的最大值,且后续块的最小值大于 key,则不在数组中
            if (i < indexTable.length - 1 && key > indexTable[i].maxValue && key < indexTable[i + 1].minValue) {
                return -1;
            }
        }

        // 如果未找到合适的块(key 超出最大值)
        if (blockIndex == -1) {
            return -1;
        }

        // 第二步:在块内顺序查找
        int start = indexTable[blockIndex].startIndex;
        int end = Math.min(start + blockSize, arr.length); // 确保不越界
        for (int i = start; i < end; i++) {
            if (arr[i] == key) {
                return i; // 找到目标值,返回索引
            }
        }

        return -1; // 未找到
    }

    // 主函数测试
    public static void main(String[] args) {
        // 示例数组:块内无序,块间有序
        int[] arr = {3, 1, 5,  // 块 1: min=1, max=5
                     7, 9, 6,  // 块 2: min=6, max=9
                     12, 10, 11}; // 块 3: min=10, max=12
        int blockSize = 3; // 每块大小

        // 创建索引表
        int blockCount = (int) Math.ceil((double) arr.length / blockSize);
        Index[] indexTable = new Index[blockCount];
        for (int i = 0; i < blockCount; i++) {
            int start = i * blockSize;
            int end = Math.min(start + blockSize, arr.length);
            int minValue = arr[start];
            int maxValue = arr[start];
            for (int j = start + 1; j < end; j++) {
                if (arr[j] < minValue) minValue = arr[j];
                if (arr[j] > maxValue) maxValue = arr[j];
            }
            indexTable[i] = new Index(minValue, maxValue, start);
        }

        // 测试查找
        int key = 6; // 要查找的值
        int result = blockSearch(arr, key, indexTable, blockSize);
        if (result != -1) {
            System.out.println("找到 " + key + " 在索引 " + result);
        } else {
            System.out.println(key + " 未找到");
        }

        // 打印索引表(调试用)
        System.out.println("索引表:");
        for (Index idx : indexTable) {
            System.out.println("块范围: [" + idx.minValue + ", " + idx.maxValue + "], 起始索引: " + idx.startIndex);
        }
    }
}

⏳ 时间复杂度

  • 时间复杂度

    • binarySearch(blockIndex, target)O(log n)(对块索引数组进行二分查找)

    • 在块内进行线性查找:O(√n)(每块大小为 √n)

    因此,整体时间复杂度为:O(log n + √n)

  • 空间复杂度

    • O(√n) 用于存储块索引数组。


🎯 适用场景

顺序存储的有序数组
访问代价较高的情况(如磁盘存储)
数据量较大时,想通过分块减小搜索范围


🆚 与二分查找对比

二分查找分块查找
查找方式每次划分数组为两半每次划分为更小的块
时间复杂度O(log n)O(log n + √n)
适用场景普通有序数组顺序存储的有序数组
优点计算简单数据存储在磁盘上时,减少了寻址次数

✨ 总结

  • 分块查找普通的二分查找多了分块的步骤,能更好地适应数据存储的特殊情况(如磁盘存储),但需要额外的空间用于存储块索引。

  • 对于常规的内存中的数据,二分查找仍然是最优选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值