分塊查找又稱索引順序查找,它是順序查找的一種改進方法。
算法流程:
- 先選取各塊中的最大關鍵字構成一個索引表;
- 查找分兩個部分:先對索引表進行二分查找或順序查找,以確定待查記錄在哪一塊中;然后,在已確定的塊中用順序法進行查找。
注:算法的思想是將n個數據元素"按塊有序"划分為m塊(m ≤ n)。每一塊中的結點不必有序,但塊與塊之間必須"按塊有序",每個塊內的的最大元素小於下一塊所有元素的任意一個值。
所以,給定一個待查找的key,在查找這個key值位置時,會先去索引表中利用順序查找或者二分查找來找出這個key所在塊的索引開始位置,然后再根據所在塊的索引開始位置開始查找這個key所在的具體位置。
下面給出一段分塊查找的代碼,其思想和上面描述的一樣,都是通過索引表來找key的位置。
先給出主表和索引表:
1 // 主表,size=30 2 static int[] mainList = new int[]{ 3 101, 102, 103, 104, 105, 0, 0, 0, 0, 0, 4 201, 202, 203, 204, 0, 0, 0, 0, 0, 0, 5 301, 302, 303, 0, 0, 0, 0, 0, 0, 0 6 }; 7 8 // 索引表 9 static IndexItem[] indexItemList = new IndexItem[]{ 10 new IndexItem(1, 0, 5), 11 new IndexItem(2, 10, 4), 12 new IndexItem(3, 20, 3) 13 };
索引表類:
static 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; } //... getter and setter }
索引查找算法:
1 public static int indexSearch(int key) { 2 IndexItem indexItem = null; 3 4 //建立索引規則 5 int index = key / 100; 6 7 //遍歷索引表 8 for(int i = 0;i < indexItemList.length; i++) { 9 //找到索引項 10 if(indexItemList[i].index == index) { 11 indexItem = indexItemList[i]; 12 break; 13 } 14 } 15 16 //索引表中不存在該索引項 17 if(indexItem == null) 18 return -1; 19 20 //根據索引項,在主表中查找 21 for(int i = indexItem.start; i < indexItem.start + indexItem.length; i++) { 22 if(mainList[i] == key) 23 return i; 24 } 25 26 return -1; 27 }
時間復雜度分析:先按二分查找去找key在索引表為大概位置(所給出代碼是順序查找),然后在主表中的可能所在塊的位置開始按順序查找,所以時間復雜度為O(log₂(m)+N/m),m為分塊的數量,N為主表元素的數量,N/m 就是每塊內元素的數量。
分塊查找的插入算法:
1 /** 2 * 插入數據 3 * 4 * @param key 要插入的值 5 * @return true表示插入成功,false表示插入失敗 6 */ 7 public static boolean insert(int key) { 8 IndexItem item = null; 9 10 // 建立索引規則 11 int index = key / 100; 12 int i = 0; 13 // 遍歷索引表,找到對應的索引項 14 for (i = 0; i < indexItemList.length; i++) { 15 if (indexItemList[i].index == index) { 16 item = indexItemList[i]; 17 break; 18 } 19 } 20 // 索引表中不存在該索引項 21 if (item == null) { 22 return false; 23 } 24 25 // 根據索引項將值插入到主表中 26 mainList[item.start + item.length] = key; 27 // 更新索引表 28 indexItemList[i].length++; 29 30 return true; 31 }
打印主表的函數:
1 /** 2 * 遍歷打印 3 */ 4 public static void display(int[] list) { 5 System.out.println("******** 展示開始 ********"); 6 if (list != null && list.length > 0) { 7 for (int i = 0; i < list.length; i++) { 8 System.out.print(list[i] + " "); 9 if ((i + 1) % 10 == 0) { 10 System.out.println(""); 11 } 12 } 13 } 14 System.out.println("******** 展示結束 ********"); 15 }
測試代碼:
1 public static void main(String[] args) { 2 System.out.println("******** 索引查找 ********"); 3 System.out.println(""); 4 System.out.println("原始數據:"); 5 display(mainList); 6 System.out.println(""); 7 8 //分塊查找 9 int key = 203; 10 System.out.println("元素" + key + "列表中的位置為:" + indexSearch(key) + "\n"); 11 12 //按規則插入數據並查找 13 int value = 106; 14 System.out.println("插入數據:" + value); 15 16 // 插入成功,查找插入位置 17 if (insert(value)) { 18 System.out.println("插入后的主表:"); 19 display(mainList); 20 System.out.println(""); 21 22 System.out.println("元素" + value + "在列表中的位置為:" + indexSearch(value)); 23 } 24 }