1. 程式人生 > >從給定陣列中找出最大的兩個數——二分遞迴

從給定陣列中找出最大的兩個數——二分遞迴

分析1:對於給定陣列找出其中最大的兩個數,很容易想到的就是遍歷陣列。首先遍歷整個陣列,找出最大的一個元素並記錄下該位置;然後分別遍歷該位置之前的區間和該位置之後的區間,分別找出這兩個子區間的最大值,然後比較這兩個子區間的最大值,大者即為整個陣列的次大元素。顯然,整個過程中,用到了三次for迴圈,演算法的時間複雜度是比較大的,對於規模較小的陣列尚且可以,但是當問題的規模非常大時,這種遍歷的方法就不可行了。

分析2:設定兩個指標,分別指向陣列的最大值和次大值(初始化時指向陣列的前兩個元素)。此後遍歷陣列的所有元素,每個元素都與這兩個指標所指元素進行比較,到最後就能確定最大值和次大值。但是複雜度與第一種方法不相上下。

分析3:遞迴+分治的方法。

遞迴:分別找出左右兩個區間的最大值與次大值,然後通過比較這四個值的大小,確定整個陣列的最大值與次大值。

遞迴基:區間元素為兩個或三個的情況。

下面給出程式碼:

// 找出給定陣列中最大的兩個數

#include <iostream>
using namespace std;

void max2(int A[], int lo, int hi, int& x1, int& x2);
int main()
{
	int A[10] = {8, 3, 30, 25, 10, 22, 31, 35, 21, 19};
	int x1 = 0;
	int x2 = 0;
	max2(A, 0, 9, x1, x2);
	cout << "x1 = " << x1 << endl;
	cout << "x2 = " << x2 << endl;
	return 0;
}

void max2(int A[], int lo, int hi, int& x1, int& x2){
	//x1存放最大的一個元素,x2存放次大的元素
	
	//只有兩個元素的情況
	if(lo + 1 == hi){
		if(A[lo] >= A[hi]){
			x1 = A[lo];
			x2 = A[hi];
			return;
		}
		else{
			x1 = A[hi];
			x2 = A[lo];
			return;
		}
	}
	
	//只有三個元素的情況
	if(lo + 2 == hi){
		if(A[lo] >= A[lo+1]){
			x1 =  A[lo];
			x2 = A[lo+1];
			if(A[hi] > x2)
				if(A[hi] > x1){
					x2 = x1;
					x1 = A[hi];
					return;
				}
				else{
					x2 = A[hi];
					return;
				}
		}
		else{
			x1 = A[lo+1];
			x2 = A[lo];
			if(A[hi] > x2)
				if(A[hi] > x1){
					x2 = x1;
					x1 = A[hi];
					return;
				}
				else{
					x1 = A[hi];
					return;
				}
		}
	}
	
	//有四個及以上的元素就可以通過分治遞迴的方式劃分成上面兩種情況
	int mi = (lo+hi) / 2;
	//分別計算左右兩個區間的最大的兩個數
	int x1L, x2L, x1R, x2R;
	max2(A, lo, mi, x1L, x2L);
	max2(A, mi+1, hi, x1R, x2R);
	
	if(x1L >= x1R){
		x1 = x1L;
		x2 = x2L > x1R ? x2L : x1R;
		return;
	}
	else{
		x1 = x1R;
		x2 = x1L > x2R ? x1L : x2R;
		return;
	}
}