遞歸 —— 二分查找法 —— 歸並排序


PS:什么是遞歸、二分查找、歸並排序。

遞歸排序大家都不陌生,遞歸簡單的說就是自己在沒有達到目的的同時在此調用本身,把一個大問題層層轉化為和原問題相似的小問題解決,遞歸需要有邊界條件、遞歸前進段和遞歸返回段。當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。

二分查找也稱折半查找(Binary Search),它是一種效率較高的查找方法。但是,折半查找要求線性表必須采用順序存儲結構,而且表中元素按關鍵字有序排列。

歸並排序(MERGE-SORT)是建立在歸並操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合並,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合並成一個有序表,稱為二路歸並

如果想了解更多可以去百度百科查閱即可。下面是簡單例子

1、二分查找法

思路

二分法就是把一個數組折半查找,再折半直到找到數據位置,或者無數據位置。比如說1-100,你選的值是23,那么范圍寫法就是(索引寫法類似)

第一次折半是1-50,51-100,經過查找23<50,是在1-50里。

第二次是1-25,26-50,經過查找23<25,是在1-25里。

..........

使用條件

  • 必須是有序數據
  • 升序和降序start角標和end角標寫法相反
/**
	 * 方法描述:二分查找方法
	 * **/
	public static int twoQueryMethod(int[] data,int query){
		int start=0;				//開始角標
		int end=data.length-1;		//結束角標
		int moddle;
		while(true){
			moddle=(end+start)/2;
			if(data[moddle] == query){
				return moddle;
			}
			//起始角標  >  最后角標   沒有找到
			else if(start > end){
				return data.length;
			}
			else{
				//中間值大於查找值
				if(data[moddle] > query){
					end = moddle-1;
				}else{
					start = moddle + 1;
				}
			}
		}
	}

 上面是用平常的while循環寫的,下面用遞歸的寫法。

2:遞歸---二分查找法

使用遞歸可以取消while的循環使用

/**
	 * 遞歸取代while循環
	 * 
	 * **/
	 //降序查找
	public static int diGuiMethod(int[] data,int search,int start,int end){
		//獲取中間值角標
		int moddle=(start+end)/2;
		if(data[moddle] == search){
			return moddle;
		}else if(start > end){
			return data.length;
		}else{
		//下面是降序
			if(data[moddle]< search){
				return diGuiMethod(data,search,start,moddle-1);
			}else{
				return diGuiMethod(data, search, moddle+1, end);

			}
		}
		
	}
	
	//升序查找
	public static int binarySearch(int[] arr, int data, int beginIndex, int endIndex) {
		int midIndex = (beginIndex + endIndex) / 2;
		if (data < arr[beginIndex] || data > arr[endIndex] || beginIndex > endIndex) {
			return -1;
		}
		if (data < arr[midIndex]) {
			return binarySearch(arr, data, beginIndex, midIndex - 1);
		} else if (data > arr[midIndex]) {
			return binarySearch(arr, data, midIndex + 1, endIndex);
		} else {
			return midIndex;
		}
	}

效率

普通二分查找法和遞歸二分查找都是 O(logN) 但是資料顯示 遞歸二分查找簡介但稍微慢一點。

擴展--分治算法

分治算法的基本思想是將一個規模為N的問題分解為K個規模較小的子問題,這些子問題相互獨立且與原問題性質相同。求出子問題的解,就可得到原問題的解。即一種分目標完成程序算法,簡單問題可用二分法完成。

分治算法--基本思想

當我們求解某些問題時,由於這些問題要處理的數據相當多,或求解過程相當復雜,使得直接求解法在時間上相當長,或者根本無法直接求出。對於這類問題,我們往往先把它分解成幾個子問題,找到求出這幾個子問題的解法后,再找到合適的方法,把它們組合成求整個問題的解法。如果這些子問題還較大,難以解決,可以再把它們分成幾個更小的子問題,以此類推,直至可以直接求出解為止。這就是分治策略的基本思想。

3:歸並排序

歸並排序(MERGE-SORT)是建立在歸並操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合並,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合並成一個有序表,稱為二路歸並。

 歸並排序的條件、使用優點

  • 通過兩個不同的有序數組,互相比較按照比較大小排序
  • 把一個無序的數組分成N個數據,每個數據本身比較一次,之后再和下一個數組比較並合並,以此類推。

3.1:兩個A,B不同的(有序)數組歸並成一個C數組,結果C還是有序的。

public static void mergeTwo(int[] arr1,int[] arr2,int[] mergeArr){
		int aIndex=0,bIndex=0,mIndex=0;
		//兩個數組都有數據時
		while(aIndex < arr1.length && bIndex < arr2.length){
			if(arr1[aIndex]<arr2[bIndex]){
				mergeArr[mIndex++] = arr1[aIndex++];
			}else{
				mergeArr[mIndex++] = arr2[bIndex++];
			}
		}
		//如果兩個數組長度相等,則下方方法就不會執行,如果A長度大於B,則會走第一個while。
		//兩個數組其中一個無數據時
		while(aIndex < arr1.length){
			mergeArr[mIndex++] = arr1[aIndex++];
		}
		while(bIndex < arr2.length){
			mergeArr[mIndex++]=arr2[bIndex++];
		}
		//遍歷結果
		for(int i=0;i<mergeArr.length;i++){
			System.out.println(mergeArr[i]);
		}
	}

 使用

//main方法中使用
	int[] arr1={12,14,15,16};
		int[] arr2={8,22,56,90,100};
		int [] merge=new int[9];
		mergeTwo(arr1, arr2, merge);

 3.2:歸並算法--排序一個無需數組

/**
	 * 一個數組內部進行排序
	 * 
	 * **/
	public static void mergeOne(int arr[],int startInt,int stopInt,int[] cArr){
		//如果范圍是1則直接返回。
		if(stopInt==startInt){
			return;
		}
		else{
			int middle=(startInt+stopInt)/2;
			//開始把數組分開---二分法
			mergeOne(arr, startInt, middle,cArr);
			mergeOne(arr, middle+1, stopInt,cArr);
			mergeTwoSort(arr,startInt,middle,stopInt,cArr);	
		}
	}
	public static void mergeTwoSort(int arr[],int start,int mid,int end,int[] cArr){
		int left=start;//左序列開始角標
		int right=mid+1;//右序列開始角標
		int cIndex=0;//臨時數組
		//當兩邊都有值時執行
		while(left <= mid&& end>=right){
			//比較兩個數組的元素大小,如:A:left=0開始到3,長度為4,B:right=4開始,長度為4,
			if(arr[left]<arr[right])
			{
				cArr[cIndex++]=arr[left++];
			}else{
				cArr[cIndex++]=arr[right++];
			}
		}
		//當右邊數組無元素時執行
		while(left<=mid){
			cArr[cIndex++]=arr[left++];
		}
		//當左邊數組無元素時執行
		while(right<=end){
			cArr[cIndex++]=arr[right++];
		}
		//將臨時數組全部添加進原數組
		cIndex=0;//指針修改為0
		while(start<=end){
			arr[start++]=cArr[cIndex++];
		}
	}

 使用

//mian方法使用
//一個數組內部排序
		int[] arr3={12,4,34,5,6,45,9};
		int[] cArr=new int[7];
		mergeOne(arr3, 0, 6, cArr);
		System.out.println("一個數組內部排序");
		for(int i=0;i<cArr.length;i++){
			System.out.println(cArr[i]);

 歸並效率

O(log2\N)以2為底N的對數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM