5.4找中位数

快速排速的算法思想其实就是建立在找中位数的基础上,先确定第一次找到的中位数的位置,此时该中位数的位置直至排序结束都是固定不变的,接着循环在该中位数两侧的一堆数值中找中位数的操作,简单来说,就是先找到第一个中位数,接着重复寻找中位数,直至数组完全有序为止。
找找中位数的基本思想
表格示例:

Java 数组的中位数 java输入数组求中位数_排序算法


在一堆无序的数值中,先假设首位的数值为中位数,即此时该假设中位数的下标为0,此时下标为0的位置也定义为begin,然后从后往前找一个比该中位数小或相等的数值,定义此时该值的下标为end,如果没找到,则end的位置向前进1,如果找到了,则该位置先不动,再从起始位置begin,向右寻找比假设中位数的值大的数,如果没有找到,则begin进1,如果找到了,则该位置不动,此时如果begin与end没有相遇,则交换begin与end位置上的值,重复上面的操作直至begin与end相遇,此时该位置就是中位数应该处于的位置,如果该位置不是下标为0的位置,则交换该位置与下标为0位置上的值,此时就找到了中位数,快速排序的思想就是建立在找中位数的基础上循环操作的。

代码示例

public class Test {
    public static void main(String[] args) {

        Random rand = new Random();
        int[] array = new int[10];
        final int LIMIT = array.length * 100;

        //生成array.length个不重复的取值范围为数组长度100倍的随机数
        int size = 0;
        array[size++] = rand.nextInt(LIMIT) + 1;//第一个值不需要验证是否已经重复

        boolean no;
        for (int t; size < array.length; ) {
            t = rand.nextInt(LIMIT) + 1;
            no = true;
            for (int j = 0; j < size; j++) {
                if (array[j] == t) {
                    no = false;
                    break;
                }
            }
            if (no) {
                array[size++] = t;
            }
        }

        System.out.println("之前:");
        for (int i : array) {
            System.out.print(i + "\t");
        }

            //找中位数
            int begin = 0, end = array.length - 1;
            int mid = array[0], t;//假设第0个数是中位数
            while (begin < end) { //begin与end没相遇进入相遇,如果相遇,则不进入循环
                while (begin < end && mid <= array[end]) {//没相遇,并且end位置的数值不比mid小,则end--向左寻找
                    end--;
                }
                while (begin < end && mid >= array[begin]) {//没相遇,并且begin为值得数值不比mid大,则begin++向右寻找
                    begin++;
                }
                if (begin < end) {//没相遇,交换begin和end位置上的数值
                    t = array[begin];
                    array[begin] = array[end];
                    array[end] = t;
                }
            }
            if (0 != begin) {//如果中间值不在begin和end相遇的位置,交换0位置和相遇位置上的值
                array[0] = array[begin];
                array[begin] = mid;
            }
        System.out.println("\n之后:");
        for (int i : array) {
            System.out.print(i + "\t");
        }
        }
    }

5.5快速排序

快速排序是对冒泡排序的一种改进,快速排序的思想其实就是建立在找中位数的基础上,进行重复操作的。

基本思想:
1,、通过一趟排序将要排序的数据分割成独立的两部分
2、其中一部分的所有数据都比另外一部分的所有数据都要小
3、然后再按此方法对这两部分数据分别进行快速排序
4、整个排序过程可以递归进行,以此达到整个数据变成有序序列.

快速排序动图演示:(来自网络图片)

Java 数组的中位数 java输入数组求中位数_java_02

代码示例

import java.util.Arrays;

public class QuackSort {

public static void main(String[] args) {
	int[] arr = { -9, 78, 0, 23, -567, 70 };

	quackSort(arr, 0, arr.length - 1);

	System.out.println("arr排序的结果是:" + Arrays.toString(arr));
}

//
public static void quackSort(int[] arr, int left, int right) {
	int l = left; // 左索引
	int r = right; // 右索引
	int pivot = arr[(left + right) / 2]; // pivot 中轴
	int temp = 0; // 临时变量,作为交换时使用
	// while循环的目的:让,比pivot 值小的放到左边,比pivot 值大的放到右边
	while (l < r) {
		// 在pivot左边一直找,找到一个大于等于pivot的值,才退出
		while (arr[l] < pivot) {
			l += 1;
		}
		// 在pivot右边一直找,找到一个小于等于pivot的值,才退出
		while (arr[r] > pivot) {
			r -= 1;
		}
		// 如果l >= r,则说明pivot 的左右两的值,已经按照左边全部是
		// 小于等于pivot值,右边全部是大于等于pivot值.
		if (l >= r) {
			break;
		}
		// 数据交换
		temp = arr[l];
		arr[l] = arr[r];
		arr[r] = temp;
		
		// 如果交换完后,发现这个arr[l] == pivot值,相等 r--, 前移
		if (arr[l] == pivot) {
			r -= 1;
		}
		// 如果交换完后,发现这个arr[r] == pivot值,相等 l++, 后移
		if (arr[r] == pivot) {
			l += 1;
		}
	}
	//如果 l == r, 必须l++, r--, 否则为出现栈溢出
	if(l == r){
		l += 1;
		r -= 1;
	}
	//向左递归
	if(left < r){
		quackSort(arr, left, r);
	}
	//向右递归
	if(right > l){
		quackSort(arr, l, right);
	}
}

}

总结
本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法,相较于冒泡排序、选择排序以及插入排序等归并排序来说性能上更优,所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。