JavaSE 进阶 - 第19章 数组(2)
1、数组的算法
1.1、常见的算法
-
排序算法:
冒泡排序算法
选择排序算法 -
查找算法:
二分法查找
以上算法在以后的java实际开发中我们不需要使用的。
因为java已经封装好了,直接调用就行。
只不过在面试的时候,可能会有机会碰上。
1.2、算法实际上在java中不需要精通,因为java中已经封装好了,要排序就调用方法就行。
例如:java中提供了一个数组工具类:java.util.Arrays
Arrays是一个工具类。
其中有一个sort()方法,可以排序。静态方法,直接使用类名调用就行。
import java.util.Arrays;
//使用以下SUN公司提供的数组工具类:java.util.Arrays;
public class ArraysTest01 {
public static void main(String[] args) {
int[] arr = {112,3,4,56,67,1};
// 工具类当中的方法大部分都是静态的,直接:类名.方法名
Arrays.sort(arr);
// 遍历输出
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
/*
1
3
4
56
67
112
*/
2、冒泡排序
- 冒泡排序算法
首先从数组的最左边开始,取出第 0 号位置(左边)的数据和第 1号位置(右边)的数据,
如果左边的数据大于右边的数据,则进行交换,否而不进行交换。
接下来右移一个位置,取出第 1 个位置的数据和第 2 个位置的数据,进行比较,
如果左边的数据大于右边的数据,则进行交换,否而不进行交换。
…
沿着这个算法一直排序下去,最大的数就会冒出水面,这就是冒泡排序。
(1)每一次循环结束之后,都要找出最大的数据,放到参与比较的这堆数据的最右边。(冒出最大的那个气泡。)
(2)核心:拿着左边的数字和右边的数字比对,当左边 > 右边的时候,交换位置。
例:
参与比较的数据:9 8 10 7 6 0 11 ---共7位数字
第1次循环:
8 9 10 7 6 0 11 (第1次比较:交换) ---第 1 位和第 2 位数字比较
8 9 10 7 6 0 11 (第2次比较:不交换) ---第 2 位和第 3 位数字比较
8 9 7 10 6 0 11 (第3次比较:交换) ---第 3 位和第 4 位数字比较
8 9 7 6 10 0 11 (第4次比较:交换) ---第 4 位和第 5 位数字比较
8 9 7 6 0 10 11 (第5次比较:交换) ---第 5 位和第 6 位数字比较
8 9 7 6 0 10 11 (第6次比较:不交换) ---第 6 位和第 7 位数字比较
-------------------------最终冒出的最大数据在右边:11
参与比较的数据:8 9 7 6 0 10
第2次循环:
8 9 7 6 0 10(第1次比较:不交换)
8 7 9 6 0 10(第2次比较:交换)
8 7 6 9 0 10(第3次比较:交换)
8 7 6 0 9 10(第4次比较:交换)
8 7 6 0 9 10(第5次比较:不交换)
-------------------------最终冒出的最大数据在右边:10
参与比较的数据:8 7 6 0 9
第3次循环:
7 8 6 0 9(第1次比较:交换)
7 6 8 0 9(第2次比较:交换)
7 6 0 8 9(第3次比较:交换)
7 6 0 8 9(第4次比较:不交换)
-------------------------最终冒出的最大数据在右边:9
参与比较的数据:7 6 0 8
第4次循环:
6 7 0 8(第1次比较:交换)
6 0 7 8(第2次比较:交换)
6 0 7 8(第3次比较:不交换)
-------------------------最终冒出的最大数据在右边:8
参与比较的数据:6 0 7
第5次循环:
0 6 7(第1次比较:交换)
0 6 7(第2次比较:不交换)
-------------------------最终冒出的最大数据在右边:7
参与比较的数据:0 6
第6次循环:
0 6 (第1次比较:不交换)
-------------------------最终冒出的最大数据在右边:6
-------------------------最终冒出的最大数据在右边:0
________________________________________________________
for(int i = 6; i > 0; i--){ // 6次
//7条数据比6次
//6条数据比5次
//5条数据比4次
//4条数据比3次
//3条数据比2次
//2条数据比1次
for(int j = 0; j < i; j++){
// 交换位置。
// arr[j] 和 arr[j+1] 交换
int temp;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
public class BubbleSort {
public static void main(String[] args) {
// 这是int类型的数组对象
int[] arr = {9, 8, 10, 7, 6, 0, 11};
// 7条数据,循环6次。以下的代码可以循环6次。(冒泡排序的外层循环采用这种方式)
int count = 0;
for(int i = arr.length-1; i > 0; i--){
for(int j = 0; j < i; j++){
// 不管是否需要交换位置,总之是要比较一次的。
if(arr[j] > arr[j+1]){
// 交换位置。
// arr[j] 和 arr[j+1] 交换
int temp;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
count++;
}
}
}
System.out.println("交换位置的次数:" + count); //13
// 输出结果
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
/*
交换位置的次数:13
0
6
7
8
9
10
11
*/
3、选择排序
-
选择排序比冒泡排序的效率高。
高在交换位置的次数上。选择排序的交换位置是有意义的。 -
循环一次,然后找出参加比较的这堆数据中最小的,拿着这个最小的值和最前面的数据“交换位置”。
例:
参与比较的数据:3 1 6 2 5 (这一堆参加比较的数据中最左边的元素下标是0)
第1次循环之后的结果是:
1 3 6 2 5
参与比较的数据:3 6 2 5 (这一堆参加比较的数据中最左边的元素下标是1)
第2次循环之后的结果是:
2 6 3 5
参与比较的数据:6 3 5 (这一堆参加比较的数据中最左边的元素下标是2)
第3次循环之后的结果是:
3 6 5
参与比较的数据:6 5 (这一堆参加比较的数据中最左边的元素下标是3)
第4次循环之后的结果是:
5 6
最终:1 2 3 5 6
注意:5条数据,循环4次。
public class SelectSort {
public static void main(String[] args) {
int[] arr = {3, 1, 6, 2, 5};
int count = 0;
int count2 = 0;
// 选择排序
// 5条数据循环4次。(外层循环4次。)
for(int i = 0; i < arr.length - 1; i++){
// i的值是0 1 2 3
// i正好是“参加比较的这堆数据中”最左边那个元素的下标。
//System.out.println(i);
// i是一个参与比较的这堆数据中的起点下标。
// 假设起点i下标位置上的元素是最小的。
int min = i;
for(int j = i+1; j < arr.length; j++){
count++;
if(arr[j] < arr[min]){
min = j; //最小值的元素下标是j
}
}
// 当i和min相等时,表示最初猜测是对的。
// 当i和min不相等时,表示最初猜测是错的,有比这个元素更小的元素,
// 需要拿着这个更小的元素和最左边的元素交换位置。
if(min != i){
// 表示存在更小的数据
// arr[min] 最小的数据
// arr[i] 最前面的数据
int temp;
temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
count2++;
}
}
// 冒泡排序和选择排序实际上比较的次数没变。
// 交换位置的次数减少了。
System.out.println("比较次数" + count); // 21
System.out.println("交换次数:" + count2); // 5
// 排序之后遍历
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
/*
比较次数10
交换次数:4
1
2
3
5
6
*/
4、二分法查找(折半查找)
-
第一:二分法查找建立在排序的基础之上。
-
第二:二分法查找效率要高于“一个挨着一个”的这种查找方式。
-
第三:二分法查找原理?
10 23 56 89 100 111 222 235 500 600 arr数组 下标:0 1 2 3 4 5 6 7 8 9 目标:找出600的下标 (0 + 9) / 2 --> 4(中间元素的下标) arr[4]这个元素就是中间元素:arr[4]是 100 100 < 600 说明被查找的元素在100的右边。 那么此时开始下标变成:4 + 1 (5 + 9) / 2 --> 7(中间元素的下标) arr[7] 对应的是:235 235 < 600 说明被查找的元素在235的右边。 开始下标又进行了转变:7 + 1 (8 + 9) / 2 --> 8 arr[8] --> 500 500 < 600 开始元素的下标又发生了变化:8 + 1 (9 + 9) / 2 --> 9 arr[9]是600,正好和600相等,此时找到了。
public class ArrayUtil {
public static void main(String[] args) {
int[] arr = {100,200,230,235,600,1000,2000,9999};
// 找出arr这个数组中230所在的下标。
// 调用方法
int index = binarySearch(arr, 230);
System.out.println(index == -1 ? "该元素不存在!" : "该元素下标" + index);
}
//封装一个方法
public static int binarySearch(int[] arr, int dest) {
// 开始下标
int begin = 0;
// 结束下标
int end = arr.length - 1;
// 开始元素的下标只要在结束元素下标的左边,就有机会继续循环。
while(begin <= end) {
// 中间元素下标
int mid = (begin + end) / 2;
if (arr[mid] == dest) {
return mid;
} else if (arr[mid] < dest) {
// 目标在“中间”的右边
// 开始元素下标需要发生变化(开始元素的下标需要重新赋值)
begin = mid + 1; // 一直增
} else {
// arr[mid] > dest
// 目标在“中间”的左边
// 修改结束元素的下标
end = mid - 1; // 一直减
}
}
return -1;
}
}
/*
该元素下标2
*/
5、java.util.Arrays工具类
所有方法都是静态的,直接用类名调用
主要使用的是两个方法:
二分法查找,排序
以后要看帮助文档,不要死记硬背。
例:
import java.util.Arrays;
/**
* 好消息:
* SUN公司已经为我们程序员写好了一个数组工具类。
* java.util.Arrays;
*/
public class ArraysTest02 {
public static void main(String[] args) {
// java.util.Arrays; 工具类中有哪些方法,我们开发的时候要参考API帮助文档
// 不要死记硬背。
int[] arr = {3,6,4,5,12,1,2,32,5,5};
// 排序
Arrays.sort(arr);
// 输出
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 二分法查找(建立在排序基础之上。)
int index = Arrays.binarySearch(arr, 5);
System.out.println(index == -1 ? "该元素不存在" : "该元素下标是:" + index);
}
}
/*
1
2
3
4
5
5
5
6
12
32
该元素下标是:4
*/