JavaSE——数组中常见的算法

First Post:

Last Update:

Word Count:
2.1k

Read Time:
8 min

数组中常见的算法

例如:java中提供了一个数组工具类:java.util.Arrays
Arrays是一个工具类。
其中有一个sort()方法,可以排序。静态方法,直接使用类名调用就行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
冒泡排序算法
1、每一次循环结束之后,都要找出最大的数据,放到参与比较的这堆数据的最右边。(冒出最大的那个气泡。)
2、核心:
拿着左边的数字和右边的数字比对,当左边 > 右边的时候,交换位置。

原始数据:
3, 2, 7, 6, 8
第1次循环:(最大的跑到最右边。)
2, 3, 7, 6, 8 (3和2比较,2 < 3,所以2和3交换位置)
2, 3, 7, 6, 8 (虽然不需要交换位置:但是3和7还是需要比较一次。)
2, 3, 6, 7, 8 (7和6交换位置)
2, 3, 6, 7, 8 (虽然不需要交换位置:但是3和7还是需要比较一次。)

经过第1次循环,此时剩下参与比较的数据:2, 3, 6, 7
第2次循环:
2, 3, 6, 7 (2和3比较,不需要交换位置)
2, 3, 6, 7 (3和6比较,不需要交换位置)
2, 3, 6, 7 (6和7比较,不需要交换位置)

经过第2次循环,此时剩下参与比较的数据:2, 3, 6
第3次循环:
2, 3, 6 (2和3比较,不需要交换位置)
2, 3, 6 (3和6比较,不需要交换位置)

经过第3次循环,此时剩下参与比较的数据:2, 3
第4次循环:
2, 3 (2和3比较,不需要交换位置)

*/
public class BubbleSort {
public static void main(String[] args) {

// 这是int类型的数组对象
//int[] arr = {3, 2, 7, 6, 8};
int[] arr = {9, 8, 10, 7, 6, 0, 11};

// 经过冒泡排序算法对以上数组中元素进行排序
// 冒泡排序算法的核心是什么?

// 7条数据,循环6次。以下的代码可以循环6次。
/*
for(int i = 0; i < arr.length-1; i++){
System.out.println(i);
}
*/

// 7条数据,循环6次。以下的代码可以循环6次。(冒泡排序的外层循环采用这种方式)
//int count = 0;
int count2 = 0;
for(int i = arr.length-1; i > 0; i--){
for(int j = 0; j < i; j++){
// 不管是否需要交换位置,总之是要比较一次的。
//count++;
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;
count2++;
}
}
}

//System.out.println("比较次数:" + count);
System.out.println("交换位置的次数:" + count2); //13
// 输出结果
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}

选择排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/*
选择排序:
每一次从这堆“参与比较的数据当中”找出最小值,
拿着这个最小值和“参与比较的这堆最前面的元素”交换位置。

选择排序比冒泡排序好在:每一次的交换位置都是有意义的。

关键点:选择排序中的关键在于,你怎么找出一堆数据中最小的。
3 2 6 1 5
假设:
第一个3是最小的。
3和2比较,发现2更小,所以此时最小的是2.

继续拿着2往下比对,2和6比较,2仍然是最小的。
继续拿着2往下比对,2和1比对,发现1更小,所以此时最小的是1.
继续拿着1往下比对,1和5比对,发现1还是小的,所以1就是最小的。

拿着1和最左边的3交换位置。
2 6 3 5
假设:
第一个2是最小的。
...

6 3 5
假设6是最小的:
6和3比对,发现3更小,所以此时最小的是3.
...
*/
public class SelectSort {
public static void main(String[] args) {

//int[] arr = {3, 1, 6, 2, 5};
int[] arr = {9, 8, 10, 7, 6, 0, 11};

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++;
//System.out.println("===>" + j);
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]);
}
}
}

//1 2 3 4 5
//假设1是最小的,结果1确实是最小的,就不需要交换位置。

查找——二分查找(binarySearch)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.bjpowernode.javase.array;

/*
1、数组工具类:自己写的。不是SUN的。

2、关于查找算法中的:二分法查找。
10(下标0) 11 12 13 14 15 16 17 18 19 20(下标10) arr数组。

通过二分法查找,找出18这个元素的下标:
(0 + 10) / 2 --> 中间元素的下标: 5

拿着中间这个元素和目标要查找的元素进行对比:
中间元素是:arr[5] --> 15
15 < 18(被查找的元素)
被查找的元素18在目前中间元素15的右边。
所以开始元素的下标从0变成 5 + 1.

再重新计算一个中间元素的下标:
开始下标是:5 + 1
结束下标是:10
(6 + 10) / 2 --> 8

8下标对应的元素arr[8]是18
找到的中间元素正好和被找的的元素18相等,表示找到了:下标为8

二分法查找的终止条件:一直折半,直到中间的那个元素恰好是被查找的元素。

3、二分法查找算法是基于排序的基础之上。(没有排序的数据是无法查找的。)

*/
public class ArrayUtil {
public static void main(String[] args) {

int[] arr = {100,200,230,235,600,1000,2000,9999};

// 找出arr这个数组中200所在的下标。
// 调用方法
int index = binarySearch(arr, 230);
System.out.println(index == -1 ? "该元素不存在!" : "该元素下标" + index);
}

/**
* 从数组中查找目标元素的下标。
* @param arr 被查找的数组(这个必须是已经排序的。)
* @param dest 目标元素
* @return -1表示该元素不存在,其它表示返回该元素的下标。
*/
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;
}
}