30分钟弄懂快速排序-详解(指针交换法)-递归实现

快速排序

快速排序算是冒泡排序的一个升级版,更高效快捷,常出现在各大面试中。
时间复杂度为O (nlogn)【不用太纠结复杂度】。

非稳定性

注意的是:快速排序不是一种稳定的排序算法,如果遇到相同的值,位置也许会在结束时产生变动。

例如数组:[1,2,8,3,5,8`];排序后结果也许是[1,2,3,5,8,]也可能是[1,2,3,5,,8]

原理

用数组的一个数值当做关键数据(基数),把比他小的数放到左边,比他大的数放到右边。

指针交换法

在开始交换之前需要知道三个数值
1.定义基数(基数可为数组中的任意一个数,现在拿数组第一个数当做基数)
2.定义数组的头部位置,i=0.
3.定义数组的尾部位置,j=N-1.(N为数组长度)

排序如下数组:
在这里插入图片描述

排序步骤

一开始我们先从j往后进行比较( j-1)
1).当 j > index, j--
2).当 i < index, i++
3).当 i 和 j的值相同时,i++然后重复执行第一和二的步骤,条件不满足则将j和i的值交换. 设数组变量名为:A

对应代码:
//1).当 j > index, j-- 
for(;(i < j) && (a[j] > index);)
	--j;
//2).当 i < index, i++
for(;(i < j) && (a[i] < index);)
	++i;
//).当 i 和 j的值相同时,i++然后重复执行第一和二的步骤,条件不满足则将j和i的值交换.
if ((a[i]==a[j])&&(i<j)) {     
	++i;
else{
	//利用第三方交换数据
	int temp = A[i];
	A[i] = A[j];
	A[j] = temp;
}
排序演示

在这里插入图片描述
此时,index = 5,i = 0.j = 7.

步骤

1.从后面开始找,当j–到 j=2时,找到第一个小于index的数
2.从i位置找,目前这个数组中A[i] = 5,index 也为 5,不满足 i < index 所以也算比index大
3.A[i]不等于a[j],交换数据.重复执行1,2个步骤

在这里插入图片描述
当第一二步重复执行完后i = 2,j = 2,当i = j时结束本轮排序.

在这里插入图片描述
从上图来看,可以直观的看到,基数左边的数比他小,右边的数比他大.

第二轮排序

1)将数组A划分成两部分

在这里插入图片描述

对于刚刚分割的前后两部分数,可以采用上面同样的方法来排序。

我再演示一遍a2的排序,a1就不演示了.

现在102对应i的位置应该是4,j位置为N-1,基数设置为102吧 当前变量为 index = 102,i = 4,j=8;

在这里插入图片描述

走完步骤第一二步,数值交换.重复执行第一二步

在这里插入图片描述

结果如下,本轮分割结束

在这里插入图片描述

当排序完后的分割,如果基数旁边没有数值了,就不用分割另个数组了。 这是分割后的数组,只切割出了一个数组.

在这里插入图片描述
完整代码如下:

import java.util.Random;

public class FastSort2 {
	static int count = 1;
	public static void main(String[] args) {
		
		int a[] =  new int[] {5,3,4,102,7,6,8,13};
		/*int a[] = new int[10000000];
		Random rm = new Random();
		for(int i=0;i<a.length;i++) {
			a[i] = rm.nextInt(10000);
		}*/
		long Strat = System.currentTimeMillis();
		method(a,0,a.length - 1);
		long j = System.currentTimeMillis();
		
		System.out.println(j - Strat);
		for(int c: a) {
			System.out.print(c + " ");
		}
	}
	//交换数据
	public static void exchange(int[] a,int i,int j) {
		 int temp = a[i];                
         a[i] = a[j];                
         a[j] = temp;    
	}
	public static void method(int[] a, int low, int right) {
		if(right < low) {
			return;
		}
		//定义基数,数组头部和数组尾部
		int i = low, j = right,index = a[low];
		
		while (i < j) {
			//从后面开始找,直到找到第一个小于index的数
			for(;(i < j) && (a[j] > index);)
				--j;
			//前面找,直到找到第一个大于index的数
			for(;(i < j) && (a[i] < index);)
				++i;
			if ((a[i]==a[j])&&(i<j)) {                
	            ++i;            
	        } else {                
	        	//交换两个数值的值
	        	exchange(a,i,j);       
	        }
			System.out.format("第%d次分割,基数 = %d,当前i=%d,j=%d\n", count++,index,i,j);
			for(int c: a) {
				System.out.print(c + " ");
			}
			System.out.println();
			//当排序完后的分割,如果基数旁边没有数值了,就不用分割另个数组了。
			//i - 1 和 j + 1这两个条件,就是为了确认是否有超出数组的边界范围。
			if(i - 1 > low) {
				method(a,low,i - 1);
			}
			if(j + 1 < right) {
				method(a,j+1,right);
			}
		}
	}
}


小结

希望通过本文,能理解快速排序~~~~~~~~~~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值