目录
六、数组的排序
七、数组元素查找
(1)冒泡排序
•冒泡排序法是最基本的排序法之一,冒泡排序法的运行机制是通过循环遍历元素并调整相邻元素顺序来实现的一种简单排序方法。
•以数组 {21, 99, 3, 1024, 16}升序排列为例演示冒泡排序的原理:
1、
冒泡排序法每一次排序目的是将数值较大(针对于升序排序)或较小(针对于降序排序)的元素移动到数组的尾部。
以升序为例:
第一次循环:将元素21与元素99进行比较,由于21 < 99,所以不用交换元素;
第二次循环:将元素99与元素3进行比较,由于99 > 3,所以需要交换元素(即99和3的位置互换,数组的序列被调整为 {21, 3, 99, 1024, 16});
第三次循环:将元素99与元素1024进行比较,由于99 < 1024,所以也不用交换元素;
第四次循环:将元素1024与元素16进行比较,由于1024 < 16,所以需要交换元素(即1024与16的位置互换)。
经过第一次遍历将最大的元素1024调整到了数组的尾部,数组序列变为 {21, 3, 99, 16, 1024}。
2、
冒泡排序法的第二次排序与第一次原理一致,只不过第二次排序不再关系数组尾部元素,因为经过前一次排序后,数组尾部元素已经存储了数组中数值最大的元素,所以第二次排序的目的是将数组中数值第二大的元素存储到数组的倒数第二个位置(即此时只关心数组前四个元素 {21, 3, 99, 16}的顺序)。
第一次循环:将元素21与元素3进行比较,由于21 > 3,所以需要交换元素(即21和3位置互换,数组的前四位序列被调整为 {3, 21, 99, 16});
第二次循环:将元素21与元素99进行比较,由于21 < 99,所以不用交换元素;
第三次循环:将元素99与元素16进行比较,由于99 > 16,所以需要交换元素(即99和16的位置互换);
第四次循环:将元素99与元素1024进行比较,由于99< 1024,所以不用交换元素。
经过第二次排序数组序列变为 {3, 21, 16, 99, 1024}。
3、
冒泡排序法的第三次排序与第一次原理一致,只不过第三次次排序不再关系数组倒数第二个位置元素,因为经过前一次排序后,数组倒数第二个位置元素已经存储了数组中数值第二大的元素,所以第三次排序的目的是将数组中数值第三大的元素存储到数组的倒数第三个位置(即此时只关心数组前四个元素 {3, 21, 16}的顺序)。
第一次循环:将元素3与元素21进行比较,由于3 < 21,所以不用交换元素;
第二次循环:将元素21与元素16进行比较,由于21 > 16,所以需要交换元素(即21和16位置互换,数组的前三位序列被调整为 {3, 16, 21});
第三次循环:将元素21与元素99进行比较,由于12 < 99,所以不需要交换元素;
第四次循环:将元素99与元素1024进行比较,由于99< 1024,所以不用交换元素。
经过第三次排序数组序列变为 {3,16, 21, 99, 1024}。
4、
冒泡排序法的第四次排序与第一次原理一致,只不过第四次次排序不再关系数组倒数第三个位置元素,因为经过前一次排序后,数组倒数第三个位置元素已经存储了数组中数值第三大的元素,所以第四次排序的目的是将数组中数值第四大的元素存储到数组的倒数第四个位置(即此时只关心数组前四个元素 {3, 16}的顺序)。
第一次循环:将元素3与元素16进行比较,由于3 < 16,所以不用交换元素;
第二次循环:将元素16与元素21进行比较,由于16 < 21,所以不用交换元素;
第三次循环:将元素21与元素99进行比较,由于12 < 99,所以不需要交换元素;
第四次循环:将元素99与元素1024进行比较,由于99< 1024,所以不用交换元素。
经过第四次排序数组序列变为 {3,16, 21, 99, 1024}。由于数组一共包含五个元素,则排序完成。
public class ArraySort{
public static void main(String [] args){
int [] array={21, 99, 3, 1024, 16};//升序排列
for(int loopTime=1;loopTimenextData){//如果当前元素大于其后面的元素,则意味着需要调换两个元素之间的位置
array[i] = nextData;
array[i+1]=currentData;
}
}
}
for(int data:array){
System.out.print(data+" ");
}
}
}
以下代码和上一个代码不同的地方:array.length-loopTime:从提高代码的性能角度出发,减少该循环“多余”的循环次数;
public class ArraySort{
public static void main(String [] args){
int [] array={21, 99, 3, 1024, 16};//升序排列
for(int loopTime=1;loopTimenextData){//如果当前元素大于其后面的元素,则意味着需要调换两个元素之间的位置
array[i] = nextData;
array[i+1]=currentData;
}
}
}
for(int data:array){
System.out.print(data+" ");
}
}
}
•冒泡排序的实质是相邻两个元素比较,然后按照升序或降序调换位置。
(2)插入排序
•每循环一次都将一个待排序的元素所对应的数据按其顺序大小插入到前面已经排序的序列的合适位置,直到全部插入排序完为止,其难点在于如何在前面已经排好序的序列中找到合适的插入位置。该排序方法有很多,比如直接插入排序、二分插入排序、希尔排序等等。
•先看如何解决这个问题:已知数组{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;ij;k--){//int k=i:待插入数据所在位置就是元素后移开始的下标位置;k>j:待插入数据“应该”插入位置(j)就是元素后移结束位置
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;ij;k--){//int k=i:待插入数据所在位置就是元素后移开始的下标位置;k>j:待插入数据“应该”插入位置(j)就是元素后移结束位置
array[k]=array[k-1];//元素后置
}
/*
*下面代码用于将待插入数据插入到“应该”插入的下标位置
*/
array[j]=willSortData;
}//该循环体每循环完一次就代表着本次待插入数据已经和前面元素是有序的了
for(int data:array){
System.out.print(data+" ");
}
}
}
•插入排序的实质:将数组分为有序区和无序区,定义一个标记无序区第一个元素的定位变量,将该元素与前面的有序区内元素遍历比较,找到该元素应该插入位置,然后将应插入位置到待插入元素所在位置之间的元素后移一位,最后再将待插入元素插入到应插入的位置,有序区扩增一位,无序区减少一位,定位变量再次后移,锁定后面无序区第一位元素位置。
当然,只看代码也许没办法看懂,需要多多练习。
•二分法查找:搜索数据与有序数组(比如升序)中间元素比较以确定在中间元素左边还是右边,如果在右边,则调整最小搜索索引值,然后进入下次循环;如果在左边,则调整最大搜索索引值,然后进入下次循环;如果相等则当前位置就是查找数据所在位置,停止循环;
import java.util.Arrays;
public class Test {
public static int search(int[] array, int data) {
Arrays.sort(array);// 将数组升序排列
int low = 0;
int high = array.length - 1;
while (low <= high) {
int middle = (low + high) / 2;
// 搜索数据与中间元素比较确定在中间元素左边还是右边,进而不断缩小查找范围
if (data > array[middle]) {//右边
low = middle + 1;
} else if (data < array[middle]) {//左边
high = middle - 1;
} else {
return middle;
}
}
return -1;
}
public static void main(String[] args) {
int[] numbers = {5, 1, 7, 3, 2};
int index = search(numbers, 5);
if (index != -1) {
System.out.println("数组中包含该数据");
} else {
System.out.println("数组中不包含该数据");
}
}
}