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);
}
图示:
快速排序的详细分析:
int[] a = {3, 6, 9, 7, 2, 1, 5},7个数,对数组进行升序排序
快速排序:每次都设第一个数为中间数,然后把小于这个值的移到左边(左边的为乱序),大于这个值的移到右边(右边的也为乱序)
解:
// 第一步
S1:标记第一个数3为中间数(亦即,交换值后,要保证左边的数比标记的这个值3小,右边的数比3大,3左右两边均为乱序的)
S2:定义两个标记,最开始的数的下标为i;结束的数的下标为 j
i = 0 j = a.length – 1 = 7 – 1 = 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 = 7 – 1 = 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过程中的一些理解与心得,以理解为主,口头语言描述的可能不很恰当,但如有错误,请大家批评指正,互相学习。