基础算法系列之排序算法-5. 快速排序

我们之前学习了冒泡排序算法,我们知道,在冒泡排序过程中,只对相邻的两个元素进行比较,因此每次交换两个相邻的元素时只能消除一个逆序。如果能通过两个(不相邻)元素的一次交换,消除多个逆序,则会大大加快排序的速度。而这就是本篇文章讲述的另一种基本排序算法——快速排序算法。


快速排序

 快速排序是通过冒泡排序改进得来的,冒泡排序每次元素的交换只能消除一个逆序,而快速排序的一次元素交换可以消除多个逆序,从而大大提高排序的效率。


快速排序的算法思想

 通过一次元素的交换消除多个逆序,以提高排序的效率。


快速排序的实现过程

     在待排序的n个元素中任取一个元素(通常取第一个元素)作为枢轴,记录它在序列中位置为pivotkey,记录待排序元素的第一个元素的位置为low,最后一个元素的位置为high。通过一次排序之后,比枢轴小的元素全部排列在起左侧,比枢轴大的元素全部在其右侧,然后通过枢轴作为分界线,将原数列一分为二(一个子列从low到pivotkey-1,另一个子列从pivotkey+1到high),对两个新生成的子列重复上述过程,直到所有新生成的子列只有一个元素,则排序完成。

 

   是不是有点抽象,有点难理解,没事~我们举个例子,来演示一下这个过程。

 

   例如:我们要对数列[49,38,65,97,76,13,27,49]进行快速排序。则记录low与pivotkey为0(数组的第一元素位置),high为7(数组的最后一个元素位置),我们从数列最"右"侧(a[high])开始,逐个与枢轴处的值(即a[pivotkey],在这个例子中为49,已用红色标明)进行比较,若元素的值大于等于枢轴值(49),则high自减(high--)。直到将第一个比枢轴处值要小的元素与枢轴值交换,则交换之后数列变为[27,38,65,97,76,13,49,49]。在从数列的最"左"侧(a[low])开始,逐个(即a[low])与a[pivotkey]比较,若元素值小于等于枢轴值,则low自增(low++)。直到将第一个比a[pivotkey]要大的元素与枢轴值交换,则交换后的数列变为[27,38,49,97,76,13,65,49]。重复上述一右一左的过程,直到low>=high。经过这样一次排序之后,数列变为了[27,38,13,49,76,97,65,49]。再对新生成的子列[27,38,13],[76,97,65,49]重复上述过程。

   示意图:

基础算法系列之排序算法-5. 快速排序


代码实现

public static void quickSort(int[] a,int start,int end){
		if( (end - start) <= 0){  //区间长度小于等于1,则排序结束
			return;
		}
		int pivotkey =start;  //定义枢轴
		int low=start;    //定义low,high的位置
		int high=end;
		while(low<high){
		while(low<high && a[high] >=a[pivotkey]){  //从最右侧开始,如果a[high]的值>=枢轴的值,则high--
			high--;
		}
		a[high] = (a[high] + a[pivotkey]) - (a[pivotkey] = a[high]);//交换a[high] 与 a[pivotkey]的值
		pivotkey  =high;  //更改枢轴的位置
		while(low<high && a[low] <=a[pivotkey]){ //从最左侧开始,如果a[low]的值<=枢轴的值,则low++
			low++;
		}
		a[low] = (a[low] + a[pivotkey]) - (a[pivotkey] = a[low]);  //交换a[low] 与 a[pivotkey]的值
		pivotkey=low;   //更改枢轴的位置
		}
		quickSort(a,start,pivotkey-1);  //对分割成的两个子表在次快排
		quickSort(a, pivotkey+1, end);
	}

 

 让我们来测试一下算法吧

public static void main(String[] args) {
		int[] a = new int[]{2,8,4,6,13,9,12,6};
		quickSort(a, 0, a.length-1);
		for(int i : a){
			System.out.print(i+"  ");
		}

	}

 

基础算法系列之排序算法-5. 快速排序

既然学习了快速排序,老规矩,上题~


HDU 1157  Who's in the Middle

Problem Description

FJ is surveying his herd to find the most average cow. He wants to know how much milk this 'median' cow gives: half of the cows give as much or more than the median; half give as much or less.

Given an odd number of cows N (1 <= N < 10,000) and their milk output (1..1,000,000), find the median amount of milk given such that at least half the cows give the same amount of milk or more and at least half give the same or less.

 

 

Input

* Line 1: A single integer N

* Lines 2..N+1: Each line contains a single integer that is the milk output of one cow.

 

 

Output

* Line 1: A single integer that is the median milk output.

 

 

Sample Input

5 2 4 1 3 5

Sample Output

3

题意:有N(N为奇数)头奶牛产奶,求这N头奶牛产奶的中位数。

 

分析:可以先奶牛的产奶量进行快速排序,最后找到N/2位置处的数即为中位数

 

代码实现:

public static void main(String[] args) {
		System.out.println("请输入奶牛的个数(奇数):");
		Scanner input = new Scanner(System.in);
		int n;   // 定义变量n存储奶牛的数量
		do {    //如果n不能奇数,重新输入
			n = input.nextInt();
			if (n % 2 != 0) {
				break;
			}
			else{
				System.out.println("输入不为奇数,请重新输入:");
			}
		} while (true);
		int[] a = new int[n]; // 每天奶牛的产奶量
		System.out.println("请输入每头奶牛的产奶量:");
		for (int i = 0; i < n; i++) {
			a[i] = input.nextInt();
		}
		quickSort(a, 0, a.length - 1); // 进行快排
		System.out.println("中位数:" + a[n / 2]); // 输出结果
		input.close();
	}

	public static void quickSort(int[] a, int start, int end) {
		if ((end - start) <= 0) { // 区间长度小于等于1,则排序结束
			return;
		}
		int pivotkey = start; // 定义枢轴
		int low = start; // 定义low,high的位置
		int high = end;
		while (low < high) {
			while (low < high && a[high] >= a[pivotkey]) { // 从最右侧开始,如果a[high]的值>=枢轴的值,则high--
				high--;
			}
			a[high] = (a[high] + a[pivotkey]) - (a[pivotkey] = a[high]);// 交换a[high]
																		// 与
																		// a[pivotkey]的值
			pivotkey = high; // 更改枢轴的位置
			while (low < high && a[low] <= a[pivotkey]) { // 从最左侧开始,如果a[low]的值<=枢轴的值,则low++
				low++;
			}
			a[low] = (a[low] + a[pivotkey]) - (a[pivotkey] = a[low]); // 交换a[low]
																		// 与
																		// a[pivotkey]的值
			pivotkey = low; // 更改枢轴的位置
		}
		quickSort(a, start, pivotkey - 1); // 对分割成的两个子表在次快排
		quickSort(a, pivotkey + 1, end);
	}

 

让我们来测试一下我们的代码吧。

基础算法系列之排序算法-5. 快速排序


总述

 快速排序算法是一种效率较高的排序算法,它是在冒泡排序的基础之上的进行改进得来的。你学会了吗ヾ(◍°∇°◍)ノ゙

                                        关注我们,免费获取海量java视频学习资源

基础算法系列之排序算法-5. 快速排序