算法07 五大查找之:索引查找

笔记仓库:https://github.com/nnngu/LearningNotes


上一篇总结了二分查找,这一篇要总结的是索引查找。

关于索引,我们很容易地联想到数据库中的索引,建立了索引,可以大大提高数据库的查询速度。

索引查找又称为分块查找,是一种介于顺序查找和二分查找之间的一种查找方法,索引查找的基本思想是:首先查找索引表,可用二分查找或顺序查找,然后在确定的块中进行顺序查找。

在实现索引查找算法前需要弄清楚以下三个术语。

(1)主表。即要查找的序列。

(2)索引项。一般我们会将主表分成几个块,每个块建立一个索引,这个索引就叫索引项。

(3)索引表。即索引项的集合。

同时,索引项包括以下三点。

(1)index,即索引项在主表的关键字。

(2)start,即块内的第1个元素在主表中的位置。

(3)length,即块的长度。

索引查找的示意图

示意图如下:

索引查找的代码实现

代码:

IndexItem.java

public class IndexItem {
    public int index;
    public int start;
    public int length;

    public IndexItem(int index, int start, int length) {
        this.index = index;
        this.start = start;
        this.length = length;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public int getStart() {
        return start;
    }

    public void setStart(int start) {
        this.start = start;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }
}

IndexSearch.java

public class IndexSearch {
    // 主表
    static int[] mainList = new int[]{
            101, 102, 103, 104, 105, 0, 0, 0, 0, 0,
            201, 202, 203, 204, 0, 0, 0, 0, 0, 0,
            301, 302, 303, 0, 0, 0, 0, 0, 0, 0
    };

    // 索引表
    static IndexItem[] indexItemList = new IndexItem[]{
            new IndexItem(1, 0, 5),
            new IndexItem(2, 10, 4),
            new IndexItem(3, 20, 3)
    };

    /**
     * 索引查找算法
     *
     * @param key 给定值
     * @return 返回给定值在表中的位置
     */
    public static int indexSearch(int key) {
        IndexItem item = null;

        // 建立索引规则
        int index = key / 100;

        // ① 遍历索引表,找到对应的索引项
        for (int i = 0; i < indexItemList.length; i++) {
            // 找到索引项
            if (indexItemList[i].index == index) {
                item = indexItemList[i];
                break;
            }
        }

        // 索引表中不存在该索引项
        if (item == null) {
            return -1;
        }

        // ② 根据索引项,在主表中查找
        for (int i = item.start; i < item.start + item.length; i++) {
            if (mainList[i] == key) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 插入数据
     *
     * @param key 要插入的值
     * @return true表示插入成功,false表示插入失败
     */
    public static boolean insert(int key) {
        IndexItem item = null;

        // 建立索引规则
        int index = key / 100;
        int i = 0;
        // 遍历索引表,找到对应的索引项
        for (i = 0; i < indexItemList.length; i++) {
            if (indexItemList[i].index == index) {
                item = indexItemList[i];
                break;
            }
        }
        // 索引表中不存在该索引项
        if (item == null) {
            return false;
        }

        // 根据索引项将值插入到主表中
        mainList[item.start + item.length] = key;
        // 更新索引表
        indexItemList[i].length++;

        return true;
    }

    /**
     * 遍历打印
     */
    public static void display(int[] list) {
        System.out.println("********展示开始********");
        if (list != null && list.length > 0) {
            for (int i = 0; i < list.length; i++) {
                System.out.print(list[i] + " ");
                if ((i + 1) % 10 == 0) {
                    System.out.println("");
                }
            }
        }
        System.out.println("********展示结束********");
    }

    public static void main(String[] args) {
        System.out.println("********索引查找********");
        System.out.println("");
        System.out.println("原始数据:");
        display(mainList);
        System.out.println("");

        int value = 106;
        System.out.println("插入数据:" + value);
        // 插入成功
        if (insert(value)) {
            System.out.println("插入后的主表:");
            display(mainList);
            System.out.println("");

            System.out.println("元素" + value + "在列表中的位置为:" + indexSearch(value));
        }
    }
}

运行结果: