演算法導論第二章練習

sscout發表於2018-08-01

2.1練習

2.1-1

   (1) 31  41  59  26  41

   (2) 31  41  59  26  41

   (3) 26  31  41  59  41

   (4) 26  31  41  41  59

需要注意的是,這裡的原陣列的後項41在排序後仍在前項41的後面

2.1-2

按降序排序,只需要在迴圈提內部的if判斷中將 < 改為 > 即可,判斷每次插入的數字是否比被插入的陣列中的元素大,若大,則開始執行

2.1-3

public static int searchNum(int[] arr,int num) {
		for(int i = 0;i < arr.length;i++) {
			if(arr[i] == num) {
				return i;
			}
		}
		return (Integer) null;
	}
	

迴圈不變式:在迴圈的每次迭代開始前,A[0...i-1]中不包含值為v的成員

初始化:在第一次迴圈開始之前,即當賦值i = 0時,陣列A[0..-1]中不包含元素,所以顯然所查詢的數字不在其中,所以迴圈不變式成立。

保持:假設本次迭代時i = K,那麼顯然若要執行本次迭代,A[0..k-1]不包含所查詢的數字,即迴圈不變式成立,那麼如果可以執行下次迭代,A[k] 必不等於 v,那麼A[0..k]中也不包含v,那麼迴圈不變式仍然成立。

終止:當i = arr.length時,迴圈結束,或在某次迴圈時A[i] == v終止,當第一種結果出現時,A[0..arr.length - 1]滿足迴圈不變式,即數字不在陣列中;當第二種結果出現時,A[0..k-1]滿足迴圈不變式,即陣列下標k位置為所查詢的數字

2.1-4

public static int[] addBirnaryNum(int[] arrA,int[] arrB) {
		int n = arrA.length;
		int[] arrC = new int[n+1];
		
		int c = 0;//進位
		
		for(int i = n-1;i >= 0;i--) {
			int addBitResult = arrA[i] + arrB[i] + c;
			if(addBitResult > 1) {   //判斷是否有進位出現
				c = 1;
			}
			if(addBitResult == 2 || addBitResult == 0) {   //判斷當前位的情況
				arrC[i+1] = 0;
			}else {
				arrC[i+1] = 1;
			}
		}
		
		if(c == 1) {
			arrC[0] = 1;
		}else {
			arrC[0] = 0;
		}
		
		return arrC;
	}

 

2.2練習

2.2-1

Θ(n³)

2.2-2

(1)

public static void selectionSort(int[] arr) {
		int minmumIndex;
		int minmum;
		
		for(int i = 0;i < arr.length - 1;i++) {
			minmumIndex = i;
			minmum = arr[i];
			for(int j = i+1;j < arr.length;j++) {
				if(arr[j] < minmum) {
					minmumIndex = j;
				}
			}
			
			int temp = arr[minmumIndex];
			arr[minmumIndex] = arr[i];
			arr[i] = temp;
		}
		
	}

(2)迴圈不變式是當迴圈迭代每次開始之前,A[0..k-1]已按序排列

(3)因為在第n-1個元素迭代時,已經比較了第n-1個元素和第n個元素的大小,所以當該次迭代執行完成後,陣列已經是排完序了

(4)最好的情況:Θ(n²)

         最壞的情況:Θ(n²)

2.2-3

平均需要查詢 n/2個元素,最壞需要查詢n個元素

平均情況下執行時間:Θ(n)

最壞情況下執行時間:Θ(n)

2.2-4

我們可以首先設計一個針對該問題的一個特定輸入,使得這個特定輸入是最好的情況,然後不斷修改演算法,使其針對該特列的執行時間達到最佳

 

2.3練習

2.3-1

(1)劃分成單個元素     3       41       52       26       38       57       9       49

(2)解決兩兩排序再合併再排序在合併         

                 3,41       26,52       38,57       9,49

                 3,26,41,52           9,38,49,57

                 3,9,26,38,41,52,57

2.3-2

public static void combine(int[] arr,int p,int q,int r) {
		int n1 = q-p+1;
		int n2 = r-q;
		
		int[] arr1 = new int[n1];
		int[] arr2 = new int[n2];
		
		for(int i = 0;i < n1;i++) {
			arr1[i] = arr[p+i];
		}
		for(int j = 0;j < n2;j++) {
			arr2[j] = arr[q+1+j];
		}
		
		int i = 0;
		int j = 0;
		for(int k = p; k <= r;k++) {		
			if(arr1[i] <= arr2[j]) {
				arr[k] = arr1[i];
				i += 1;
				if(i == n1) {
					for(;j < n2;j++) {
						arr[k+1] = arr2[j];
						k += 1;
					}
					break;
				}
			}else {
				arr[k] = arr2[j];
				j += 1;
				if(j == n2) {
					for(;i < n1;i++) {
						arr[k+1] = arr1[i];
						k += 1;
					}
					break;
				}
			}
		}
	}

2.3-3

證明:

當n = 2時,

T(n)= nlgn = 2*lg2 = 2

∴ 成立

當n = 2^k

假設 T(n/2)= n/2 * lg(n/2) 成立

 ∵  T(n)= 2T(n/2)+ n

∴   T(n)= n* lg(n/2) + n

                 = nlgn - n + n

                 = nlgn

∴ T(n)= nlgn

2.3-4

public static void insert(int[] arr,int p,int q) {
		int i;
		int key = arr[q];
		
		for(i = q-1;arr[i] >= key;i--) {
			arr[i+1] = arr[i];
		}
		
		arr[i+1] = key;
	}



public static void divideAndConquerInsertionSort(int[] arr,int p,int q) {
		if(p < q){
			divideAndConquerInsertionSort(arr,p,q-1);
			insert(arr,p,q);
		}
	}

∴ T(n)= T(n-1)+ cn

2.3-5

遞迴實現

public static int binarySearch(int[] arr,int p,int r,int num) {
		if(p <= r) {
			int q = (p+r)/2;
			if(arr[q] == num) {
				return q;
			}else if(arr[q] > num) {
				return binarySearch(arr,p,q-1,num);
			}else {
				return binarySearch(arr,q+1,r,num);
			}
		}
		return -1;
	}

迭代實現

public static int binarySearch2(int[] arr,int p,int r,int num) {
		int q;
		while(p <= r) {
			q = (p+r)/2;
			if(arr[q] == num) {
				return q;
			}else if(arr[q] > num) {
				r= q-1;
			}else {
				p = q+1;
			}
		}
		return -1;
	}

∵ T(n) = T(n/2)

∴ n/2^i = 1

∴ i = lgn

∴ T(n)= c(lgn + 1) = Θ(lgn)

2.3-6

程式碼實現

public static int binarySearch(int[] arr, int p, int r, int num) {
		int mid = 0;
		while (p <= r) {
			mid = (p + r) / 2;
			if (arr[mid] == num) {
				break;
			} else if (arr[mid] > num) {
				r = mid - 1;
			} else {
				p = mid + 1;
			}
		}
		return mid;
	}



	public static void insertionSort(int[] arr) {
		for(int i = 1;i < arr.length;i++) {
			int j = i-1;
			int index = binarySearch(arr,0,j,arr[i]);
			int temp = arr[i];
			
			if(arr[index] == arr[i]) {
				for(;j >= index;j--) {
					arr[j+1] = arr[j];
				}
			}else if(arr[index] > arr[i]) {
				for(;j > index - 1;j--) {
					arr[j+1] = arr[j];
				}
				arr[index] = temp;
			}else {
				for(;j > index;j--) {
					arr[j+1] = arr[j];
				}
				arr[index + 1] = temp;
			}
			
		}
	}

在該二分查詢的方法中,做了修改,如果沒有查詢到數字,則返回放置時與它最近的一個元素的下標,也就是最後一次mid的位置,如果有這個元素就返回找到元素的下標。

然後在插入排序中進行判斷返回的下標在陣列中的數字是否與插入元素的值相等,如果相等,則在該元素的後面插入,如果大於插入元素,則在該下標前插入元素,如果小於,則該下標之後插入元素。

但是不難看出,因為需要元素移位,那麼迴圈內部必定巢狀迴圈,那麼最後T(n)= Θ(n²),所以不可能

2.3-7

public static boolean findNumInTwoNumSum(int[] arr,int num) {
		int subNum;
		int result;
		
		for(int i = 0;i < arr.length - 1;i++) {
			subNum = num - arr[i];
			result = binarySearch2(arr,0,arr.length - 1,subNum);
			if(result != i && result != -1) {
				return true;
			}
		}
		
		return false;
	}

思路就是,用所給的數逐個減陣列中的元素,然後用二分查詢找減後的數,然後存在,即S中存在兩數之和剛好為x

相關文章