淺析java歸併排序的遞歸算法和迭代算法

1.遞歸算法的實現

遞歸算法相對來講更好理解些,採用分治法進行實現,在拆分的元素個數小於三個的時候進行排序。這裏first,last和mid都爲數組元素的下標值。

private void mergeSort1(int[] src, int temp[], int first, int last) {
		if (last - first < 3) {// 拆分的元素個數小於等於3的時候進行排序
			sort(src, first, last);
			return;
		}

		int mid = (first + last) / 2;
		mergeSort1(src, temp, first, mid);
		mergeSort1(src, temp, mid + 1, last);


		int i = first;// 二分歸併第一組元素的頭指針
		int j = mid + 1;// 二分歸併第二組元素的頭指針
		int k = first;// 臨時數組的頭指針


		while (i <= mid && j <= last) {
			temp[k++] = src[i] < src[j] ? src[i++] : src[j++];
		}
		while (i > mid && j <= last) {
			</span>temp[k++] = src[j++];
		}
		while (j > last && i <= mid) {
			temp[k++] = src[i++];
		}


		arrayCopy(src, temp, first, last);


	}


	// 將臨時數組的數據拷貝到原數組當中temp->src
	private void arrayCopy(int[] to, int[] from, int first, int last) {
		for (int i = first; i <= last; ++i) {
			to[i] = from[i];
		}
	}


	private void arrayCopy(int[] src, int[] temp) {
		arrayCopy(src, temp, 0, src.length - 1);
	}


	private void sort(int[] src, int first, int last) {
		// 採用冒泡排序的方式對小於等於3個的拆分過的數組進行排序
		int temp = 0;
		for (int i = first; i < last; ++i) {
			for (int j = first; j < last - i + first; ++j) {
				if (src[j] > src[j + 1]) {
					</span>temp = src[j];
					</span>src[j] = src[j + 1];
					</span>src[j + 1] = temp;
				}
			}
		}
	}


2.歸併排序的迭代算法

歸併排序的算法邏輯比較不容易理清,請大家自己代入幾個數試一下很快就會明白。


private void mergeSort2(int[] src, int[] temp) {
		
		//設置最開始分隔元素的距離爲2
		
//		如果我們要排序的數組爲5,4,3,2,1  那麼第一次就應該對間隔爲2的元素進行先簡單排序再歸併
//		排序後數組爲4,5   2,3    1
//		然後此時對4,5   2,3  進行歸併,1自然落下
//		而後數組變爲2,3,4,5  然後space進行加倍,重複步驟,此時space不爲2,所以不再進行排序,直接
//		進行歸併
		
		int space = 2;
		// 下次是否是歸併到原數組中的判斷。  最開始的歸併是從src到temp數組中進行的
		boolean toSrc = false;
		int len = src.length;
		
		if(len == 2){
			int temp1 = 0;
			if(src[0]>src[1]){
				temp1 = src[0];
				src[0] = src[1];
				src[1] = temp1;
			}
		}
		int first = 0, last = 0, mid = 0;
		while (space < len) {
			for (int i = 0; i < len; i = last + 1) {
				first = i;
				mid = first + space - 1;
				last = first + space * 2 - 1;
				//在最末尾的元素大於數組最後一個元素的下標值時,將last設置爲最後元素的下標值
				if (last >= len - 1)
					last = len - 1;
				// 在mid<=last的時候 我們認爲數組中最後剩餘的元素可以進行歸併而不是直接落入下次歸併中
				if (mid <= last) {
					if (space == 2) {
						compareForSwap(src, first, mid, last);
					}
					if (!toSrc) {
						//向temp中進行歸併
						merge(src, temp, first, mid, last);
					} else {
						//向src中進行歸併
						merge(temp, src, first, mid, last);
					}
				}else{
					if (!toSrc) {
						//向temp中進行拷貝剩餘元素
						arrayCopy(temp, src, first, last);
					} else {
						//向src中進行拷貝剩餘元素
						arrayCopy(src, temp, first, last);
					}
					
				}

			}
			// 代表下一步該歸併到那個數組中
			toSrc = !toSrc;
			
			
			space *= 2;
		}
		// 如果下一步該要歸併到src中,代表現在已經正確歸併的值留在了temp中 我們需要將他們複製到src中
		if (toSrc) {
			arrayCopy(src, temp);
		}

	}

	//實現元素之間的比較判斷以及交換
	private void compareForSwap(int[] src, int first, int mid, int last) {
		int temp = 0;
		if (src[first] > src[mid]) {
			temp = src[first];
			src[first] = src[mid];
			src[mid] = temp;
		}
		//這裏用if判斷使當最後的元素不足時不進行交換
		if (mid + 1 < last) {
			if (src[mid + 1] > src[last]) {
				temp = src[mid + 1];
				src[mid + 1] = src[last];
				src[last] = temp;
			}
		}
	}

	private void merge(int[] from, int[] to, int first, int mid, int last) {
		int i = first;// 二分歸併第一組元素的頭指針
		int j = mid + 1;// 二分歸併第二組元素的頭指針
		int k = first;// to數組的頭指針

		while (i <= mid && j <= last) {
			to[k++] = from[i] < from[j] ? from[i++] : from[j++];
		}
		while (i > mid && j <= last) {
			to[k++] = from[j++];
		}
		while (j > last && i <= mid) {
			to[k++] = from[i++];
		}
	}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章