算法:静态查找算法

查找是最简单的算法了。但是查找的算法不同,也会有不同的差距。

1、带哨兵的顺序查找。
很简单,我先上代码:

int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public static int findKey(int[] a, int key) {
	int index = a.length;
	while(index -- > 0) {
		if(a[index] == key)
			return index;
	}
	return -1;
}

这样做是做了两次判断(while循环做了一次,if语句又做了一次),如果有了哨兵,我们就可以节约一次判断。我们通常把哨兵放在数组下标为0的位置。
数组的结构和查找函数发生了如下变化:

int key = 5;
int[] a = new int[] { key, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public static int findKey(int[] a, int key) {
	int index = a.length - 1;
	while (a[index --] == key) {
		return index;
	}
	return 0;
}

这样的话,如果findKey结果返回0,则代表查找失败,即数组a中并未有key值的位置。

2、折半查找
折半查找是基于数组有序的,即从大到小,或者从小到大。然后数组内容为1 2 3 4 5 6 7 8 9,且要查找key = 8的位置。我们可以看看算法实现:

public static int findKey(int[] a, int key) {
	int low = 0;
	int high = a.length - 1;
	int middle;
	while (low <= high) {
		middle = (low + high) / 2;
		if (a[middle] == key)
			return middle;
		else if (key < a[middle])
			high = middle - 1;
		else
			low = middle + 1;
	}
	return -1;
}

也就是说如果要查找8的话,low = 0, high = 8,middle = (8+0)/2=4。因为a[middle] < key,那我们就锁定4-8再来一次折半。
一开始也说了,折半查找算法是基于数组有序的,但是这样查找的效率会高。一般来说,涉及到折半、递归的,效率都为O(log2N)。

3、分块查找
分块查找是类似于顺序查找与折半查找的混合。
查找的数组是按关键字有序的,每个结点含有最大关键字域和指向本块第一个结点的指针。
结构如下:

class Indetype {
	int max; // 块间最大值
	int start; // 块的起始位置
}

这里写图片描述
首先需要找到块间的最大值。
而每组的大小为6是随意的,为了更好的演示,我设置每组的大小为7。且保证当前块的最小值要比前一块的最大值要大
首先要建立索引表:

class IndexType {
	int max; // 块内最大值
	int start; // 块内开始位置
}
public static int findKey(int[] a, int key) {
	int pieceCount = 0; // 计算块个数
	if (a.length % 7 == 0)
		pieceCount = a.length / 7;
	else
		pieceCount = a.length / 7 + 1;

	IndexType[] indexType = new IndexType[pieceCount]; // 初始化块数据
	for (int i = 0; i < pieceCount; i++) {
		indexType[i] = new IndexType();
		indexType[i].start = 7 * i;
	}

	for (int i = 0; i < pieceCount - 1; i++) { // 找到前pieceCount - 1块的最大值
		int max = indexType[i].start;
		for (int j = indexType[i].start; j < indexType[i + 1].start; j++) {
			if (max < a[j])
				max = a[j];
		}
		indexType[i].max = max;
	}

	int max = indexType[pieceCount - 1].start; // 找到最后一块的最大值
	for (int i = indexType[pieceCount - 1].start; i < a.length; i++) {
		if (max < a[i])
			max = a[i];
	}
	indexType[pieceCount - 1].max = max;
	
	if(key > indexType[pieceCount-1].max) // 如果大于最后一块的最大值,就返回-1
		return -1;

	// 找到key所在的块内范围,采用顺序查找
	int index = 0;
	for (index = 0; index < pieceCount - 1; index++) {
		if (indexType[index].max >= key)
			break;
	}
		
	//找到块内具体的位置,采用顺序查找
	int low = 0;
	int high = 0;
	if (index == pieceCount-1) {
		low = indexType[index].start;
		high = a.length;
	}
	else {
		low = indexType[index].start;
		high = indexType[index +1].start;
	}
	for(int i = low; i < high; i ++) {
		if(a[i] == key)
			return i;
	}
	return -1;
}

调用上述函数:

int a[] = new int[] { 22, 12, 13, 8, 9, 20, 33,
	42, 44, 39, 24, 48, 60, 58,
	74, 57, 86, 53, 91, 95, 97,
	100, 98, 101
};
int key = 20;
int position = findKey(a, key);
System.out.println(position);

猜你喜欢

转载自blog.csdn.net/new_Aiden/article/details/50984809