1. 程式人生 > >java 二分查詢法和順序查詢法的效率比較

java 二分查詢法和順序查詢法的效率比較

專案背景:

從一個檔案獲取10萬筆字串型別資料,資料庫表中查詢出符合條件的5千數字符竄型別資料。把兩者匹配的資料查詢出來。

結論:

1、如果數量級不大,二種方式速度差不多
2、如果數量級較大
   *如果源資料是有序的,則二分查詢法效率高
   *如果源資料是無序的,則順序查詢法效率高

原因:

1、字串排序非常耗時

2、二分查詢法需要先排序

執行結果

----------------根據順序查詢法查詢數字-----start
構建的源陣列長度為:10000
從源陣列中隨機抽取500個構建第二個陣列
總共找到的數字個數為:500
總耗時為:14毫秒
end
----------------先對整形陣列進行排序,根據二分查詢法查詢-----start
構建的源陣列長度為:10000
從源陣列中隨機抽取500個構建第二個陣列
10000個數字排序耗時:188毫秒
總共找到的數字的個數為:500
總耗時為:189毫秒
end
----------------根據順序查詢法查詢字元竄-----start
構建的源陣列長度為:10000
從源陣列中隨機抽取500個構建第二個陣列
總共找到的字元竄的個數為:500
總耗時為:42毫秒
end
----------------先對字串陣列進行排序,根據二分查詢法查詢字元竄-----start
構建的源陣列長度為:10000
從源陣列中隨機抽取500個構建第二個陣列
10000個字串排序耗時:1021
總共找到的字元竄的個數為:500
總耗時為:1021毫秒
end

原始碼

package test;

import java.util.Random;
import java.util.UUID;

public class A {

	/**
	 * @param 順序查詢法、二分查詢法的比較結論
	 * 1、如果數量級不大,二種方式速度差不多
	 * 2、如果數量級較大
	 *    *如果源資料是有序的,則二分查詢法效率高
	 *    *如果源資料是無序的,則順序查詢法效率高
	 */
	public static void main(String[] args) throws Exception {
		testIntArr2(10000, 500);
		testIntArr1(10000, 500);
		testStringArr2(10000, 500);
		testStringArr1(10000, 500);
	}
	
	/**
	 * 整形:使用順序查詢法搜尋陣列
	 * @param oldLength
	 * @param newLength
	 * @throws Exception
	 */
	public static void testIntArr2(int oldLength,int newLength) throws Exception{
		System.out.println("----------------根據順序查詢法查詢數字-----start");
		int[] arr1 = createIntArr(oldLength);//生成一個包含oldLength個字串的陣列
		int[] arr2 = getIntArrFromOtherArr(arr1,newLength);//從陣列中挑選newLength個字串組成第二個陣列
		long t0=(long) System.currentTimeMillis();//開始計時
		int searchedNum=0;
		for(int i=0;i<arr2.length;i++){
			int temp = arr2[i];
			for(int j=0;j<arr1.length;j++){
				if(temp==arr1[j]){
					searchedNum++;
					continue;
				}
			}
		}
		System.out.println("總共找到的數字個數為:"+searchedNum);
		long t1=(long) System.currentTimeMillis();
		System.out.println("總耗時為:"+(t1-t0)+"毫秒");
		System.out.println("end");
	}
	
	/**
	 * 整形:使用二分查詢法搜尋陣列
	 * @param oldLength
	 * @param newLength
	 * @throws Exception
	 */
	public static void testIntArr1(int oldLength,int newLength) throws Exception{
		System.out.println("----------------先對整形陣列進行排序,根據二分查詢法查詢-----start");
		int[] arr1 = createIntArr(oldLength);//生成一個包含oldLength的陣列
		int[] arr2 = getIntArrFromOtherArr(arr1,newLength);//從陣列中挑選newLength個組成第二個陣列
		long t0=(long) System.currentTimeMillis();//開始計時
		sort(arr1);//使用氣泡排序法對陣列1排序
		long t1=(long) System.currentTimeMillis();
		System.out.println(oldLength+"個數字排序耗時:"+(t1-t0)+"毫秒");
		int searchedNum = 0;
		for(int i=0;i<arr2.length;i++){
			int temp = arr2[i];
			if(binarySearch(arr1, temp)>0){
				searchedNum++;
			}
		}
		System.out.println("總共找到的數字的個數為:"+searchedNum);
		long t2=(long) System.currentTimeMillis();
		System.out.println("總耗時為:"+(t2-t0)+"毫秒");
		System.out.println("end");
	}
	
	
	
	
	/**
	 * 字串:使用順序查詢法搜尋陣列
	 * @param oldLength
	 * @param newLength
	 * @throws Exception
	 */
	public static void testStringArr2(int oldLength,int newLength) throws Exception{
		System.out.println("----------------根據順序查詢法查詢字元竄-----start");
		String[] arr1 = createStringArr(oldLength);//生成一個包含oldLength個字串的陣列
		String[] arr2 = getStringArrFromOtherArr(arr1,newLength);//從陣列中挑選newLength個字串組成第二個陣列
		long t0=(long) System.currentTimeMillis();//開始計時
		int searchedNum=0;
		for(int i=0;i<arr2.length;i++){
			String temp = arr2[i];
			for(int j=0;j<arr1.length;j++){
				if(temp.equals(arr1[j])){
					searchedNum++;
					continue;
				}
			}
		}
		System.out.println("總共找到的字元竄的個數為:"+searchedNum);
		long t1=(long) System.currentTimeMillis();
		System.out.println("總耗時為:"+(t1-t0)+"毫秒");
		System.out.println("end");
	}
	
	/**
	 * 字串:使用二分查詢法搜尋陣列
	 * @param oldLength
	 * @param newLength
	 * @throws Exception
	 */
	public static void testStringArr1(int oldLength,int newLength) throws Exception{
		System.out.println("----------------先對字串陣列進行排序,根據二分查詢法查詢字元竄-----start");
		String[] arr1 = createStringArr(oldLength);//生成一個包含oldLength個字串的陣列
		String[] arr2 = getStringArrFromOtherArr(arr1,newLength);//從陣列中挑選newLength個字串組成第二個陣列
		long t0=(long) System.currentTimeMillis();//開始計時
		sort(arr1);//使用氣泡排序法對陣列1排序
		long t1=(long) System.currentTimeMillis();
		System.out.println(oldLength+"個字串排序耗時:"+(t1-t0));
		int searchedNum = 0;
		for(int i=0;i<arr2.length;i++){
			String temp = arr2[i];
			if(binarySearch(arr1, temp)>0){
				searchedNum++;
			}
		}
		System.out.println("總共找到的字元竄的個數為:"+searchedNum);
		long t2=(long) System.currentTimeMillis();
		System.out.println("總耗時為:"+(t2-t0)+"毫秒");
		System.out.println("end");
	}
	
	
	
	/**
	 *二分查詢法:字元竄
	 * @param arr
	 * @param num
	 * @return
	 */
	public static int binarySearch(String[] arr , String num){
		int start =0;
		int end = arr.length-1;
		while(start<=end){
			int mid = (start+end)/2;
			if(num.compareTo(arr[mid]) > 0){
				start=mid+1;
			}else if(num.compareTo(arr[mid]) < 0){
				end=mid-1;
			}else{
				return mid;
			}
		}
		return -1;
	}
	
	/**
	 * 二分查詢法:整數
	 * @param arr
	 * @param num
	 * @return
	 */
	public static int binarySearch(int[] arr , int num){
		int low = 0;
		int upper=arr.length-1;
		while(low<=upper){
			int mid = (low+upper)/2;
			if(arr[mid] < num){
				low = mid+1;
			}else if(arr[mid] > num){
				upper=mid-1;
			}else{
				return mid;
			}
		}
		return -1;
		
	}
	
	/**
	 * 字元竄從小到大排序
	 * @param arr
	 */
	public static void sort(String[] arr){
		for(int i=0;i<arr.length;i++){
			for(int j=0;j<arr.length-i-1;j++){
				if(arr[j].compareTo(arr[j+1]) > 0){
					String temp = arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=temp;
				}
			}
		}
//		for(String x : arr){
//			System.out.println(x);
//		}
		
	}
	
	/**
	 * 整形陣列氣泡排序:從小到大
	 */
	public static void sort(int[] arr){
		for(int i=0;i<arr.length;i++){
			for(int j=0;j<arr.length-i-1;j++){
				if(arr[j]>arr[j+1]){
					int temp = arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=temp;
				}
			}
		}
//		for(int x : arr){
//			System.out.println(x);
//		}
	}
	
	/**
	 * 構建字串陣列---包含num個uuid
	 * @return
	 */
	public static String[] createStringArr(int num){
		String[] arr = new String[num]; 
		for(int i=0;i<num;i++){
			arr[i] = UUID.randomUUID().toString();
		}
		System.out.println("構建的源陣列長度為:"+arr.length);
		return arr;
	}
	/**
	 * 從源陣列中隨機選擇n個數據,構建第二個陣列
	 * @param source
	 * @return
	 * @throws Exception 
	 */
	public static String[] getStringArrFromOtherArr(String[] source,int n) throws Exception{
		if(n>source.length){
			throw new Exception("不能超過源陣列的長度");
		}
		Random random = new Random();
		String[] arr = new String[n]; 
		for(int i=0;i<n;i++){
			int index = random.nextInt(source.length-1);
			arr[i]=source[index];
		}
		System.out.println("從源陣列中隨機抽取"+arr.length+"個構建第二個陣列");
		return arr;
	}
	
	/**
	 * 構建整形陣列---包含num個整形
	 * @return
	 */
	public static int[] createIntArr(int num){
		Random random = new Random();
		int[] arr = new int[num]; 
		for(int i=0;i<num;i++){
			arr[i] = random.nextInt();
		}
		System.out.println("構建的源陣列長度為:"+arr.length);
		return arr;
	}
	/**
	 * 從源陣列中隨機選擇n個數據,構建第二個陣列
	 * @param source
	 * @return
	 * @throws Exception 
	 */
	public static int[] getIntArrFromOtherArr(int[] source,int n) throws Exception{
		if(n>source.length){
			throw new Exception("不能超過源陣列的長度");
		}
		Random random = new Random();
		int[] arr = new int[n]; 
		for(int i=0;i<n;i++){
			int index = random.nextInt(source.length-1);
			arr[i]=source[index];
		}
		System.out.println("從源陣列中隨機抽取"+arr.length+"個構建第二個陣列");
		return arr;
	}

}