1. 程式人生 > >【Java】快速排序的非遞歸實現

【Java】快速排序的非遞歸實現

scrip swa java版 sys ext 遞歸實現 ref src 分享

  快速排序一般采用遞歸方法(詳見快速排序及其優化),但遞歸方法一般都可以用循環代替。本文實現了java版的非遞歸快速排序。

更多:數據結構與算法合集

思路分析

  采用非遞歸的方法,首先要想到棧的使用,通過閱讀遞歸調用部分的代碼,思考如何用棧來代替。遞歸調用的核心代碼是 pivot = partition(a, low, high); 每次循環都必須包含這句核心代碼,可以想到,如果要對該行代碼實現循環,只能對low和high采取操作,所以我們在棧中壓入low和high,每個循環彈出一對low和high,用於核心代碼的實現,當棧空後就說明沒有需要排序的部分了,結束循環。
  下面是遞歸代碼和根據遞歸代碼修改成的非遞歸代碼。

遞歸部分代碼:

	/**
	 * 遞歸調用
	 */
	public void qSort(int[] a, int low, int high) {
		int pivot;
		if (low >= high)
			return;
		
		//原始遞歸操作
		// pivot = partition(a, low, high); // 將數列一分為二
		// qSort(a, low, pivot - 1); // 對低子表排序
		// qSort(a, pivot + 1, high); // 對高子表排序

		// 優化遞歸操作
		while (low < high) {
			pivot = partition(a, low, high); // 將數列一分為二
			qSort(a, low, pivot - 1); // 對低子表排序
			low = pivot + 1;
		}
	}

  

修改成的非遞歸代碼:

	/**
	 * 非遞歸
	 */
	public void qSort2(int[] a, int low, int high) {
		int pivot;
		if (low >= high)
			return;
		Stack<Integer> stack = new Stack<Integer>();
		stack.push(low);
		stack.push(high);
		while (!stack.empty()) {
			// 先彈出high,再彈出low
			high = stack.pop();
			low = stack.pop();
			pivot = partition(a, low, high);
			// 先壓low,再壓high
			if (low < pivot - 1) {
				stack.push(low);
				stack.push(pivot - 1);
			}
			if (pivot + 1 < high) {
				stack.push(pivot + 1);
				stack.push(high);
			}
		}
	}

  

註意點:棧彈出的順序與壓入的順序相反,要小心棧的壓入與彈出操作。

完整Java代碼

(含測試代碼)

import java.util.Arrays;
import java.util.Stack;

/**
 * 
 * @Description 快速排序的遞歸與非遞歸實現
 *
 * @author yongh
 * @date 2018年9月14日 下午2:39:00
 */
public class QuickSort {
	public void quickSort(int[] a) {
		if (a == null)
			return;
		qSort(a, 0, a.length - 1);
	}
	/**
	 * 遞歸
	 */
	public void qSort(int[] a, int low, int high) {
		int pivot;
		if (low >= high)
			return;
		
		//原始遞歸操作
		// pivot = partition(a, low, high); // 將數列一分為二
		// qSort(a, low, pivot - 1); // 對低子表排序
		// qSort(a, pivot + 1, high); // 對高子表排序

		// 優化遞歸操作
		while (low < high) {
			pivot = partition(a, low, high); // 將數列一分為二
			qSort(a, low, pivot - 1); // 對低子表排序
			low = pivot + 1;
		}
	}


	public void quickSort2(int[] a) {
		if (a == null)
			return;
		qSort2(a, 0, a.length - 1);
	}
	/**
	 * 非遞歸
	 */
	public void qSort2(int[] a, int low, int high) {
		int pivot;
		if (low >= high)
			return;
		Stack<Integer> stack = new Stack<Integer>();
		stack.push(low);
		stack.push(high);
		while (!stack.empty()) {
			// 先彈出high,再彈出low
			high = stack.pop();
			low = stack.pop();
			pivot = partition(a, low, high);
			// 先壓low,再壓high
			if (low < pivot - 1) {
				stack.push(low);
				stack.push(pivot - 1);
			}
			if (pivot + 1 < high) {
				stack.push(pivot + 1);
				stack.push(high);
			}
		}
	}

	/**
	 * 對數組a中下標從low到high的元素,選取基準元素pivotKey,
	 * 根據與基準比較的大小,將各個元素排到基準元素的兩端。
	 * 返回值為最後基準元素的位置
	 */
	public int partition(int[] a, int low, int high) {

		// 三數取中,將中間元素放在第一個位置
		if (a[low] > a[high])
			swap(a, low, high);
		if (a[(low + high) / 2] > a[high])
			swap(a, (low + high) / 2, high);
		if (a[low] < a[(low + high) / 2])
			swap(a, (low + high) / 2, low);

		int pivotKey = a[low]; // 用第一個元素作為基準元素
		while (low < high) { // 兩側交替向中間掃描
			while (low < high && a[high] >= pivotKey)
				high--;
			a[low] = a[high];
			// swap(a, low, high); //比基準小的元素放到低端
			while (low < high && a[low] <= pivotKey)
				low++;
			a[high] = a[low];
			// swap(a, low, high); //比基準大的元素放到高端
		}
		a[low] = pivotKey; // 在中間位置放回基準值
		return low; // 返回基準元素所在位置
	}

	public void swap(int[] a, int i, int j) {
		int temp;
		temp = a[j];
		a[j] = a[i];
		a[i] = temp;
	}

	// =========測試代碼=======
	//測試的為非遞歸方法quickSort2()
	public void test1() {
		int[] a = null;
		quickSort2(a);
		System.out.println(Arrays.toString(a));
	}

	public void test2() {
		int[] a = {};
		quickSort2(a);
		System.out.println(Arrays.toString(a));
	}

	public void test3() {
		int[] a = { 1 };
		quickSort2(a);
		System.out.println(Arrays.toString(a));
	}

	public void test4() {
		int[] a = { 3, 3, 3, 3, 3 };
		quickSort2(a);
		System.out.println(Arrays.toString(a));
	}

	public void test5() {
		int[] a = { -3, 6, 3, 1, 3, 7, 5, 6, 2 };
		quickSort2(a);
		System.out.println(Arrays.toString(a));
	}

	public static void main(String[] args) {
		QuickSort demo = new QuickSort();
		demo.test1();
		demo.test2();
		demo.test3();
		demo.test4();
		demo.test5();
	}
}

  

技術分享圖片
null
[]
[1]
[3, 3, 3, 3, 3]
[-3, 1, 2, 3, 3, 5, 6, 6, 7]
QuickSort

收獲

  遞歸改為非遞歸,聯想到棧的使用,根據對核心代碼的循環,確定棧中存儲什麽數據。

更多:數據結構與算法合集

【Java】快速排序的非遞歸實現