java数组学习
一.声明数组
//首选java定义
dataType[] arr_1 ;
//不建议使用以下这种定义,该定义是为方便C程序员快速看懂Java程序
dataType arr_2[] ;
二.创建数组
Java语言使用new操作符来创建数组,语法如下:
array = new int[arraySize];
数组变量的声明,和创建数组可以用一条语句完成,如下所示:
dataType[] array = new dataType[arraySize];
还可以
dataType[] array = {value0,value1,value2.......value*};
dataType[] array = new dataType[]{value0,value1,value2.......value*};
//静态数组
int[] arr_1 = {1,2,3,4};
//还可以 int[] arr_1 =new int[]{1,2,3,4};
int[] arr_2 = new int[4];
arr_2[0] = 1;
arr_2[1] = 2;
arr_2[2] = 3;
arr_2[3] = 4;
//计算元素和
int sum = 0;
for (int i = 0; i < 4; i++) {
sum = sum + arr_2[i];
}
System.out.println("sum = " + sum);
//sum = 10
三.处理数组
处理数组元素时候,我们通常使用基本循环或者 For-Each 循环
double[] array = {1.9,2.9,3.4,3.5};
//打印所有元素
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
/**
*1.9
*2.9
*3.4
*3.5
*/
}
//计算所有元素的和
double sum = 0;
for (int j = 0; j < array.length; j++) {
sum += array[j];
}
System.out.println("sum = " + sum);//sum = 11.7
//查找最大元素
double max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
System.out.println("max = " + max);//max = 3.5
四.For-Each 循环
JDK 1.5 引进了一种新的循环类型,被称为 For-Each 循环或者加强型循环,它能在不使用下标的情况下遍历数组。
语法格式如下:
for(type element: array) { System.out.println(element); }
double[] array = {1.9,2.9,3.4,3.5};
//打印所有元素
// for (double element : array)
for(double element
: array){
System.out.println("element = " + element);
}
/**
* element = 1.9
* element = 2.9
* element = 3.4
* element = 3.5
*/
五.数组作为函数的参数
数组可以作为参数传递给方法。
public class Main {
public static void main(String[] args) {
printArray(new int[]{1,2,3,4});
}
public static void printArray(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
/**
* 1
* 2
* 3
* 4
*/
六.数组作为函数的返回值
public static int[] reverse(int[] list) {
int[] result = new int[list.length];
for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {
result[j] = list[i];
}
return result;
七.多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组,例如:
String[][] str = new String[3][4];
多维数组的动态初始化
(以二维数组为例)
1. 直接为每一维分配空间
格式如下:
type[][] typeName = new type[typeLength1][typeLength2];
type 可以为基本数据类型和复合数据类型,typeLength1 和 typeLength2 必须为正整数,typeLength1 为行数,typeLength2 为列数。
例如:
int[][] a = new int[2][3];
解析:
二维数组 a 可以看成一个两行三列的数组。
2. 从最高维开始,分别为每一维分配空间
例如:
String[][] s = new String[2][];
s[0] = new String[2];
s[1] = new String[3];
s[0][0] = new String("Good");
s[0][1] = new String("Luck");
s[1][0] = new String("to");
s[1][1] = new String("you");
s[1][2] = new String("!");
解析:
s[0]=new String[2] 和 s[1]=new String[3] (第一行只能有两列,第二行有三列)是为最高维分配引用空间,也就是为最高维限制其能保存数据的最长的长度,s[0],s[1]代表已经给定的2行
然后再为其每个数组元素单独分配空间 s0=new String("Good") 等操作。
package com.company;
import java.util.Scanner;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
//第一种方法
int[][] a= {{1,2,3},{4,5,6}};
System.out.println("a : " + Arrays.toString(a));
int[][] b = {{1,2,3},{4,5,6}};
System.out.println("b : " + Arrays.deepToString(b));
//第二种方法
int[][] c = new int[2][3];
c[0][0] = 1;
c[0][1] = 2;
c[0][2] = 3;
c[1][0] = 4;
c[1][1] = 5;
c[1][2] = 6;
System.out.println("c : " + Arrays.deepToString(c));
//第三种方法:数组第二维长度可以动态申请
int[][] d = new int[5][];//给定行的长度
//遍历第一维
for (int i = 0; i < d.length; i++) {
//列的长度每次都变化,所以每次都要重新申请空间(长度)
//为第i行创建了一个长度为i+1的整型数组
d[i] = new int[i + 1];
//嵌套循环遍历当前行的每个元素
for (int j = 0; j < d[i].length; j++) {
//嵌套循环遍历当前行的每个元素
d[i][j] = i + j;
//元素赋值为i+j
System.out.println("d[i][j] = " + d[i][j]);
}
System.out.println("d[i][j] : " + Arrays.toString(d[i]));
}
}
}
打印结果
a : [[I@1b6d3586, [I@4554617c]
b : [[1, 2, 3], [4, 5, 6]]
c : [[1, 2, 3], [4, 5, 6]]
d[i][j] = 0
d[i][j] : [0]
d[i][j] = 1
d[i][j] = 2
d[i][j] : [1, 2]
d[i][j] = 2
d[i][j] = 3
d[i][j] = 4
d[i][j] : [2, 3, 4]
d[i][j] = 3
d[i][j] = 4
d[i][j] = 5
d[i][j] = 6
d[i][j] : [3, 4, 5, 6]
d[i][j] = 4
d[i][j] = 5
d[i][j] = 6
d[i][j] = 7
d[i][j] = 8
d[i][j] : [4, 5, 6, 7, 8]
a:[[I@7852e922, [I@4e25154f]这种输出结果是因为:
因为a是一个二维数组。相当于一个长度为2的数组,但是这个数组的元素是数组。
当执行Arrays.toString的时候相当于遍历数组,并且输出数组的元素,但是这个数组的元素是数组,所以这里输出的是数组元素的地址。
3.多维数组的引用(以二维数组为例)
对二维数组中的每个元素,引用方式为 arrayName[index1][index2],例如:
num[1][0];
八.Java中对Array数组的常用操作
package com.company;
import java.util.*;
public class Main {
public static void main(String[] args) {
//声明数组
String[] arr;
int[] arr_1;
//初始化数组
int[] arr_2 = new int[]{1, 2, 3, 4};
int[][] d = new int[][]{{1, 2}, {3, 4}};
String[] array_1 = {"马超", "马云", "关羽", "刘备", "张飞"};
String[] array_2 = new String[]{"黄渤", "张艺兴", "孙红雷", "小猪", "牙哥", "黄磊"};
String[] array = new String[5];
//查看数组大小
int length = array_1.length;
System.out.println("array1.length = " + array_1.length);
//输出数组
System.out.println(array_1);//没有下标输出变量名地址
System.out.println(Arrays.toString(arr_2));
//遍历数组
for(int i = 0; i < array_1.length; i++){
System.out.println(array_1[i]);
}
//int数组转成字符串
int[] arr_3 = {1,2,3,4,5,6,7,8,9};
String str = Arrays.toString(arr_3);
System.out.println("str = " + str);
//从array中创建arraylist
ArrayList<String> v = new ArrayList<String>(Arrays.asList(array_1));
System.out.println("v = " + v);
//数组中是否包含某一个值
String a = "马超";
if(Arrays.asList(array_1).contains(a)) {
System.out.println("马超在这里");
}
//将数组转成set集合
Set<String> set = new HashSet<String>(Arrays.asList(array_2));
System.out.println("set = " + set);
//将数组转化为List集合
List<String> list_1 = new ArrayList<String>();
for (int i = 0; i < array_2.length; i++) {
list_1.add(array_2[i]);
}
System.out.println("list_1 = " + list_1);
String[] arrStr = {"1","2","3"};
List<String> list_2 = Arrays.asList(arrStr);
System.out.println("list_2 = " + list_2);
//Arrays.fill()填充数组
int[] arr3 = new int[5];
Arrays.fill(arr3 , 10);//全部填充为10
System.out.println("arr3 = " + arr3);
for (int i = 0; i < arr3.length; i++) {
System.out.println("arr3 : " + arr3[i]);
}
//数组排序
int[] arr4 = new int[]{3,7,2,1,9};
Arrays.sort(arr4);
System.out.println("arr4 = " + arr4);
System.out.println(Arrays.toString(arr4));
for (int i = 0; i >= arr4.length; i++) {
System.out.println("arr4 : " + arr4[i]);
}
int[] arr5 = {3, 7, 2, 1, 9,3,45,7,8,8,3,2,65,34,5};
Arrays.sort(arr5 , 1 ,4);//从第几个到第几个之间的进行排序
System.out.println("arr5 = " + arr5);
for (int i = 0; i < arr5.length; i++) {
System.out.println("arr5 : " + arr5[i]);
}
//复制数组
int[] arr6 = {3,7,2,1};
int[] arr7 = Arrays.copyOf(arr6 , 10);//指定新数组长度
int[] arr8 = Arrays.copyOfRange(arr6 , 1 , 3);//只复制从索引[1]到索引[3]之间的元素(不包括索引[3]的元素)
for (int i = 0; i < arr8.length; i++) {
System.out.println("arr8[i] = " + arr8[i]);
}
//比较两个数组
int[] arr9 = {1,2,3,4,5,6,7,8,9,0};
boolean arr10 = Arrays.equals(arr6 , arr9);
System.out.println("arr10 = " + arr10);
//去重复
//利用set的特性
int[] arr11 = {1, 2, 3, 4,5,6,7,8,9,0,3,2,4,5,6,7,4,32,2,1,1,4,6,3};
Set<Integer> set2 = new HashSet<Integer>();
for (int i = 0; i < arr11.length; i++) {
set2.add(arr11[i]);
}
System.out.println("set2 = " + set2);
int[] arr12 = new int[set2.size()];
int j = 0;
for(Integer i : set2){
arr12[j++] = i;
}
System.out.println(Arrays.toString(arr12));
}
}
运行结果
E:\DevTools\Java\jdk8\bin\java.exe "-javaagent:E:\DevTools\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=51279:E:\DevTools\IntelliJ IDEA 2021.1.3\bin" -Dfile.encoding=UTF-8 -classpath E:\DevTools\Java\jdk8\jre\lib\charsets.jar;E:\DevTools\Java\jdk8\jre\lib\deploy.jar;E:\DevTools\Java\jdk8\jre\lib\ext\access-bridge-64.jar;E:\DevTools\Java\jdk8\jre\lib\ext\cldrdata.jar;E:\DevTools\Java\jdk8\jre\lib\ext\dnsns.jar;E:\DevTools\Java\jdk8\jre\lib\ext\jaccess.jar;E:\DevTools\Java\jdk8\jre\lib\ext\jfxrt.jar;E:\DevTools\Java\jdk8\jre\lib\ext\localedata.jar;E:\DevTools\Java\jdk8\jre\lib\ext\nashorn.jar;E:\DevTools\Java\jdk8\jre\lib\ext\sunec.jar;E:\DevTools\Java\jdk8\jre\lib\ext\sunjce_provider.jar;E:\DevTools\Java\jdk8\jre\lib\ext\sunmscapi.jar;E:\DevTools\Java\jdk8\jre\lib\ext\sunpkcs11.jar;E:\DevTools\Java\jdk8\jre\lib\ext\zipfs.jar;E:\DevTools\Java\jdk8\jre\lib\javaws.jar;E:\DevTools\Java\jdk8\jre\lib\jce.jar;E:\DevTools\Java\jdk8\jre\lib\jfr.jar;E:\DevTools\Java\jdk8\jre\lib\jfxswt.jar;E:\DevTools\Java\jdk8\jre\lib\jsse.jar;E:\DevTools\Java\jdk8\jre\lib\management-agent.jar;E:\DevTools\Java\jdk8\jre\lib\plugin.jar;E:\DevTools\Java\jdk8\jre\lib\resources.jar;E:\DevTools\Java\jdk8\jre\lib\rt.jar;E:\File\codefile\JavaProject\test\out\production\test com.company.Main
array1.length = 5
[Ljava.lang.String;@1b6d3586
[1, 2, 3, 4]
马超
马云
关羽
刘备
张飞
str = [1, 2, 3, 4, 5, 6, 7, 8, 9]
v = [马超, 马云, 关羽, 刘备, 张飞]
马超在这里
set = [小猪, 牙哥, 黄渤, 黄磊, 孙红雷, 张艺兴]
list_1 = [黄渤, 张艺兴, 孙红雷, 小猪, 牙哥, 黄磊]
list_2 = [1, 2, 3]
arr3 = [I@4554617c
arr3 : 10
arr3 : 10
arr3 : 10
arr3 : 10
arr3 : 10
arr4 = [I@74a14482
[1, 2, 3, 7, 9]
arr5 = [I@1540e19d
arr5 : 3
arr5 : 1
arr5 : 2
arr5 : 7
arr5 : 9
arr5 : 3
arr5 : 45
arr5 : 7
arr5 : 8
arr5 : 8
arr5 : 3
arr5 : 2
arr5 : 65
arr5 : 34
arr5 : 5
arr8[i] = 7
arr8[i] = 2
arr10 = false
set2 = [0, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Process finished with exit code 0
九.Arrays 类
java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。
具有以下功能:
- 给数组赋值:通过 fill 方法。
- 对数组排序:通过 sort 方法,按升序。
- 比较数组:通过 equals 方法比较数组中元素值是否相等。
- 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
具体说明请查看下表:
序号 | 方法和说明 |
---|---|
1 | public static int binarySearch(Object[] a, Object key) 用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。 |
2 | public static boolean equals(long[] a, long[] a2) 如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
3 | public static void fill(int[] a, int val) 将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
4 | public static void sort(Object[] a) 对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
十.数组与排序
1.直接查找
- 遍历整个数组,逐一与目标值比较
public static void main(String[] args) {
int[] a = {1, 23, 43, 2, 13, 134};
System.out.println(basicLookup(a, 13));//运行结果 4
System.out.println(basicLookup(a, 22));//运行结果 -1
}
//直接查找
public static int basicLookup(int[] array_1 , int i){
for (int j = 0; j < array_1.length; j++) {
if(i == array_1[j])
return j;
}
return -1;//数组中没有目标值时返回-1
}
}
2.二分查找
(1)使用前提:数组元素是有序的
(2)算法思想:每一次都查找、比较中间的元素;若目标值比中间值小,则在其左侧再进行相同的步骤,否则在右侧进行
public static void main(String[] args) {
int[] array = {10,20,30,40,50,60,70,80,90};
System.out.println(twoPointLookup(array , 70));
}
//二分查找
public static int twoPointLookup(int[] array_1 , int target) {
int low = 0;
int high = array_1.length - 1;
while (low < high) {
int mid = low + (high - low) / 2;//定义中间值下标
// 将目标值与中间值进行比较
if (target == array_1[mid]) {
return mid;// 如果相等则直接返回
} else if (target < array_1[mid]) {
high = mid - 1;//更改查找范围,在 原low ~ 原mid 间查找
} else if (target > array_1[mid]) {
low = mid + 1;//更改查找范围,在 原mid ~ 原high 间查找
}
}
return -1;//数组中没有目标值时返回-1
}
}
3.冒泡排序
核心
(1)比较数组中相邻的两个元素,若前一个数比后一个数大,则交换二者位置
(2)每一次比较,都会产生一个最大或最小的值
(3)第一轮从0到n,第二轮从0到n-1,以此类推,直至结束
public static void main(String[] args) {
int[] arr = {4,7,34,47,8,5,7,6,16,3,98,8,54};
System.out.println(Arrays.toString(pSort(arr)));
//这玩意居然可以套进去,小白震惊
// 我刚开始就尝试了但是因为自定义函数返回值类型没搞好显示报错
// 我还以为不行呢
}
//冒泡排序
//注意返回值的类型是int[],不是int 不然return和主函数输出会报错
//我就是因为没注意这个问题,所以花了半个小时发现并解决这个问题
public static int[] pSort(int[] array){
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length-1-i; j++) {
if(array[j+1] < array[j]){
int temp = array[j+1];
array[j+1] = array[j];
array[j] = temp;
}
}
}
return array;
}
}
4.选择排序
(1)思想:每轮选择出一个最大/最小的元素,放在每轮的起始位置
(2)算法
- 第一轮从0下标开始,选择出一个最大/最小的元素与array[0]交换
- 第二轮从1下标开始,选择出一个最大/最小的元素与array[1]交换
· · · · · ·
- 第(n-1)轮从 n-2 开始,选择出一个最大/最小的元素与array[n-2]交换
public static void main(String[] args) {
int[] arr = {9,6,5,1,56,43,27,878,67,61,34};
System.out.println("arr = " + Arrays.toString(selectSort(arr)));
}
//选择排序
public static int[] selectSort(int[] array){
for (int i = 0; i < array.length; i++) {
int min = i; //假设每轮开头的元素为最小值,随后进行打擂台
for (int j = 1 + i; j < array.length; j++) {
if(array[min] > array[j]){
min = j;// 更新最小值下标
}
} // 将最小值放在每轮开头的位置
int temp = array[i];
array[i] = array[min];
array[min] = temp;
}
return array;
}
}
5.直接插入排序
(1)思想:将一个数插入到原数组(有序)中,时其仍然保持有序状态
(2)算法
从1下标开始(一个元素的数组总是有序的)进行循环
比较后一个元素与前一个元素,若 array[j] < array[j-1] 则交换两者位置,再向前找比它更小的元素。
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8,9,0};
System.out.println(Arrays.toString(insertSort(arr)));
}
//直接插入排序
public static int[] insertSort(int[] array){
//把调换次数变成for循环
for (int i = 1; i < array.length; i++) {
for(int j = i; j > 0; j--){
// 依次往前,寻找一个比它小(最小)的数换位置
if(array[j] < array[j-1]){
int temp = array[j];
array[j] = array[j-1];
array[j-1] = temp;
}
}
}
return array;
}
}
6.希尔排序
(1)思想: 以增量h为间隔比较两个元素,排成有序元素,随后减少h再进行相同的操作,直至h=1时完成对所有数的排序
(2)算法
根据克努特序列寻找最佳增量h
从下标h开始,直至 array.length-1 为止,进入循环
排列此元素和与之相隔 h 距离的元素(向前寻找)
对 h 进行 h = (h-1) / 3 操作,减少 h 的值,再次进行以上操作,直至 h=1 为止
// 希尔算法
private static int[] hillSort(int[] array) {
// 根据克努特序列,寻找最佳增量
int interval = 1;
while(interval < array.length/3)
interval = interval * 3 + 1;
// 插入算法的进阶
// 增量 h 需不断变化,直至为 1 时完成排序后结束
for (int h = interval; h > 0; h = (h-1)/3) {
// 从 h 索引处开始排序
for (int i = h; i < array.length; i++) {
// 将 h 索引值 与前面元素进行比较
for (int j = i; j > h-1; j = j-h) {
if(array[j] < array[j-h]){
int temp = array[j];
array[j] = array[j-h];
array[j-h] = temp;
}
}
}
}
return array;
}
7.快速排序
(1)思想:寻找一个基准数,将数组中大于它的数放右边,小于它的数放左边,再对左右两边进行相同的操作
(2)算法
一般地,选择 array[0] 为基准数
设定 j,从后往前找小于 array[0] 的数,设定 i,从前往后找大于 array[0] 的数,交换两者位置
直至 j =i 为止(总是 j 先寻找),将 array[0] 与 array[i] 交换位置
对原基准数的左右两侧再进行相同的操作
//快速排序
private static void quickSort(int[] array, int low, int high) {
if(low > high)
return;
int i = low;
int j = high;
int base = array[low];
while (i < j) {
//先对右侧进行查找
while (base <= array[j] && i < j) {
j--;
}
//再对左侧进行查找
while (base >= array[i] && i < j) {
i++;
}
//交换两者的值
if (i < j) {
int temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
//将基准数与二者重合处的数进行交换
array[low] = array[i];
array[i] = base;
//对左右两侧再进行相同的操作
quickSort(array,low,j-1);
quickSort(array,j+1,high);
}
8.2路归并排序
(1)思想:对数组进行对半拆分直至分为一个个的,再两两排序至有序状态
(2)算法
对数组进行对半拆分,再进行递归的左右两侧拆分至单个元素
定义一个临时数组
比较左右数组,谁小谁先放入临时数组中,最后再把剩余元素全部放入临时数组中
//2路归并排序
// 拆分
private static void sort(int[] array, int startIndex, int endIndex) {
//计算中间索引
int centerIndex = (startIndex + endIndex) / 2;
if(startIndex < endIndex){
sort(array, startIndex, centerIndex);
sort(array, centerIndex+1, endIndex);
merge(array, startIndex, centerIndex, endIndex);
}
}
// 合并
private static void merge(int[] array, int startIndex, int centerIndex, int endIndex) {
//定义一个临时数组
int[] tempArray = new int [endIndex - startIndex + 1];
//定义左边数组的起始索引
int i = startIndex;
//定义右边数组的起始索引
int j = centerIndex + 1;
//定义临时数组的起始索引
int index = 0;
//放入元素至临时数组
while (i <= centerIndex && j <= endIndex) {
//左边小时,先放左边
if(array[i] <= array[j]){
tempArray[index] = array[i];
i++;
}
//右边小时,先放右边
else{
tempArray[index] = array[j];
j++;
}
index++;
}
//处理剩余元素
while (i <= centerIndex) {
tempArray[index] = array[i];
i++;
index++;
}
while (j <= endIndex) {
tempArray[index] = array[j];
j++;
index++;
}
// 将临时数组的值赋值到原数组中
for (int k = 0; k < tempArray.length; k++)
array[k + startIndex] = tempArray[k];
}