目录
一. 顺序查找和折半查找的实现
1. 顺序查找
1.1 一般线性表的顺序查找
1.2 有序表的顺序查找
2. 折半查找
二. 代码实现
1. 内部节点
2. 类的构造函数
3. 顺序查找
4. 折半查找
三. 代码展示
四. 数据测试
五. 小结
一. 顺序查找和折半查找的实现
1. 顺序查找
顺序查找又称线性查找,顾名思义我们查找的方式就是挨着一个元素一个元素的查找。顺序查找通常分为堆一般无序线性表的顺序查找和对按关键字有序的顺序查找。
1.1 一般线性表的顺序查找
作为一种最直观的查找方法,其基本思想是从线性表的一端开始,逐个检查关键字是否满足给定的条件。若查找到某个元素的关键字满足给定条件,则查找成功,返回该元素在线性表中的位置;若已经查找到表的另一端, 但还没有查找到符合给定条件的元素,则返回查找失败的信息。在这里补充说明其中引入的“哨兵”的作用。
当我们引入哨兵时,我们从数据的最后一位开始判断,当Data i!=Key时,我们将i的值减1,若有Data i的值等于Key则直接返回(我们一定能得到有一个i的值等于Key,因为我们第0位就是Key的值,这样我们在进行循环的时候不用每次判断i是否越界);若不用哨兵,则我们现在的查找变成了在数据里面寻找Data i的值等于Key,且我们每对一个不同的i进行判断就要判断i是否越界(i<Length)。所以这可以让我们少掉不少判断的语句,提升效率。
除此之外,我们这里谈谈平均查找长度ASL:
在查找过程中,一次查找的长度是指需要比较的关键字次数,而平均查找长度则是所有查找过程中进行关键字的比较次数的平均值,其数学定义为:
式子中,n是查找表的长度;是查找第i个数据元素的概率,一般认为每个数据元素的查找概率相等,即;是找到第i个数据元素所需进行的比较次数。平均查找长度是衡量查找算法效率的最主要的指标。
1.2 有序表的顺序查找
若在查找之前就已经知道表是关键字有序的,则查找失败时可以不用再比较到表的另一端就能返回查找失败的信息,从而降低顺序查找失败的平均查找长度。
假设表L是按关键字从小到大排列的,查找的顺序是从前往后,待查找元素的关键字为key,当查找到第i个元素时,发现第i个元素对应的关键字小于key,但第i+ 1个元素对应的关键字大于key,这时就可返回查找失败的信息,因为第i个元素之后的元素的关键字均大于key,所以表中不存在关键字为key的元素。
若要搜索45,则从10开始,10不等于45,继续比较20,接着比较30...直到比较到50依然不等于45,于是直接返回False。
2. 折半查找
折半查找又称二分查找,它仅适用于有序的顺序表。折半查找的基本思想:首先将给定值key与表中中间位置的元素比较,若相等,则查找成功,返回该元素的存储位置;若不等,则所需查找的元素只能在中间元素以外的前半部分或后半部分(例如,在查找表升序排列时,若给定值key大于中间元素,则所查找的元素只可能在后半部分)。然后在缩小的范围内继续进行同样的查找,如此重复,直到找到为止,或确定表中没有所需要查找的元素,则查找不成功,返回查找失败的信息。
二. 代码实现
1. 内部节点
构建一个内部类,用来存储数据,每一个节点由Key(标签),content(内容)构成,构造函数是传入标签,内容构造一个节点。重写了一个输出函数toString。
/**
* An inner class for data nodes. The text book usually use an int value to
* represent the data. I would like to use a key-value pair instead.
*/
class DataNode {
/**
* The key.
*/
int key;
/**
* The data content.
*/
String content;
/**
* ********************
* The first constructor.
* ********************
*/
DataNode(int paraKey, String paraContent) {
key = paraKey;
content = paraContent;
}// Of the first constructor
/**
* ********************
* Overrides the method claimed in Object, the superclass of any class.
* ********************
*/
public String toString() {
return "(" + key + ", " + content + ") ";
}// Of toString
}// Of class DataNode
2. 类的构造函数
传入标签数组,内容数组,构造(length=标签数组的长度)length长度的节点(数据数组),每个节点是对应标签数组,内容数组的数据,完成初始化。
public DataArray(int[] paraKeyArray, String[] paraContentArray) {
length = paraKeyArray.length;
data = new DataNode[length];
for (int i = 0; i < length; i++) {
data[i] = new DataNode(paraKeyArray[i], paraContentArray[i]);
} // Of for i
}// Of the first constructor
3. 顺序查找
根据传入标签,从最后一个标签开始查找,若数据数组里面的标签等于传入的标签值paraKey,查找成功输出结果;若一直到哨兵位仍然没有找到结果,查找失败。
/**
* ********************
* Sequential search. Attention: It is assume that the index 0 is NOT used.
*
* @param paraKey The given key.
* @return The content of the key.
* ********************
*/
public String sequentialSearch(int paraKey) {
data[0].key = paraKey;
int i;
// Note that we do not judge i >= 0 since data[0].key = paraKey.
// In this way the runtime is saved about 1/2.
// This for statement is equivalent to
//for (i = length - 1; data[i].key != paraKey; i--);
for (i = length - 1; data[i].key != paraKey; i--) {
;
}//Of for i
return data[i].content;
}// Of sequentialSearch
4. 折半查找
设置左边界初始化为0,tempLeft = 0;右边界初始化为length-1,tempRight = length - 1;接着当tempLeft≤tempRight的时候,开始循环。当tempMiddle对应的标签等于查找的标签时,查找成功,退出循环。若不等,则判断tempMiddle对应的标签和我们所查找的标签,如果tempMiddle对应的标签≤我们所查找的标签,则修改左边界tempLeft = tempMiddle + 1;同理右边。最终我们得到查找的结果。
/**
* ********************
* Binary search. Attention: It is assume that keys are sorted in ascending
* order.
*
* @param paraKey The given key.
* @return The content of the key.
* ********************
*/
public String binarySearch(int paraKey) {
int tempLeft = 0;
int tempRight = length - 1;
int tempMiddle = (tempLeft + tempRight) / 2;
while (tempLeft <= tempRight) {
tempMiddle = (tempLeft + tempRight) / 2;
if (data[tempMiddle].key == paraKey) {
return data[tempMiddle].content;
} else if (data[tempMiddle].key <= paraKey) {
tempLeft = tempMiddle + 1;
} else {
tempRight = tempMiddle - 1;
}
} // Of while
// Not found.
return "null";
}// Of binarySearch
三. 代码展示
主类:
package Day_41;
public class demo1 {
/**
*********************
* The entrance of the program.
*
* @param args Not used now.
*********************
*/
public static void main(String args[]) {
System.out.println("\r\n-------sequentialSearchTest-------");
int []paraKeyArray;
paraKeyArray=new int[]{1,2,3};
String[] paraContentArray = new String[]{"121","21","324"};
DataArray test=new DataArray(paraKeyArray,paraContentArray);
test.sequentialSearchTest();
System.out.println("\r\n-------binarySearchTest-------");
test.binarySearchTest();
}// Of main
}
调用类:
package Day_41;
/**
* Data array for searching and sorting algorithms.
*
* @author Jian An 2569222191@qq.com.
*/
public class DataArray {
/**
* An inner class for data nodes. The text book usually use an int value to
* represent the data. I would like to use a key-value pair instead.
*/
class DataNode {
/**
* The key.
*/
int key;
/**
* The data content.
*/
String content;
/**
* ********************
* The first constructor.
* ********************
*/
DataNode(int paraKey, String paraContent) {
key = paraKey;
content = paraContent;
}// Of the first constructor
/**
* ********************
* Overrides the method claimed in Object, the superclass of any class.
* ********************
*/
public String toString() {
return "(" + key + ", " + content + ") ";
}// Of toString
}// Of class DataNode
/**
* The data array.
*/
DataNode[] data;
/**
* The length of the data array.
*/
int length;
/**
* ********************
* The first constructor.
*
* @param paraKeyArray The array of the keys.
* @param paraContentArray The array of contents.
* ********************
*/
public DataArray(int[] paraKeyArray, String[] paraContentArray) {
length = paraKeyArray.length;
data = new DataNode[length];
for (int i = 0; i < length; i++) {
data[i] = new DataNode(paraKeyArray[i], paraContentArray[i]);
} // Of for i
}// Of the first constructor
/**
* ********************
* Overrides the method claimed in Object, the superclass of any class.
* ********************
*/
public String toString() {
String resultString = "I am a data array with " + length + " items.\r\n";
for (int i = 0; i < length; i++) {
resultString += data[i] + " ";
} // Of for i
return resultString;
}// Of toString
/**
* ********************
* Sequential search. Attention: It is assume that the index 0 is NOT used.
*
* @param paraKey The given key.
* @return The content of the key.
* ********************
*/
public String sequentialSearch(int paraKey) {
data[0].key = paraKey;
int i;
// Note that we do not judge i >= 0 since data[0].key = paraKey.
// In this way the runtime is saved about 1/2.
// This for statement is equivalent to
//for (i = length - 1; data[i].key != paraKey; i--);
for (i = length - 1; data[i].key != paraKey; i--) {
;
}//Of for i
return data[i].content;
}// Of sequentialSearch
/**
* ********************
* Test the method.
* ********************
*/
public static void sequentialSearchTest() {
int[] tempUnsortedKeys = {-1, 5, 3, 6, 10, 7, 1, 9};
String[] tempContents = {"null", "if", "then", "else", "switch", "case", "for", "while"};
DataArray tempDataArray = new DataArray(tempUnsortedKeys, tempContents);
System.out.println(tempDataArray);
System.out.println("Search result of 10 is: " + tempDataArray.sequentialSearch(10));
System.out.println("Search result of 5 is: " + tempDataArray.sequentialSearch(5));
System.out.println("Search result of 4 is: " + tempDataArray.sequentialSearch(4));
}// Of sequentialSearchTest
/**
* ********************
* Binary search. Attention: It is assume that keys are sorted in ascending
* order.
*
* @param paraKey The given key.
* @return The content of the key.
* ********************
*/
public String binarySearch(int paraKey) {
int tempLeft = 0;
int tempRight = length - 1;
int tempMiddle = (tempLeft + tempRight) / 2;
while (tempLeft <= tempRight) {
tempMiddle = (tempLeft + tempRight) / 2;
if (data[tempMiddle].key == paraKey) {
return data[tempMiddle].content;
} else if (data[tempMiddle].key <= paraKey) {
tempLeft = tempMiddle + 1;
} else {
tempRight = tempMiddle - 1;
}
} // Of while
// Not found.
return "null";
}// Of binarySearch
/**
* ********************
* Test the method.
* ********************
*/
public static void binarySearchTest() {
int[] tempSortedKeys = {1, 3, 5, 6, 7, 9, 10};
String[] tempContents = {"if", "then", "else", "switch", "case", "for", "while"};
DataArray tempDataArray = new DataArray(tempSortedKeys, tempContents);
System.out.println(tempDataArray);
System.out.println("Search result of 10 is: " + tempDataArray.binarySearch(10));
System.out.println("Search result of 5 is: " + tempDataArray.binarySearch(5));
System.out.println("Search result of 4 is: " + tempDataArray.binarySearch(4));
}// Of binarySearchTest
}// Of class DataArray
四. 数据测试
运行结果
五. 小结
这一小节的知识比较简单,但是却十分重要。查找不仅仅运用在顺序存储,还有链式存储等等。顺序查找在这里我们引入了一个哨兵位,可以减少判断的次数,提高效率。折半查找只能应用于有序表,由于每一次查找都可以舍弃一般的查找长度,所以查找的效率较好。