• 算法——查找算法


    1、顺序查找:

    定义:

    顺序查找(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)+"个");
    	    }
    	         
    		
    	}
    }
    

      

    2、折半查找(二分查找)

    定义:

    折半查找(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)+"位");
    		}
    	}
    
    }
    

      

    3、插值查找

    定义:

    插值查找(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)+"个位置");
    		}
    	}
    	
    		
    }
    

      

    4、斐波那契查找

    定义:

    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));
    	}
    
    }
     
  • 相关阅读:
    delphi 字符串查找替换函数 转
    Delphi流的操作
    【BZOJ1316】树上的询问 点分治+set
    【BZOJ2406】矩阵 二分+有上下界的可行流
    【BZOJ1853/2393】[Scoi2010]幸运数字/Cirno的完美算数教室 DFS+容斥
    【BZOJ4999】This Problem Is Too Simple! 离线+树状数组+LCA
    【BZOJ2427】[HAOI2010]软件安装 Tarjan+树形背包
    【BZOJ3217】ALOEXT 替罪羊树+Trie树
    【BZOJ1336】[Balkan2002]Alien最小圆覆盖 随机增量法
    【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT
  • 原文地址:https://www.cnblogs.com/wugongzi/p/11231637.html
Copyright © 2020-2023  润新知