五、java基础-数组

五、数组

【数组定义】:

​ 数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。每一个数据称作一个元素,每个元素通过一个索引(下标)进行访问。

【特点】:

  1. 长度是确定的。数组一旦被创建,它的大小就是不可以改变的
  2. 其元素的类型必须是相同类型,不允许出现混合类型
  3. 数组类型可以是任何数据类型,包括基本类型和引用类型
  4. 数组变量属于引用类型,数组也是对象。
  • 数组变量属于引用类型,也是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java 中对象在堆中,因此数组无论保存原始类型还是其他对象类型,数组对象本身在堆中存储。

5.1 一维数组

1、创建声明

  • 首先必须声明变量,才能使用
dataType[] arrayRefVar;//首选
//或
dataType arrayRefVar[];//效果相同,但不是首选方法

【注意点】:

  1. 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM 才分配空间,这时才与长度有关
  2. 声明一个数组的时候并没有数组真正被创建
  3. 构造一个数组,必须指定长度
  • 创建数组:new
dataType[] arrayRefVar = new dataType[arraysize];
  • 数组元素通过索引访问,数组索引从0开始
  • 获取数组长度
arrays.length

创建一个数组的步骤:

  1. 声明一个数组
  2. 创建数组
  3. 给数组赋值
//1、定义,声明一个数组
int[] s;
//int nums[];
//2、创建数组,给数组分配空间
s = new int[10];
//3、给数组元素赋值;数组是对象,数组中的元素就是对象的属性
for (int i = 0; i < 10; i++) {
	s[i] = 2 * i + 1;//给数组元素赋值; 数组是对象,数组中的元素就是对象的属性
}

五、java基础-数组_第1张图片

【java内存】:

1、堆:

  1. 存放new的对象和数组
  2. 可以被所有线程共享,不会存放别的对象引用

2、

  1. 存放基本类型变量(会包含这个基本类型的具体数值)
  2. 引用对象的值(会存放这个引用在对立面的具体地址)

3、方法区

  1. 可以被所有线程共享
  2. 包含所有的class和static变量

【创建引用型一维数组】

public class Application {
    public static void main(String[] args) {
        Man[ ] mans; //声明引用类型数组;
        mans = new Man[10]; //给引用类型数组分配空间;
        Man m1 = new Man(1,11);
        Man m2 = new Man(2,22);
        mans[0]=m1;//给引用类型数组元素赋值;
        mans[1]=m2;//给引用类型数组元素赋值;
    }
}
class Man{
    private int age;
    private int id;
    public Man(int id,int age) {
        super();
        this.age = age;
        this.id = id;
    }
}

五、java基础-数组_第2张图片

  • 数组下标越界
int[] nums = new int[10];

2、三种初始化

  1. 静态初始化

    除了用 new 关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值

    //创建+赋值
    int[] a = {1,2,3};
    Man[] mans = {new Man(1,1),newMan(2,2)};
    
  2. 动态初始化

    数组定义与为数组元素分配空间并赋值的操作分开进行

    //包含默认初始化
    int[] a = new int[10];
    a[0] = 1;
    a[1] = 2;
    
  3. 默认初始化

    数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化

    int a2[ ] = new int[2]; // 默认值:0,0
    boolean[ ] b = new boolean[2]; // 默认值:false,false
    String[ ] s = new String[2]; // 默认值:null, null
    

3、数组边界问题

  • 下标合法区间:[0,length-1],如果月结将会报错
  • ArrayIndexOutofBoundException

4、数组操作

  1. For-Each 循环
  2. for普通循环遍历
  3. 拷贝
  4. 数组作方法入参
  5. 数组作返回值

(遍历、拷贝最常见)

数组的遍历

for循环:数组元素下标的合法区间:[0, length-1]。可以通过下标来遍历数组中的元素,遍历时可以读取元素的值或者修改元素的值。

int[ ] a = new int[4];
//初始化数组元素的值
for(int i=0;i<a.length;i++){
	a[i] = 100*i;
}
//读取元素的值
for(int i=0;i<a.length;i++){
	System.out.println(a[i]);
}

for-each 循环:增强 for 循环 for-each 是 JDK1.5 新增加的功能,专门用于读取数组或集合中所有的元素,即对数组进行遍历。

  1. for-each 循环在遍历数组过程中不能修改数组中某元素的值
  2. for-each 仅适用于遍历,不涉及有关索引(下标)的操作
//翻转数组
public static int[] reverse(int[] array){
    int[] res = new int[array.length];
    for (int i = 0,j = array.length-1;i< res.length;i++,j--){
        res[i] = array[j];
    }
    return res;
}
//遍历
public static void printarray(int[] array){
    for (int x : array) {
        System.out.print(x+" ");
    }
}

数组的拷贝

System 类中的 static void arraycopy(object src,int srcpos,object dest, int destpos,int length)方法可以将 src 数组里的元素值赋给 dest 数组的元素,其中 srcpos 指定从 src 数组的第几个元素开始赋值,length 参数指定将 src 数组的多少个元素赋给 dest 数组的元素。

String[ ] s = {"张三","李四","王五","小明","小红"};
String[ ] sBak = new String[6];
System.arraycopy(s,0,sBak,1,s.length);
for (int i = 0; i < sBak.length; i++) {
    System.out.print(sBak[i]+ "\t");
}//null	张三	李四	王五	小明	小红

5、Array类

JDK 提供的 java.util.Arrays 类,包含了:排序、查找、填充、打印内容等常见的操作。

  • 打印数组元素:Arrays.toString(arr)
  • 数组排序:升序Arrays.sort(arr)
  • 数组填充: fill()
  • 比较数组:equals
  • 二分查找数组元素:binary Search()
int[ ] arr = {1,2,323,23,543,12,59};
//打印数组元素Arrays.toString
Arrays.toString(arr);
//数组排序:升序Arrays.sort
Arrarys.sort(a);
//数组填充 fill
Arrays.fill(arr,11);
Arrays.fill(arr,2,5,11);将2到5索引的元素替换为11
//使用二分法查找,必须先对数组进行排序
//返回排序后新的索引位置,若未找到返回负数
Arrays.binarySearch(arr, 12));

Comparable 接口

对某个类的对象之间做比较,可以通过Comparable 接口实现。接口中只有一个方法compareTo,这个方法定义了对象之间的比较规则

public int compareTo(Object obj) //obj 为要比较的对象

将当前对象和 obj 这个对象进行比较,如果大于返回 1,等于返回 0,小于返回-1.

public int compareTo(Object obj) {
	Man man = (Man) obj;
	if (this.age < man.age) {
	return -1;
	}
	if (this.age > man.age) {
	return 1;
	}
	return 0;
}
class Man implements Comparable{
    int age;
	int id;
	String name;
	public Man(int age, String name) {
	super();this.age = age;
	this.name = name;
	}
	public String toString() {
	return this.name;
	}
    
    public int compareTo(Object o) {
		Man man = (Man) o;
		if (this.age < man.age) {
			return -1;
		}
		if (this.age > man.age) {
			return 1;
		}
		return 0;
	}
}
public class Test {
	public static void main(String[ ] args) {
		Man[ ] msMans = { new Man(3, "a"), new Man(60, "b"), new Man(2, "c") };
		Arrays.sort(msMans);
		System.out.println(Arrays.toString(msMans));
	}
}

5.2 二维数组

多维数组可以看成以数组为元素的数组(数组的数组),eg:二维数组的每一个元素都是一个一维数组。

int a[][] = new int[2][5];

五、java基础-数组_第3张图片

for (int i = 0;i< array.length;i++){
    for (int j = 0;j<array[i].length;j++){
        System.out.print(array[i][j]+" ");
    }
}

二维数组的声明

// Java中多维数组的声明和初始化应按从低维到高维的顺序进行
int[ ][ ] a = new int[3][ ];
a[0] = new int[2];
a[1] = new int[4];
a[2] = new int[3];
// int a1[ ][ ]=new int[ ][4];//非法

二维数组的静态初始化

int[ ][ ] a = { { 1, 2, 3 }, { 3, 4 }, { 3, 5, 6, 7 } };
System.out.println(a[2][3]);

五、java基础-数组_第4张图片

二维数组的动态初始化

int[ ][ ] a = new int[3][ ];
// a[0] = {1,2,5}; //错误,没有声明类型就初始化
a[0] = new int[ ] { 1, 2 };
a[1] = new int[ ] { 2, 2 };
a[2] = new int[ ] { 2, 2, 3, 4 };
System.out.println(a[2][3]);//4
System.out.println(Arrays.toString(a[0]));//[1,2]
System.out.println(Arrays.toString(a[1]));//[2,2]
System.out.println(Arrays.toString(a[2]))//[2,2,3,4]

获取数组长度

//获取的二维数组第一维数组的长度。
System.out.println(a.length);
//获取第二维第一个数组长度。
System.out.println(a[0].length);

5.3 其他常见API

1、向数组末尾添加/删除一个元素

push()        // 向数组末尾添加一个元素
pop()         // 删除数组最后一个元素

2、向数组开头添加/删除一个元素

unshift()     // 向数组开头添加一个元素
shift()       // 删除数组开头第一个元素

3、对两个数组进行拼接concat()

也可以使用扩展运算符

//arr.concat(['你', '好'], ['欢', '迎'])

4、**对数组进行截取splice() **

当第二个参数不传的时候直接从开始的索引截取到最后一个,直接改变原数组

arr.splice(开始的索引, 截取多少个, 要插入的元素可以不传)

5、截取数组中的值slice()

当第二个参数不传的时候直接从开始的索引截取到最后一个,不改变原数组

arr.slice(开始的索引,结束的索引);

6、**数组排序sort() **

arr.sort(); 

7、**反转数组reverse() **

arr.reverse();

8、字符连接join()

arr.join(以什么字符链接);

9、查找数据当中有没有该元素

includes()

includes() 可以查找出数据当中有没有该元素,使用indexOf也可以

区别:

  • indexOf()方法:不够语义化,找到参数值的第一个出现的位置比较是否不等于-1;indexOf()方法内部使用了严格相等运算符来进行判断,这会导致误判
  • includes()使用的算法不一样所以不会有这个问题

5.4 其他

1、冒泡排序

通过动画可视化数据结构和算法 - VisuAlgo

  • 两层嵌套循环,外层表示冒泡轮数,里层依次比较
  • 时间复杂度O(n2)
  1. 比较相邻的元素,如果第一个数比第二个数大,交换位置
  2. 每次比较都会产生出一个最大/最小的数字
  3. 下一轮则可以少一次排序
  4. 依次循环,直至结束
for (int i = 0 ;i< array.length-1;i++){
	for (int j = 0;j<array.length-1-i;j++){
        if (array[j]<array[j+1]) {
            temp = array[j];
            array[j] = array[j+1];
            array[j+1] = temp;
        }
    }
}

优化

1.整个数列分成两部分:前面是无序数列,后面是有序数列。

2.初始状态下,整个数列都是无序的,有序数列是空。

3.每一趟循环让无序数列中最大数排到最后,(有序数列的元素个数增加1)

4.每一趟循环都从数列的第一个元素开始进行比较,依次比较相邻的两个元素,比较到无序数列的末尾即可(而不是数列的末尾);如果前一个大于后一个,交换。

5.判断每一趟是否发生了数组元素的交换,如果没有发生,则说明此时数组已经有序,无需再进行后续趟数的比较了。此时可以中止比较。

// 外层循环:n个元素排序,则至多需要n-1趟循环
for (int i = 0 ;i< array.length-1;i++){
    // 定义一个布尔类型的变量,标记数组是否已达到有序状态
	boolean flag = false;//通过flag标志位减少没有意义的比较
    /*内层循环:每一趟循环都从数列的前两个元素开始进行比较,比较到无序数组的最后*/
    for (int j = 0;j<array.length-1-i;j++){
        // 如果前一个元素大于后一个元素,则交换两元素的值;
        if (array[j]<array[j+1]) {
            temp = array[j];
            array[j] = array[j+1];
            array[j+1] = temp;
            //本趟发生了交换,表明该数组在本趟处于无序状态,需要继续比较;
            flag = true;
        }
    }
    //根据标记量的值判断数组是否有序,如果有序,则退出;无序,则继续循环
    if (flag == false)
        break;
}

2、二分查找

​ 基本思想是设数组中的元素从小到大有序地存放在数组(array)中,首先将给定值 key 与数组中间位置上元素的关键码(key)比较,如果相等,则检索成功;

​ 否则,若 key 小,则在数组前半部分中继续进行二分法检索;

​ 若 key 大,则在数组后半部分中继续进行二分法检索。

​ 每经过一次比较将缩小一半的检索区间。
五、java基础-数组_第5张图片

//Arrays.sort(arr); 
//二分法查找之前,先要对数组元素排序
int low = 0;
int high = array.length - 1;
while(low <= high){
	int middle = (low + high) / 2;
	if(value == array[middle]){
		return middle; //返回查询到的索引位置
	}
	if(value > array[middle]){
		low = middle + 1;
	}
	if(value < array[middle]){
		high = middle - 1;
	}
}
return -1; //上面循环完毕,说明未找到,返回-1
3、稀疏数组
  • 压缩算法

五、java基础-数组_第6张图片

  • 当一个数组中大部分元素为0,或者同一值的数组时,可以使用稀疏数组来保存该数组
  • 处理方式:
  1. 记录数组一共有几行几列,有多少个不同的值
  2. 把具有不同值的元素和行列及值记录在一共小规模的数组中,从而缩小程序的规模
//1.创建一共11×11的二维数组
//0:没有;1:白棋;2:黑棋
int[][] arr = new int[11][11];
arr[1][2] = 1;
arr[2][3] = 2;
System.out.println("输出原始的数组");
for (int[] Ints : arr){
    for (int anInt : Ints){

        System.out.print(anInt+"\t");
    }
    System.out.println();
}
//转换为稀疏数组
//遍历获取有效值的个数
int sum = 0;
for (int[] Ints : arr){
    for (int anInt : Ints){
        if (anInt!=0)   sum++;
    }
}
System.out.println("有效值个数为:"+sum);
//创建一个稀疏数组
int[][] arr2 = new int[sum+1][3];

arr2[0][0] = 11;
arr2[0][1] = 11;
arr2[0][2] = sum;

//遍历二维数组,将非零值存入稀疏数组
int k = 0;
for (int i =0;i<arr.length;i++)
    for (int j =0;j<arr[i].length;j++){
        if (arr[i][j] != 0){
            k++;
            arr2[k][0] = i;
            arr2[k][1] = j;
            arr2[k][2] = arr[i][j];
        }
    }
System.out.println("稀疏数组表示为:");
for (int[] Ints : arr2){
    for (int anInt : Ints)
        System.out.print(anInt+"\t");
    System.out.println();
}

五、java基础-数组_第7张图片

//还原稀疏数组
int[][] rearray = new int[newarray[0][0]][newarray[0][1]];
for (int i = 1;i< newarray.length;i++){
    rearray[newarray[i][0]][newarray[i][1]] = newarray[i][2];
}
for (int[] Ints : rearray){
    for (int anInts:Ints){
        System.out.print(anInts+"\t");
    }
    System.out.println();
}

你可能感兴趣的:(Java,java,开发语言)