• 【Java】快速排序的非递归实现


      快速排序一般采用递归方法(详见快速排序及其优化),但递归方法一般都可以用循环代替。本文实现了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

    收获

      递归改为非递归,联想到栈的使用,根据对核心代码的循环,确定栈中存储什么数据。

    更多:数据结构与算法合集

  • 相关阅读:
    【Oracle】将表名与字段名连接成一行数据展示,字段名使用顿号的分隔
    【Accountancy】资产
    【FinacialKnowledge】财务报表及名词解释
    模块独立性原理
    C# this.Invoke()的作用与用法
    浅谈C#委托和事件(转载)
    C#三种定时器的实现
    一张图看懂开源许可协议,开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
    c++ comment
    C#使用StreamWriter类写入文件文件
  • 原文地址:https://www.cnblogs.com/yongh/p/9652704.html
Copyright © 2020-2023  润新知