算法自学笔记:快速排序

快速排序在一般情况下是所有排序算法里面效率最高的,并且属于原地排序(递归需要栈内存为logN,符合原地排序定义)

快速排序原理:
1 选择数组中一个值为基准值,把所有比基准值小的元素移到其左边,所有大于基准值的元素移到其右边
2 将左半数组和右半数组递归进行相同操作,直到数组长为1

示例程序

private static int partition(Comparable[] a, int lo, int hi) {
		int i = lo, j = hi;
		while (true) {
			while (less(a[lo], a[j]) && j > lo) {
				j--;
			}
			while (less(a[i], a[lo])) {
				i++;
			}
			exch(a, i, j);
			if (i >= j) {
				break;
			}
		}
		exch(a, lo, i);
		return i;
	}
	
	
	// eliminate the dependency on input
	private static void shuffle(Comparable[] a) {
		for (int i = 0; i < a.length; i++) {
			exch(a, i, (int)(Math.random() * (i + 1)));
		}
	}
	
	
	private static void sort(Comparable[] a, int lo, int hi) {
		if (hi <= lo) {
			return;
		}
		int j = partition(a, lo, hi);
		sort(a, lo, j - 1);
		sort(a, j + 1, hi);
	}
	
	
	public static void sort(Comparable[] a) {
		shuffle(a);
		sort(a, 0, a.length - 1);
	}

1 partition(Comparable[]a, int lo, int hi)函数:
1 设置两个变量i与j初始指向数组最左和最右元素,设置数组第一个值为基准值
2 移动j指针向左,直到发现小于基准值的第一个数
3 移动i指针向右,直到发现大于基准值第一个数
4 交换i与j位置的数
5 重复上述操作直到i == j,将基准值与此时i(或j)位置的值交换,此时实现该位置左边值均小于基准值,右边值均大于基准值

2 sort(Comparable[] a, int lo, int hi)函数:
用于递归执行partition函数
1 如果发现hi <= lo,说明该子数组只剩一个元素
2 对数组进行分区
3 递归排序分区后数组

3 sort(Comparable[] a)函数:
用户调用
1 把输入数组顺序打乱
2 调用sort

额外说明:
1 保持输入随机性:快速排序在一般情况下时间复杂度为O(NlogN),但是如果在一次切分后一部分没有把数组分为两部分,而是基准值左侧(或右侧)数组为空,快速排序时间复杂度将会降为O(N²)。如果输入数组为有序时会出现该问题。把数组初始打乱可以避免有序数组导致的效率下降。不过,在数组中出现大量重复元素时,即使打乱数组也无法避免性能降低。

2 时间复杂度:快速排序时间复杂度为O(NlogN)
证明:对于最优情况,每次拆分可以把数组对半分,此时满足分治递归Cn = 2Cn/2 + n,2Cn/2为排序子数组成本,n为切分元素和比较的成本。可以证明Cn=nlogn
尽管其实快速排序切分位置为随机,但是一般情况和最优情况区别不大
3 稳定性:快速排序不稳定,因为在切分时交换元素可能会带来大的跨越

算法改进:
1切换到插入排序:快速排序在数组规模很小时速度低于插入排序,因此在数组长度小于10时可以改用插入排序

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值