冒泡排序、选择排序、快速排序算法

1.三种排序方案

1.冒泡法排序

以升序为例:

内层循环控制的是求 最大值外层循环控制的是要求几次最大值

		int[] numbers = new int[5];
		for (int i = 0; i < numbers.length; i++) {
			numbers[i] = (int) (Math.random() * 100);
		}
		System.out.println(Arrays.toString(numbers));
		
		// 对数组进行升序排序(从小到大排序)
		// 第一步:把最大数放到最后
		// 第二步:在最外层套上循环次数
		//		  5个数求4次最大数即可
		// 第三部:优化循环次数(第2次比较时,没必要再比较那么多次)
		// 12 34 67 79 48  数组长度为5
		// 比较4次
		for (int j = 0; j < numbers.length - 1; j++) {// 外层循环控制的是要找几次最大值并放到															本次的最后
			for (int i = 0; i < numbers.length - 1 - j; i++) {// 内层循环控制的是找每次的最大值
				// count++;
				if (numbers[i] > numbers[i + 1]) {
					numbers[i + 1] = numbers[i] ^ numbers[i + 1];
					numbers[i] = numbers[i] ^ numbers[i + 1];
					numbers[i + 1] = numbers[i] ^ numbers[i + 1];
				}
			}
		}
		System.out.println(Arrays.toString(numbers));

图示:
在这里插入图片描述

2.选择排序

以升序为例:

内层循环控制的是找最小值的下标,将最小值提到每次循环的最前面

外层循环控制找多少次最小值的下标并将其提到每次的最前面

		int[] numbers = { 15, 34, 64, 78, 67, 7};
		
		System.out.println(Arrays.toString(numbers));
		// 选择排序 --> 升序
		// 第一步:内层循环。假设最前面的数为最小数;(内层循环,将最小数提到最前面)
		//		  写内层循环,通过依次比较,找到更小值的下标,并记录最小值的下标;循环完后,将其与每次循环最前面的数交换
		// 第二步:外层循环。控制循环次数(n个数,求 n-1 次最小值即可 )
		// 第三步:优化
		// 		 第0次循环假设下标为0的数为最小值,第1次循环假设下标为1的数为最小值,第j次循环假设下标为j的数为最小值
		// 		 第0次循环,从第1个数开始和最前面的数比较;第j次循环,从第 j+1 个数开始和最前面的数比较
		// 			都是从第 j 个数到最够一个数
		for (int j = 0; j < numbers.length - 1; j++) {
			int minIndex = j;	// 第j次循环假设下标为j的数为最小值
			for (int i = 1 + j; i < numbers.length; i++) {
				if(numbers[minIndex] > numbers[i]) {
					minIndex = i;
				}
			}
			if(minIndex != j) {
				numbers[minIndex] = numbers[j] ^ numbers[minIndex];
				numbers[j] = numbers[j] ^ numbers[minIndex];
				numbers[minIndex] = numbers[j] ^ numbers[minIndex];
			}
		}
		System.out.println(Arrays.toString(numbers));

图示:
在这里插入图片描述

3.快速排序(递归)

快速排序:每次都设第一个数为中间数,然后把小于这个值的移到左边(左边的为乱序),大于这个值的移到右边(右边的也为乱序)

	public static void main(String[] args) {
		int[] arrays = new int[7];
		for (int i = 0; i < arrays.length; i++) {
			arrays2[i] = (int) (Math.random() * 10);
		}
		
		System.out.println(Arrays.toString(arrays));
		methodOverloading(arrays);
		System.out.println(Arrays.toString(arrays));
	}
	
	// 方法重载
	public static void methodOverloading(int[] arrays) {
		quicksort(arrays, 0, arrays.length);
	}

	public static void quicksort(int[] arrays, int start, int end) {
		int i = start;
		int j = end;
        
        // 中间数
		// 每次将第一个数设为中间数
		// 把小的放到这个数的左边,把大的放到这个数的右边
		while (i < j) {
			while (i < j) {
				j--;
				if (arrays[j] < arrays[i]) {
					int temp = arrays[i];
					arrays[i] = arrays[j];
					arrays[j] = temp;
					break;
				}
			}

			while (i < j) {
				i++;
				if (arrays[i] > arrays[j]) {
					int temp = arrays[i];
					arrays[i] = arrays[j];
					arrays[j] = temp;
					break;
				}
			}
		}
		
        // 下面的star会随着i+1变化,下面的end会随着j变化
        // 新的start和end是会变化的,每次改变其中1个
        
		// 解决中间数左边的排序
		// 当中间数的左边为 0或者1 的时候,不进入
		if (i - start > 1) {
			// 新的i=start,新的j=j
			quicksort(arrays, start, j);
		}
		
		// 解决中间数右边的排序
		// 当中间数的左边为 0或者1 的时候,不进入
		if (end - (i + 1) > 1) {
			// 新的i=i+1, 新的j=end
			quicksort(arrays, i + 1, end);
		}

图示:
在这里插入图片描述

快速排序的详细分析:

快速排序_lanzous

int[] a = {3, 6, 9, 7, 2, 1, 5}7个数,对数组进行升序排序
快速排序:每次都设第一个数为中间数,然后把小于这个值的移到左边(左边的为乱序),大于这个值的移到右边(右边的也为乱序)
解:
// 第一步
S1:标记第一个数3为中间数(亦即,交换值后,要保证左边的数比标记的这个值3小,右边的数比3大,3左右两边均为乱序的)
S2:定义两个标记,最开始的数的下标为i;结束的数的下标为 j
   i = 0	j = a.length – 1 = 71 = 6
-------------------------------------------------------------------------------
S3:先从j开始,把小于标记值3的数,与a[i](和标记值相等)交换,如果 a[j] < a[i],则交换,因为 a[j]=5不小于a[i]=3,则 j--,再判断 a[j] < a[i],即现在的a[j]=1,而
1 < 3成立,故交换a[j]和a[i],{3, 6, 9, 7, 2, 1, 5}--> {1, 6, 9, 7, 2, 3, 5}
此时标记的数为a[j]
S4:j找到小于标记的数之后,就到了i的回合,如果a[i]>a[j],就交换,否则i++
因为a[i] =1不大于a[j] =3,故i++ ,此时a[i]=6,显然此时的a[i]大于标记值a[j],他们值交换,即{1, 6, 9, 7, 2, 3, 5}--> {1, 3, 9, 7, 2, 6, 5}
-------------------------------------------------------------------------------
S5:重复S3,此时的a[i]=3,a[j]=6, 此时标记的数为a[i],又找a[j]是否小于标记值,如果小于则交换,显然 6不小于标记值3的,故j--,此时a[j]变成了2,而2小于3,故交换a[j]与a[i],即{1, 3, 9, 7, 2, 6, 5}-->{1, 2, 9, 7, 3, 6, 5}
S6:重复S4,此时a[i]=2,a[j]=3。如果a[i]>a[j],则交换,显然不满足要求,则i++,此时a[i]=9,9>3,故交换,即{1, 2, 9, 7, 3, 6, 5}-->{1, 2, 3, 7, 9, 6, 5}
S7: 重复S,此时的a[i]=3,a[j]=9 ,显然3不大于9,故i++;此时的a[i]=7,显然7也不大于9,故i++,达到i=j,此时可以看出:标记值3的左边的数,都小于3,右边的数都大于3,但左右是乱序的(左边数据特殊),此时i=j=2// 第二步
思路:重复上一步。
1.取右边:{1, 2, 3, 7, 9, 6, 5}
S1:标记第一个数7为中间数(亦即,交换值后,要保证左边的数比标记的这个值7小,右边的数比7大,7左右两边均为乱序的)
S2:定义两个标记,最开始的数的下标为i;结束的数的下标为 j
   新的i = i+1	 新的j = a.length – 1 = 71 = 6
-------------------------------------------------------------------------------
S3:先从j开始,把小于标记值7的数,与a[i](和标记值相等)交换,如果 a[j] < a[i],则交换;因为 a[j]=5小于a[i]=7,故交换a[j]和a[i],{1, 2, 3, 7, 9, 6, 5}--> {1, 2, 3, 5, 9, 6, 7},此时标记的数为a[j]
S4:j找到小于标记的数之后,就到了i的回合,如果a[i]>a[j],就交换,否则i++;
因为a[i] =5不大于a[j] =7,故i++ ,此时a[i]=9,显然此时的a[i]大于标记值a[j],他们值交换,即{1, 2, 3, 5, 9, 6, 7}--> {1, 2, 3, 5, 7, 6, 9}
-------------------------------------------------------------------------------
S5: 重复S3,此时的a[i]=7,a[j]=9, 此时标记的数为a[i],又找a[j]是否小于标记值,如果小于则交换;显然 9不小于标记值7的,故j--,显然 6是小于标记值7的,即{1, 2, 3, 5, 7, 6, 9}-->{1, 2, 3, 5, 6, 7, 9}
S6:此时到了i的回合,此时a[i]=6,a[j]=7,6不大于7,故i++,此时i=j。此时可以看到: {1, 2, 3, 5, 6,7, 9}
2.左边同理
  注:左右分别通过if判断,递归算法,如果中间值左边为0个或者1个数,则结束循环

注:本文是个人学习Java过程中的一些理解与心得,以理解为主,口头语言描述的可能不很恰当,但如有错误,请大家批评指正,互相学习。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值