分块查找算法适用情境:
有些数据并不是按一定顺序排列的,也不是完全没有顺序的,而是在无序中透露出有序,例如下面的数据
7 | 10 | 13 | 19 | 16 | 20 | 27 | 22 | 30 | 40 | 36 | 43 | 50 | 48 |
可以把这些数据按照下面的方式进行分块
7 | 10 | 13 |
19 | 16 | 20 |
27 | 22 | 30 | 40 | 36 |
43 | 50 | 48 |
遵循的原则:
1.前一块中的最大数据,小于后一块中的所有数据(块内无序,块间有序)
2.块数数量一般等于数据的个数开根号。例如16个数据一般分为4块左右
这就是分块查找的核心思路:先确定要查找的元素在哪一块,然后在块内一个个查找
代码实现思路:
(1)先存储四块数据的信息对每一块都创建对象,具体是通过创建数组blockArr存放每一个块对象的信息
(2)查找blockArr确定要查找的数据属于哪一块
(3)在块中单独遍历这一数据
代码实现:
int[] arr = {17,5,9,12,23,19,32,24,37,27,45,36,50,49,61,57,72,66};
例如我们要查询元素number是否在数组arr中,先对其进行分块,要遵循分块的原则,初步使其分成下面四块
int[] arr = {17,5,9,12,
23,19,
32,24,37,27,45,36,
50,49,61,57,72,66};
数据不是很均匀,为了使其更加均匀在保证分块原则的前提下考虑分成三块
int[] arr = {17,5,9,12,23,19,
32,24,37,27,45,36,
50,49,61,57,72,66};
用下面的类来描述这个块
class Block {
private int max; //块中的最大值
private int startIndex; //起始索引
private int endIndex; //结束索引
}
将其补充为JavaBean类,然后创建三个块的对象
Block b1 = new Block(23,0,5);
Block b2 = new Block(45,6,11);
Block b3 = new Block(72,12,17);
//管理三个块的对象(索引表)
Block[] blockArr = {b1,b2,b3};
//记录要查找的元素
int number = 36;
首先确定number在哪一个块中,定义方法得到在索引表中的索引
public static int findIndexBlock(Block[] blockArr,int number){
//从0索引开始遍历blockArr,如果nubmer小于max,那么number就在这个块中
for (int i = 0; i < blockArr.length; i++) {
if(number <= blockArr[i].getMax()){
return i;
}
}
return -1;
}
通过上个方法再利用分块查找的原理,查询number的索引
private static int getIndex(Block[] blockArr, int[] arr, int number) {
// 1.确定number是在哪一个块中
int indexBlock = findIndexBlock(blockArr,number);
if(indexBlock == -1){
//表示number不在块中
return -1;
}
// 2.获取这一块的起始索引和结束索引
int startIndex = blockArr[indexBlock].getStartIndex();
int endIndex = blockArr[indexBlock].getEndIndex();
// 3.遍历
for (int i = startIndex; i <= endIndex ; i++) {
if(arr[i] == number){
return i;
}
}
//表示number不在数组中
return -1;
}
正式查找中,调用方法,传递索引表,数组以及要查找的元素,最后打印得出索引值,没有找到则返回-1
int index = getIndex(blockArr,arr,number);
System.out.println(index);
完整代码:
public class divideBlock {
public static void main(String[] args) {
int[] arr = {17,5,9,12,23,19,
32,24,37,27,45,36,
50,49,61,57,72,66};
//创建三个块的对象
Block b1 = new Block(23,0,5);
Block b2 = new Block(45,6,11);
Block b3 = new Block(72,12,17);
//管理三个块的对象(索引表)
Block[] blockArr = {b1,b2,b3};
//记录要查找的元素
int number = 36;
//调用方法,传递索引表,数组以及要查找的元素
int index = getIndex(blockArr,arr,number);
//打印
System.out.println(index);
}
//分块查找的原理,查询number的索引
private static int getIndex(Block[] blockArr, int[] arr, int number) {
// 1.确定number是在哪一个块中
int indexBlock = findIndexBlock(blockArr,number);
if(indexBlock == -1){
//表示number不在数组中
return -1;
}
// 2.获取这一块的起始索引和结束索引
int startIndex = blockArr[indexBlock].getStartIndex();
int endIndex = blockArr[indexBlock].getEndIndex();
// 3.遍历
for (int i = startIndex; i <= endIndex ; i++) {
if(arr[i] == number){
return i;
}
}
return -1;
}
//确定number在哪一个块中
public static int findIndexBlock(Block[] blockArr,int number){
//从0索引开始遍历blockArr,如果nubmer小于max,那么number就在这个块中
for (int i = 0; i < blockArr.length; i++) {
if(number <= blockArr[i].getMax()){
return i;
}
}
return -1;
}
}
class Block {
private int max; //最大值
private int startIndex; //起始索引
private int endIndex; //结束索引
public Block() {
}
public Block(int max, int startIndex, int endIndex) {
this.max = max;
this.startIndex = startIndex;
this.endIndex = endIndex;
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
public int getStartIndex() {
return startIndex;
}
public void setStartIndex(int startIndex) {
this.startIndex = startIndex;
}
public int getEndIndex() {
return endIndex;
}
public void setEndIndex(int endIndex) {
this.endIndex = endIndex;
}
public String toString() {
return "Block{max = " + max + ", startIndex = " + startIndex + ", endIndex = " + endIndex + "}";
}
}
最后要查找的元素为36,运行后得到在数组中的索引-------11