学习笔记----快速排序的java实现

快速排序算法是我们学习数据结构必学的算法之一,虽然在java中,对列表的排序可直接使用Collections.sort(List l) (这使用的是归并排序算法) ,对基本类型的数组也有Arrays.sort()(这使用的是改进的快速排序算法),但实现一个快速排序,仍能给自己很多启发。
很多算法书上都使用c或者c++实现快排算法,但是作为一个写惯了java的程序员,再去写c或c++有着各种水土不服(没有丰富的API库帮忙),加上jvm虚拟机性能的提高,也就可以用java回顾一下以前的快速排序算法,也算为面试做个准备。 快速排序的平均时间复杂度能达到O(n*log n),最坏情况下 (元素基本有序,中轴选择总是最大或最小 、元素,此时快速排序退化成冒泡排序)为O(n^2)。
本例中使用随机选择中轴元素的方式降低了最坏情况可能性,并在子数组比较小(在书上推荐是5-15个元素即比较小)的时候停止快排,采用插入排序(最好情况既元素基本有序下,时间复杂度为O(n))完成整个List的排序。 有关快速排序的原理,算法书上已经讲的很清楚了,按照我个人的理解,快速排序就是如何将整个数组通过选择的中轴(key)划分成两个子数组,并且满足(key)这种关系。这就算完成一趟快排了,剩下的只需要递归(key)即可。 快排代码如下:

public class QuickSort {

	static List<Integer> list = new ArrayList<>();
	private static int END_QUICKSORT = 7;

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		for (int i = 0; i < 100000; i++) {
			list.add((int) (Math.random() * 1000));
			//list.add(i);
		}
		long a1 = System.nanoTime();
		
		quickSort(list);

		long a2 = System.nanoTime();
		System.out.println(a2 - a1);
		/*for (Integer temp : list) {
			System.out.println(temp);
		}*/
	}

	public static void quickSort(List<Integer> list) {
		
		quick(list, 0, list.size() - 1);
		

		// 对快排后基本有序数组进行一次插入排序
		insertSort(list);
	}

	private static void insertSort(List<Integer> list2) {
		// TODO Auto-generated method stub
		for (int i = 1; i < list2.size(); i++) {
			int v = list2.get(i);
			int j = i - 1;
			for (; j >= 0 && list2.get(j) > v; j--) {
				list2.set(j + 1, list.get(j));
			}
			list.set(j + 1, v);
		}
	}

	private static void quick(List<Integer> list, int low, int hight) {
		// TODO Auto-generated method stub
		if (low < hight) {
			int key = partition(list, low, hight); // 选择中轴并对子数组部分排序
			
			if (key - low > END_QUICKSORT)
				quick(list, low, key - 1); // 对左半部分继续使用快排
			if (hight - key > END_QUICKSORT)
				quick(list, key + 1, hight); // 当(key,hight)范围小到一定程度,不再进行快排
		}
	}

	private static int partition(List<Integer> list, int low, int hight) {
		// TODO Auto-generated method stub
		int rand = (int) (Math.random() * (hight - low)) + low;
		int key = list.get(rand);
		if (rand != low) {
			int temp = list.get(low);
			list.set(low, key);
			list.set(rand, temp);
		}
		while (low < hight) {
			while (low < hight && list.get(hight) >= key)
				hight--;
			list.set(low, list.get(hight));
			while (low < hight && list.get(low) <= key)
				low++;
			list.set(hight, list.get(low));
		}

		list.set(low, key);
		return low;
	}

}

然而比较下原快速排序和随机化快排的代码执行速度发现两者差别并不大,当然在电脑上还存在其它进程影响执行,不够准确,所以这个时间值就不贴出来了。

在JDK中,对快速排序做了如下三个优化,有兴趣的同学可以去看看Arrays.sort方法的源码。
1、就像上面提到的,对于元素数小于7(java内定值)的数组,直接返回插入排序的结果(因为插入排序对基本有序数组和简单数组能保证线性性能,所以一些O(n^2)的算法不一定就不能使用)
2、使用三平均划分法(数组最左边,最右边,最中间的元素的中位数)找到中轴。
3、对于这一点我还不太理解,即是说:将和中轴相等的元素都放到数组中间,如:4,3,1,15,15,15,23,34,21 . 这样只需排序(4,3,1)和(23,34,21)这三个子数组,对于重复元素多的数组可减少问题规模。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值