顺序查找(Sequential Search) 又叫线性查找,是最基本的查找技术,它的查找过程是:从表中第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查的记录;如果直到最后一个(或第一个)记录,其关键字和给定值比较都不等时,则表中没有所查的记录,查找不成功。
import java.util.Scanner;
import org.junit.jupiter.api.Test;
/**
* 顺序查找
* @author wydream
*
*/
public class SequelSearch {
public int search(int[] arr,int num) {
if(arr.length==0) {
return -1;
}
for(int i=0;i<arr.length;i++) {
if(arr[i]==num) {
return i;
}
}
return -1;
}
@Test
public void test() {
int[] arr={4,6,2,8,1,9,0,3};
Scanner input=new Scanner(System.in);
System.out.println("请输入你要查找的数:");
int num=input.nextInt();
int result=search(arr,num);
if(result==-1){
System.out.println("你输入的数不存在与数组中");
}
else {
System.out.println("你输入的数字存在,在数组中的位置是第:"+(result+1)+"个");
}
}
}
折半查找(Binary Search) 技术,又称为:二分查找。它的前提是线性表中的记录必须是关键码有序(通常从小到大有序),线性表必须采用顺序存储。折半查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,直到查找成功,或所查找区域无记录,查找失败为止
import org.junit.jupiter.api.Test;
/**
* 二分查找
* 1.循环实现
* 2.递归实现
* @author wydream
*
*/
public class BinarySearch {
//1.循环实现二分查找
public int rank(int[] arr,int num) {
int start=0;
int end=arr.length;
int mid=(start+end)/2;//中间数的下标
while(start<=end) {//退出循环的条件 若一直没找到这个数,则会退出循环
if(arr[mid]==num)
return mid;
else if(arr[mid]>num) {
end=mid-1;
}else {
start=mid+1;
}
mid=(start+end)/2;
}
return -1;
}
//2.递归实现二分查找
public int recursion(int[] arr,int num,int start,int end) {
int mid=(start+end)/2;
if(start==end&&arr[mid]!=num) {
return -1;
}
if(arr[mid]==num) {
return mid;
}else {
if(arr[mid]>num) {
end=mid-1;
return recursion(arr,num,start,end);
}else{
start=mid+1;
return recursion(arr,num,start,end);
}
}
}
//测试
@Test
public void testRank() {
int[] arr= {2,3,6,9,13,18,20,22,24,29,30,45,67,88};
int result=rank(arr,2);
if(result==-1) {
System.out.println("你要查找的数字不在该数组中");
}else {
System.out.println("你查找的数字在数组的第"+(result+1)+"位");
}
}
@Test
public void testRecursion() {
int[] arr= {2,3,6,9,13,18,20,22,24,29,30,45,67,88};
int result=recursion(arr,20,0,arr.length-1);
if(result==-1) {
System.out.println("你要查找的数字不在该数组中");
}else {
System.out.println("你查找的数字在数组的第"+(result+1)+"位");
}
}
}
插值查找(Interpolation Search)是根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在于插值的计算公式。插值计算公式:mid=start+(key-a[start])/(arr[end]-arr[start])*(end-start);
import org.junit.jupiter.api.Test;
/**
* 插值查找(Interpolation Search)是根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在于插值的计算公式
* 插值计算公式:mid=start+(key-a[start])/(arr[end]-arr[start])*(end-start);
* @author wydream
*
*/
public class InsertValueSearch {
//递归实现插值查找
public int recursionBinarySearch(int[] arr,int key,int start,int end) {
//当查找的值小于数组最小值,或者大于数组最大值,或者start>end时查找结束
if(key<arr[start]||key>arr[end]||start>end) {
return -1;
}
if(arr[start]==key) {
return start;
}
if(arr[end]==key) {
return end;
}
int mid = start+(end-start)*((key-arr[start])/(arr[end]-arr[start]));
if(arr[mid]>key) {
//说明key在前半部分
return recursionBinarySearch(arr,key,start,mid-1);
}
else if(arr[mid]<key) {
//说明key在后半部分
return recursionBinarySearch(arr,key,mid+1,end);
}else {
return mid;
}
}
//非递归实现插值查找
public int commonBinarySearch(int[] arr,int key) {
int start=0;
int end=arr.length-1;
if(key<arr[start]||key>arr[end]) {
return -1;
}
int mid = start+(end-start)*((key-arr[start])/(arr[end]-arr[start]));
while(start<=end) {
if(arr[mid]==key) {
return mid;
}else if(arr[mid]>key) {//说明查找的值在mid的前面
end=mid-1;
}else {//说明查找的值在mid的后面
start=mid+1;
}
mid=start+(end-start)*((key-arr[start])/(arr[end]-arr[start]));
}
return -1;
}
//递归测试
@Test
public void testRecursion() {
int[] arr= {1,2,4,5,6,7,8,9};
int result=recursionBinarySearch(arr,1,0,arr.length-1);
if(result==-1) {
System.out.println("你要查找的数不在该数组中");
}else {
System.out.println("你要查找的数在数组的第"+(result+1)+"个位置");
}
}
//非递归测试
@Test
public void testCommon() {
int[] arr= {1,2,4,5,6,7,8,9};
int result=commonBinarySearch(arr,1);
if(result==-1) {
System.out.println("你要查找的数不在该数组中");
}else {
System.out.println("你要查找的数在数组的第"+(result+1)+"个位置");
}
}
}
1.斐波那契实在二分查找基础上,用斐波那契数列来进行分割 2.在斐波那契数列上找一个略大于查找元素表个数的值f(n) 3.将查找元素表个数扩充到f(n) 如果要补充元素用最后一个元素补充 4.完成后对f(n)个元素进行斐波那契分割,即分割成 前面f(n-1)个元素,后面f(n-2)个元素 5.对要查找元素的那个部分进行递归 6.就平均性能而言 优于折半查找 但是若一直在左边长半区查找则低于折半查找
import java.util.Arrays;
import org.junit.jupiter.api.Test;
/*
*----- 斐波那契查找------
* 1.斐波那契实在二分查找基础上,用斐波那契数列来进行分割
* 2.在斐波那契数列上找一个略大于查找元素表个数的值f(n)
* 3.将查找元素表个数扩充到f(n) 如果要补充元素用最后一个元素补充
* 4.完成后对f(n)个元素进行斐波那契分割,即分割成 前面f(n-1)个元素,后面f(n-2)个元素
* 5.对要查找元素的那个部分进行递归
* 6.就平均性能而言 优于折半查找 但是若一直在左边长半区查找则低于折半查找
* */
public class FibonacciSearch {
private static int maxsize=20;
//生成斐波那契数列
public int[] fibonaqie() {
int[] f=new int[maxsize];
f[0]=1;
f[1]=1;
for(int i=2;i<maxsize;i++) {
f[i]=f[i-1]+f[i-2];
}
return f;
}
//查找
public int search(int[] arr,int key) {
int low=0;
int high=arr.length-1;
int k=0;//斐波那契分割数值下标
int mid=0;
int f[]=fibonaqie();
//获得斐波那契分割数值下标
while(high>f[k]-1) { //int [] a= {1,3,5,7,9,11,12}; 6
k++;
}
//利用Java工具类Arrays 构造新数组并指向 数组 arr[]
int[] temp=Arrays.copyOf(arr, f[k]);
//对新构造的数组进行 元素补充
for(int i=high+1;i<temp.length;i++) {
temp[i]=arr[high];
}
while(low<=high) {
//由于前面部分有f[k-1]个元素
mid=low+f[k-1]-1;
if(key<temp[mid]) {
high=mid-1;
/**
*
*全部元素=前部元素+后部元素
* f[k]=f[k-1]+f[k-2]
* 因为前部有f[k-1]个元素,所以可以继续拆分f[k-1]=f[k-2]+f[k-3]
* 即在f[k-1]的前部继续查找 所以k--
* 即下次循环 mid=f[k-1-1]-1
* */
k--;
}else if(key>temp[mid]) {//关键字大于切个位置元素 则查找后半部分
low=mid+1;
/***
* 全部元素=前部元素+后部元素
* f[k]=f[k-1]+f[k-2]
* 因为后部有f[k-2]个元素,所以可以继续拆分f[k-2]=f[k-3]+f[k-4]
* 即在f[k-2]的前部继续查找 所以k-=2
* 即下次循环 mid=f[k-1-2]-1
*/
k-=2;
}else {
if(mid<=high) {
return mid;
}else {
return high;
}
}
}
return -1;
}
@Test
public void test() {
int [] a= {1,3,5,7,9,11,12};
int i=search(a, 5);
System.out.println("5在:"+(i+1));
int j=search(a, 12);
System.out.println("12在:"+(j+1));
}
}