在对数组进行排序的过程中,我们需要用到数值的传递才能保证数组中的序数--数值对应着改变,而数值的传递有两种方式
-
值传递
•值传递(pass by value)是指在调用函数时将实际参数复制 一份传递到函数中,这样在函数中如果对 参数 进行修改,将不会影响到实际参数。
public class Test {
public static void main(String[] args) {
int x=10;
test(x);
System.out.println(x);//输出10
}
public static void test(int y) {
y=0;
}
}
在这段代码中,10作为一个参数被传给了x,但是10这个参数之后的改变不会影响x
-
引用传递
•引用传递(pass by reference)是指在调用函数时将实际参数的地址 直接 传递到函数中,那么在函数中对 参数 所进行的修改,将影响到实际参数。
public class Test {
public static void main(String[] args) {
int [] x= {10};
test(x);
System.out.println(x[0]);//输出0
}
public static void test(int [] y) {
y[0]=0;
}
}
在这段代码中,{10}是以将其地址传给了x,使得x的值与{10}一样,由于x与{10}指向同一个地址,之后{10}发生改变,x也会随之改变。
-
冒泡排序
- •冒泡排序法是最基本的排序法之一,冒泡排序法的运行机制是通过循环遍历元素并调整相邻元素顺序来实现的一种简单排序方法。
- 冒泡排序的原理其实就是通过对比相邻两个数的大小,交换位置,循环使得最终最大的数一直被交换到首或尾部。
- 通过数组{21, 99, 3, 1024, 16}示范
public class ArraySort{
public static void main(String [] args){
int [] array={21, 99, 3, 1024, 16};//升序排列
for(int i=0;i<array.length-1;i++){//该for循环每循环一次就会将较大的数据放在适当的位置,比如loopTime=1;则将最大数据放在最后;loopTime=2;则将第二大数据放在倒数第二个元素位置;
int currentData = array[i];//当前遍历出来的数据
int nextData = array[i+1];//当前数据下标对应的下一个元素的数据
if(currentData>nextData){//如果当前元素大于其后面的元素,则意味着需要调换两个元素之间的位置
array[i] = nextData;
array[i+1]=currentData;
}
}
for(int data:array){
System.out.print(data+" ");
}
}
}
通过这个循环,可以使得当前次序时的相邻两数按大小进行交换,但是要往头部移动的数据进行一次这个循环无论如何只能移动一位(因为其在最后才交换),因此为了做到确保最小或者最大的数据在尾部,能够移动到头部时,我们需要在外面再嵌套循环,而循环的次数就是它最多需要移动的次数——即数组的长度-1
public class ArraySort{
public static void main(String [] args){
int [] array={21, 99, 3, 1024, 16};//升序排列
for(int loopTime=1;loopTime<array.length;loopTime++){//只是控制内部for循环的次数
for(int i=0;i<array.length-1;i++){//该for循环每循环一次就会将较大的数据放在适当的位置,比如loopTime=1;则将最大数据放在最后;loopTime=2;则将第二大数据放在倒数第二个元素位置;array.length-loopTime:从提高代码的性能角度出发,减少该循环“多余”的循环次数
int currentData = array[i];//当前遍历出来的数据
int nextData = array[i+1];//当前数据下标对应的下一个元素的数据
if(currentData>nextData){//如果当前元素大于其后面的元素,则意味着需要调换两个元素之间的位置
array[i] = nextData;
array[i+1]=currentData;
}
}
}
for(int data:array){
System.out.print(data+" ");
}
}
}
现在这样就能做到确保完成排序了,但是我们内部循环一定会使得靠近头部的数据移动到其无法再交换的位置为止,所以外部循环的次数需要减少,因此代码还可以改进
public class ArraySort{
public static void main(String [] args){
int [] array={21, 99, 3, 1024, 16};//升序排列
for(int loopTime=1;loopTime<array.length;loopTime++){//只是控制内部for循环的次数
for(int i=0;i<array.length-loopTime;i++){//该for循环每循环一次就会将较大的数据放在适当的位置,比如loopTime=1;则将最大数据放在最后;loopTime=2;则将第二大数据放在倒数第二个元素位置;array.length-loopTime:从提高代码的性能角度出发,减少该循环“多余”的循环次数
int currentData = array[i];//当前遍历出来的数据
int nextData = array[i+1];//当前数据下标对应的下一个元素的数据
if(currentData>nextData){//如果当前元素大于其后面的元素,则意味着需要调换两个元素之间的位置
array[i] = nextData;
array[i+1]=currentData;
}
}
}
for(int data:array){
System.out.print(data+" ");
}
}
}
-
插入排序
-
•每循环一次都将一个待排序的元素所对应的数据按其顺序大小插入到前面已经排序的序列的合适位置,直到全部插入排序完为止,其难点在于如何在前面已经排好序的序列中找到合适的插入位置。该排序方法有很多,比如直接插入排序、二分插入排序、希尔排序等等。
•先看如何解决这个问题:已知数组{1, 2, 4, 5, 3},将3插入到适当位置,使之成为一个升序排列的数组,即{1, 2, 3, 4, 5}。
-
其实原理就是通过依次比照大小,将待插入元素放在它应该在的位置,再使得后面的元素位置后移。而有的时候因为顺序更乱,需要多次插入排序,这时我们可以外套循环public class SortArray { /** * 已知数组{1, 2, 4, 5, 3},将3插入到适当位置,使之成为一个升序排列的数组,即{1, 2, 3, 4, 5} */ public static void main(String[] args) { int[] array = new int[]{1, 2, 4, 5, 3}; int i=4;//待插入元素数据3所在位置 int willSortData = array[i];//将待插入元素数据3保存在临时变量willSortData中 int j = 0; for (; j < i; j++) { if(willSortData<=array[j]){//找到应该插入3的索引位置 break;//找到插入位置后结束该循环 } } //System.out.println(j);//输出2,即数据3应该插入到数据4的位置 int k=i;//待插入元素数据所在位置 for (; k >j; k--) {//从待插入元素数据所在位置(即第5个元素)将数组元素后移一个元素位,直到待插入数据该插入位置(不包含)结束 array[k]=array[k-1]; } array[j]=willSortData;//将待插入数据插入到该插入的位置,即在排序位置插入数据待排序数据 for (int data : array) { System.out.print(data+" "); } } }
public class ArraySort{
public static void main(String [] args){
int [] array={1,2,6,7,2,9,12,2};//升序排列
for(int i=1;i<array.length;i++){//i为待排序数据的下标,由于将第一个元素是有序的,所以i从1开始;i<array:这样才能遍历完后续数组,进而实现全部排序;
int willSortData=array[i];//将待排序数据保存到变量willSortData中
int j=0;
/*
*查找待插入数据“应该”插入的下标位置
*/
for(;j<i;j++){//j<i:和待排序数据前面(i)的所有元素进行比较,以找到“应该”插入的下标位置。说明:不能这样写j<=i,因为无需自己和自己比对
if(willSortData<array[j]){//如果条件成立意味着待插入数据小于其前面的某个元素值
break;//当if条件成立时就找到了该待插入数据“应该”插入的下标位置,所以这时必须终止循环
}
}//for循环执行结束意味着找到了待插入数据“应该”插入的下标位置
/*
*下面循环用于元素后置
*/
for(int k=i;k>j;k--){//int k=i:待插入数据所在位置就是元素后移开始的下标位置;k>j:待插入数据“应该”插入位置(j)就是元素后移结束位置
array[k]=array[k-1];//元素后置
}
/*
*下面代码用于将待插入数据插入到“应该”插入的下标位置
*/
array[j]=willSortData;
}//该循环体每循环完一次就代表着本次待插入数据已经和前面元素是有序的了
for(int data:array){
System.out.print(data+" ");
}
}
}
其实可以理解为将数组分成了有序区和无序区,有序区由于已经排列好,可以直接比照过去,如果大小符合要求便插入,不符合便放在两个区域中间,这时候无序区的下一个元素又拿出来再做插入,随着循环进行,无序区的数就会越来越少,直到全部有序。