快速排序之我的理解.

很多资料都在说"快速排序""冒泡排序"的一种改进,我没看出来,依我之见,冒泡是最基础最好理解的入门排序算法.任何算法都可以借鉴于此,那是不是任何排序的算法,都是可以说是冒泡的优化?

 

冒泡是交换排序的基础算法,而快排是交换排序的高级算法。快排给我的感觉跟插入排序的感觉很像,都有点挖坑填数的感觉。不同的是插入是一个一个元素的定位,少了分而治之.

 

快速排序主要思路是: 挖坑填数 + 分治法(Divided-and-ConquerMethod).

 

分治法相对来说,还是很好理解,从字面就可以看出,分而治之的意思,以某个标准,或者说是以数组某个元素为中介,将数组划分为两部分,分别进行排序.

 

而挖坑填数,则是理解的难点,尤其是习惯了冒泡算法的交换之后,思路很不容易扭转过来.借用网上的一个例子:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

72

6

57

88

60

42

83

73

48

85

 

第一步, 选择一个pivotpos枢轴点. 其实不要被枢轴这两个看起来高大上的字眼给唬住.理解了的话, 其实就是任意选取一个数值而已.一般我们默认就选第一个.

 

a[0]=72拿到一边去.数组变为:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

XX

6

57

88

60

42

83

73

48

85

 

然后a[0]就空出来了,变成一个等着被填的坑.

 

第二步,从右至左遍历数组,寻找比a[0]=72小的第一个数字,也就是48. 48 填进72空出来的坑.于是数组变为:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

48

6

57

88

60

42

83

73

XX

85

 

第三步,从左至右遍历数组,寻找比a[0]=72大的第一个数字,也就是88,88填入刚才空出来的坑:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

48

6

57

XX

60

42

83

73

88

85

 

循环第二步, 从右到左找小数,42,填坑:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

48

6

57

42

60

XX

83

73

88

85

 

循环第三步,从左到右找大数,到坑的index为止,a[0-4]都比72.没有选择了,于是枢轴点a[0]=72入坑:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

48

6

57

42

60

72

83

73

88

85

 

到此,第一个数字的位置确定下来了.左边都是比它小的,右边都是比它大的.再以72为中点,将数组两边分别看作是一个数组.再次用刚才的方法排序.即可完成最终的排序.我想这也是枢轴点这个词的由来吧.

 

继续算法,对于左边部分:

 

48拿出来,42放进去:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

42

6

57

XX

60

72

83

73

88

85

 

57放进去,48最后入坑:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

42

6

48

57

60

72

83

73

88

85

 

接下来,再次对48左右两边分而治之:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

6

42

48

57

60

72

83

73

88

85

 

待左边排序完成,对最早的枢轴点72右边进行排序:

 

83拿出来,73比它小,入坑:

 

Index

0

1

2

3

4

5

6

7

8

9

Value

6

42

48

57

60

72

73

83

88

85

 

当划分出来的数组长度为1时,递归结束。

 

Index

0

1

2

3

4

5

6

7

8

9

Value

6

42

48

57

60

72

73

83

85

88

 

当划分出来的数组长度为1时,递归结束。遍历完成,标为黄色的数字是被选为枢轴的数字。

 

而其中运用到了递归分别对两端再次遍历,就是常说的分治法.晚点补上代码实现.

 

 

public class MyQuickSort {

	/**
	 * 分治法, 确定每个枢轴的位置.
	 * 
	 * @param a
	 * @param low
	 * @param high
	 * @return
	 */
	private static int partition(int[] a, int low, int high) {
		int pivot = a[low];
		while (low < high) {
			while (low < high && a[high] >= pivot) { // 找到右边第一个比枢轴小的值,循环退出.
				high--;
			}
			a[low] = a[high];
			while (low < high && a[low] <= pivot) { // 左边找到第一个比枢轴大的值,循环退出.
				low++;
			}
			a[high] = a[low];
		}
		a[low] = pivot;
		return low;
	}
	/**
	 * 快速排序, 用递归不断迭代出每次枢轴两边的数组部分.
	 * 
	 * @param a
	 */
	public static void quickSort(int[] a, int low, int high) {
		if (low < high) { //不加会堆溢出.
			int pivotPos = partition(a, low, high);
			quickSort(a, low, pivotPos - 1);
			quickSort(a, pivotPos + 1, high);
		}
	}

	/**
	 * main(),测试用.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		int[] a = new int[]{72, 6, 57, 88, 60, 42, 83, 73, 48, 85};
		quickSort(a, 0, a.length - 1);
		for (int i : a) {
			System.out.print(i + " ");
		}
	}
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值