Java中常见的算法和Arrays工具类
一、常见的算法
1.1 冒泡排序
概念:冒泡排序是一种排序算法,(以升序排序为例)原理是每次通过相邻的两个元素比较,找出较大的那个元素,放到两元素之中较后的元素位置上,即如果两个元素前面的元素大于后面的那个元素,就交换两个元素的位置。每次遍历到未实现排序的元素,每次获得一个较大值放到数组的后面,以此反复,在实现n-1(假设有n个元素)次迭代后,找出了n-1个较大值完成升序排序,因为每一次找出一个较大值放在数组的最后,类似水中的冒泡,故称为冒泡排序。
public class Test {
public static void main(String[] args) {
int arr[] = {12, 23, 9, 34, 22, 45};
int[] newArr = getArr(arr);
System.out.println(Arrays.toString(newArr));
}
public static int[] getArr(int arr[]){
if(arr == null || arr.length ==0){
return null;
}
// 冒泡排序确定要实现n-1次的迭代,即要找出n-1个较大值
for (int i = 0; i < arr.length - 1; i++) {
// 每一次找出未排序元素中的最大值,放到未排序元素序列中的最后
for (int j = 0; j < arr.length - 1 - i; j++) {
if(arr[j]>arr[j+1]){
// 符合条件就交换位置
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
}
1.2 选择排序
选择排序是一种排序算法,(以升序排序为例)假设数组中有n个元素,要进行n-1次迭代,每一次迭代找出一个最小值放在未排序元素的最前面,每一次迭代遍历未排序元素,固定未排序元素的第一个元素,让第一个元素依次跟后面的元素比较,如果后面有元素比第一个的值小(符合排序规则)就交换两个元素的位置,下一次继续用第一个元素跟后面未遍历的元素比较,以此每一次迭代就能保证找出未排序元素中的最小值。
public class Test {
public static void main(String[] args) {
int arr[] = {44, 33, 22, 11};
int newArr[] = getArr(arr);
System.out.println(Arrays.toString(newArr));
}
public static int[] getArr(int arr[]) {
if (arr == null || arr.length == 0) {
return null;
}
for (int i = 0; i < arr.length; i++) {
// 每一次迭代找出最小的值放在未排序元素的最前面
for (int j = i + 1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
}
1.3二分查找
二分查找是确定一个数据结构中是否有某个数据的算法,它默认的条件是升序或降序,每次查找的值只能是一个。它的原理是每次确定可查找序列的头尾值的位置,并通过头尾的位置计算出序列的中间位置,每一次迭代比较目标值和中间值,根据不同情况舍弃另一半序列或者直接找到目标值对应的数据。因为每一次迭代很大概率都要舍弃一半的序列进行查找,所以次算法本称为二分查找。
public class Test {
public static void main(String[] args) {
int arr[] = {22, 11, 55, 44, 33};
int index = getIndex(arr, 22);
System.out.println("目标数字的下标为:" + index);
}
public static int getIndex(int arr[], int target) {
// 查找前先进行数组的判断
if(arr == null || arr.length == 0){
return -1;
}
// 二分查找前先进行排序
Arrays.sort(arr);
// 进行迭代
int left = 0; // 头位置下标
int right = arr.length - 1; // 尾位置下标
while (left <= right) {
// 每一次迭代要重新定义中间位置的值
int middle = (left + right) / 2;
if (arr[middle] > target) {
// 说明目标值在序列的左边,舍弃右边的序列,重新定义尾位置的下标
right = middle - 1; // 因为arr[middle] > target,说明中间位置的值也不是目标值,所以要往左移动一位
} else if (arr[middle] < target) {
// 说明目标值在序列的右边,舍弃左边的序列,重新定义头位置的下标
left = middle + 1; // 因为arr[middle] < target,说明中间位置的值也不是目标值,所以要往右移动一位
}else {
return middle; // 这种情况就是中间值等于目标值,所以直接返回中间值的索引
}
}
return -1; // 找不到目标值返回-1
}
}
-
在程序开始前,我们对首尾位置的值进行初始化
-
left = 0; right = arr.length-1;
-
middle = (left+right)/2;
-
第一轮迭代我们对比
arr[middle]
和target
的值,发现中间值大于目标值,这样我们就要舍弃右边的序列,重新定义尾位置right
的值为middle-1
- 第二轮迭代我们确定了首尾的值,并根据其计算出中间的值
middle = 0
- 开始比较
arr[middle]
和target
的值,发现两者相同 - 找到目标值,返回目标值的下标
middle
,并结束迭代,查询完毕
二、Arrays工具类
Arrays类其实就是一个工具类,是Java为操作数组提供的类,里面提供了很多API,如toString()、sort()、setAll()等这些常用API,下面我们就演示一下它们的作用
API | 作用 |
---|---|
toString() | 返回数组的特定形式字符串 |
copyOfRange(Object arr[], int start, int end) | 返回一个新数组,复制特定范围的数组内容,包前不包后 |
copyOf(Object arr[], int length) | 返回一个新数组,把数组复制进一个指定长度的新数组里面 |
sort() | 改变原数组,把基本数据类型和String类型的数组从到大排列 |
sort() | 改变原数组让数组按照指定的规则排序 |
setAll(Object arr[],匿名方法) | 把数组中的数据进行操作后返回 |
binarySearch(arr[],int number) | 前提是数组有序,底层通过二分查找找寻指定数据的索引,找不到就返回-1 |
public class Test {
public static void main(String[] args) {
int arr[] = {55,44,33,22,11};
// toString() 返回数组的特定形式字符串
String s = Arrays.toString(arr);
System.out.println(s);
System.out.println("--------------------");
// copyOfRange(Object arr[], int start, int end)
// 返回一个新数组,复制特定范围的数组内容,包前不包后
int[] newArr = Arrays.copyOfRange(arr, 2, 4);
System.out.println(Arrays.toString(newArr));
System.out.println("--------------------");
// copyOf(Object arr[], int length) 返回一个新数组,把数组复制进一个指定长度的新数组里面
int[] newArr2 = Arrays.copyOf(arr, 6);
System.out.println(Arrays.toString(newArr2));
System.out.println("--------------------");
// sort() 改变原数组,把基本数据类型和String类型的数组从到大排列
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
System.out.println("--------------------");
// sort(匿名内部类) 一般用于自定义类型的数组
Student s1 = new Student("乾巧", 19);
Student s2 = new Student("草加", 23);
Student s3 = new Student("小樱", 16);
Student s4 = new Student("五代", 21);
Student student[] = {s1,s2,s3,s4};
Arrays.sort(student, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 按照年龄的升序排列
return o1.getAge()-o2.getAge();
}
});
System.out.println(Arrays.toString(student));
System.out.println("--------------------");
// setAll(Object arr[],匿名方法) 把数组中的数据进行操作后返回
Arrays.setAll(arr, new IntUnaryOperator() {
@Override
public int applyAsInt(int operand) {
return arr[operand]+10;
}
});
System.out.println(Arrays.toString(arr));
System.out.println("--------------------");
// binarySearch(arr[],int number) 前提是数组有序,底层通过二分查找找寻指定数据的索引,找不到就返回-1
int index = Arrays.binarySearch(arr, 43);
System.out.println("索引为:"+index);
}
}
补充:
sort()
方法对于自定义类型的数据进行排序有两种,第一种是让类实现Comparable<?>接口,并重写compareTo(? obj)方法,里面指定比较规则;第二种是传入Comparator接口的实现类对象,里面也是重写compare(? o1,? o2)并指定比较规则
比较规则:总体来说两种重写的方法都会传入两个参数,这两个参数分别是数组里面的相邻的两个元素,方法规定,如果返回的是整数,就交换两个元素的位置
总结:升序–>参数1-参数2-----降序–>参数2-参数1
下面是sort()对于自定义类型数据排序的第二种方法