博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java——数组
阅读量:3956 次
发布时间:2019-05-24

本文共 26072 字,大约阅读时间需要 86 分钟。

文章目录

1. 数组概述

Java语言中的数组是一种引用数据类型。不属于基本数据类型。数组的父类是Object

在这里插入图片描述

  • 数组实际上是一个容器,可以容纳多个元素(数组是相同类型数据的有序集合)
  • 数组当中可以存储“基本数据类型”的数据,也可以存储“引用数据类型”的数据
  • 因为数组是引用数据类型,所以数组对象是在堆内存当中
  • 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。

1.1 数组内存图

  • 数组当中如果存储的是“Java对象”的话,实际上存储的是对象的“引用(内存地址)”,数组不能直接存储java对象
  • 数组一旦创建,在java中规定,长度不可变
    在这里插入图片描述

数组存储元素的特点:

  • 数组在内存方面存储的时候,数组中的元素内存地址(存储的每一个元素都是有规则的挨着排列的)是连续的。内存地址连续
  • 数组实际上是一种简单的数据结构
    在这里插入图片描述

所有的数组都是拿“第一个小方框的内存地址”作为整个数组对象的内存地址。(数组中首元素的内存地址作为整个数组对象的内存地址)

原因:数组存储元素的时候,内存地址是连续的,知道了第一个元素的内存地址,      可以算出第二个,以此类推,算出所有的元素内存地址

在这里插入图片描述

1.2 数组的分类

  • 所有的数组对象都有length属性(java自带的)用来获取数组中元素的个数
    在这里插入图片描述

1.3 数组的四个基本特点

  • 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的

  • 其元素必须是相同类型,不允许出现混合类型

    例如:int类型数组只能存储int类型,Person类型数组只能存储Person类型
  • 数组中的元素可以是任何数据类型,包括基本类型和引用类型

  • 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相对于该对象的成员变量。

数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的

1.4 数组边界

在这里插入图片描述

  • 数组中每一个元素都是有下标的,下标从0开始,以1递增,最后一个元素的下标是:length-1
  • 下标的合法区间:[0,length-1],如果越界就会报错;
  • 我们对数组中的元素进行存取的时候,都需要通过下标来进行
public class ArrayDemo03 {
public static void main(String[] args) {
int[] a = new int[2]; System.out.println(a[2]); }}

java.lang.ArrayIndexOutOfBoundsException:数组下标越界异常

小结

  • 数组是相同数据类型(数据类型可以为任意类型)的有序集合
  • 数组也是对象。数组元素相对于对象的成员变量
  • 数组长度是确定的,不可变的。如果越界,则报错ArrayIndexOutOfBounds

1.5 数组这种数据结构的优缺点?

1.5.1 优点

查询 / 查找 / 检索某个下标上的元素时效率极高。可以说是查询效率最高的一个数据结构

  • 原因一:每一个元素的内存地址在空间存储上是连续的

  • 原因二:每一个元素类型相同,所以占用空间大小一样

  • 原因三:知道第一个元素内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。直接通过内存地址定位元素,所以数组的检索效率最高的

    数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,  因为数组中元素查找的时候不会一个一个找,是通过数学表达式计算出来的  (算出内存地址,直接定位)

1.5.2 缺点

  • 第一:由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候,效率较低,因为随机增删元素会涉及到后面元素统一向前或者向后位移的操作
  • 第二:数组不能存储大数据量,因为很难在内存空间上找到一块特别大的连续的内存空间

注意:对于数组中最后一个元素的增删,是没有效率影响的

2. 一维数组

2.1 声明一维数组

首先必须声明数组变量,才能在程序中使用数组。

下面是声明数组变量的语法:

dataType[] arrayRefVar;	//首选的方法	int[] array1	double[] array2	boolean[] array3	String[] array3	Object[] array5

dataType arrayRefVar[];	//效果相同,但不是首选方法

2.2 创建一维数组

声明完数组之后对数据进行创建,分配内存空间

arrayRefVar = new dataType[空间大小];

Java语言也可以使用new操作符将声明和创建二合一创建数组,语法如下:

dataType[] arrayRedVar = new dataType[arraySize];

数组的元素是通过索引访问的,数组索引从0开始

获取素组的长度:

arrays.length
代码里面声明创建数组package com.pudding.array;public class ArrayDemo01 {
//变量的类型 变量的名字 = 变量的值; //数组类型 public static void main(String[] args) {
int[] nums; //1. 声明一个数组// int nums[]; //分配空间:这里面可以存放10个int类型的数字 nums = new int[10]; //2. 创建数组 //声明和创建合二为一// int[] nums = new int[10]; //3. 给数组元素中赋值 nums[0] = 1; nums[1] = 2; nums[2] = 3; nums[3] = 4; nums[4] = 5; nums[5] = 6; nums[6] = 7; nums[7] = 8; nums[8] = 9; nums[9] = 10; //计算所有元素的和 int sum = 0; //获取数组长度:arrays.length for (int i = 0; i < nums.length; i++) {
sum = sum + nums[i]; } System.out.println("总和为:"+sum); }}

在这里插入图片描述

2.3 初始化一维数组

1. Java内存分析:

在这里插入图片描述

在这里插入图片描述

2. 三种初始化状态:

1. 静态初始化:

int[] a = {1,2,3};Man[] mans = {new Man(1,1), new Man(2,2)};

C++风格和Java风格:

C++风格不建议使用:int a[] = {1,100,10,20,55}; Java风格:		  int[] a = {1,100,10,20,55};
public class ArrayTest01 {
public static void main(String[] args) {
//声明一个int类型的数组,使用静态初始化的方式 int[] a = {
1,100,10,20,55,689}; //所有的数组对象都有length属性 System.out.println("数组中元素的个数"+a.length); //数组中每一个元素都有下标 //通过下标对数组中的元素进行存和取 //取(读) System.out.println("第一个元素 = "+a[0]); System.out.println("最后一个元素 = "+a[a.length - 1]); //存(改) //把第一个元素修改为111 a[0] = 111; //把最后一个元素修改为0 a[a.length-1] = 0; System.out.println("第一个元素 = "+a[0]); System.out.println("最后一个元素 = "+a[5]); //一维数组怎么遍历? for (int i = 0; i < a.length; i++) {
System.out.println(a[i]); //i是0到5,是下标 } //下标为6表示第7个元素,下标越界了,会出现什么异常?// System.out.println(a[6]); //ArrayIndexOutOfBoundsException 数组下标越界异常 //从最后一个元素遍历到第一个元素 for (int i = a.length - 1; i > 0; i--) {
System.out.println("颠倒顺序输出-->" + a[i]); } }}

2. 动态初始化:

int[] a = new int[2]; //这个的2表示数组的元素个数					  //初始化一个5个长度的int类型数组,每个元素默认值0a[0] = 1;a[1] = 2;String[] names = new String[6]; //初始化6个长度的String类型数组,每个元素默认值null
public class ArrayTest02 {
public static void main(String[] args) {
//声明/定义一个数组,采用动态初始化的方式创建 int[] a = new int[4]; //创建长度为4的int数组,数组中每一个元素的默认值是0 //遍历数组 for (int i = 0; i < a.length; i++) {
System.out.println("数组中下标为:"+i+"的元素为"+a[i]); } //后期赋值,注意下标别越界 a[0] = 1; a[1] = 2; a[2] = 3; a[3] = 4; //初始化一个Object类型的数组,采用动态初始化方式 Object[] obj = new Object[3]; //3个长度,动态初始化,所有每个默认值是null for (int i = 0; i < obj.length; i++) {
System.out.println(obj[i]); } //采用静态初始化数组的方式 Object o1 = new Object(); Object o2 = new Object(); Object o3 = new Object(); Object[] objects = {
o1,o2,o3}; for (int i = 0; i < objects.length; i++) {
System.out.println(objects[i]); //println默认调用toString方法, // 输出java.lang.Object@3f99bd52 //java.lang.Object@4f023edb //java.lang.Object@3a71f4dd } //等价于 //Object[] object = {new Object(),new Object(), new Object()}; System.out.println("========================="); String[] strs = new String[3]; //动态初始化数组 for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]); } //采用静态初始化的方式 String[] strs2 = {
"abc","def","xyz"}; for (int i = 0; i < strs2.length; i++) {
System.out.println(strs2[i]); } }}

在这里插入图片描述

3. 数组的默认初始化

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

/*关于每个类型的默认值还有印象?    数据类型        默认值    --------------------    byte            0    short           0    int             0    long            0L    float           0.0F    double          0.0    boolean         false    char            \u0000    引用数据类型     null */
public class ArrayDemo02 {
public static void main(String[] args) {
//静态初始化:创建+赋值 (这个是基本类型) int[] a = {
1,2,3,4,5,6,7,8}; System.out.println(a[0]); //动态初始化: 包含默认初始化 int[] b = new int[10]; b[0] = 10; System.out.println(b[0]); System.out.println(b[1]); //默认初始化中的值都是0 System.out.println(b[2]); System.out.println(b[3]); }}

什么时候采用静态初始化,什么时候采用动态初始化?

  • 当你创建数组的时候,确定数组中存储哪些具体的元素的时候,采用静态初始化方式
  • 当你创建数组的时候,不确定将来数组中存储哪些数据,你可以采用动态初始化的方式,预先分配内存空间,之后再赋值

2.4 使用一维数组

1. 一维数组的遍历

public class ArreyDemo04 {
public static void main(String[] args) {
int[] arrays = {
1,2,3,4,5}; //打印全部的数组元素 for (int i=0; i
max){
max = arrays[i]; } } System.out.println("max = "+max); }}

For-Each循环

public class ArrayDemo05 {
public static void main(String[] args) {
int[] arrays = {
1,2,3,4,5}; for (int array : arrays) {
//增强型的for循环,JDK1.5之后,没有下标 System.out.println(array); } }}

2. 数组作为方法的参数类型进行传参

数组作为方法的参数举例理解

package com.pudding.array;public class ArrayDemo05 {
public static void main(String[] args) {
int[] arrays = {
1,2,3,4,5}; int[] reverse = reverse(arrays); printArray(reverse); } //打印数组元素 public static void printArray(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+" "); } } //反转数组 public static int[] reverse(int[] arrays){
int[] result = new int[arrays.length]; //反转的操作 for (int i = 0,j=result.length-1; i < arrays.length; i++,j--) {
result[i] = arrays[j]; } return result; }}

当一个方法上,参数类型是一个数组的时候,我们可以采用以下基本传参方式。

public class ArrayTest03 {
//main方法的编写方式,还可以采用C++的语法格式 public static void main(String args[]) {
//调用方法时传一个数组 int[] x = {
1,2,3,4}; printArray(x); //创建String数组 String[] strs= {
"abc","def","hehe","haha"}; printArray(strs); //动态创建数组 String[] strArray = new String[10]; printArray(strArray); //10个null System.out.println("==============="); printArray(new String[3]); System.out.println("****************"); printArray(new int[4]); } public static void printArray(int[] array){
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]); } } public static void printArray(String[] args){
for (int i = 0; i < args.length; i++) {
System.out.println("String数组中的元素:"+args[i]); } }}

当一个方法的参数是一个数组的时候,我们还可以采用这种方式传参,采用静态初始化直接传参。

public class ArrayTest04 {
public static void main(String[] args) {
//静态初始化一维数组 int[] a = {
1,2,3}; printArray(a); System.out.println("============"); //没有这种语法 //printArray({1,2,3}); //如果直接传递一个静态数组的话,语法必须这样写 printArray(new int[]{
1,2,3}); //动态初始化一维数组 int[] a2 = new int[4]; printArray(a2); System.out.println("========="); printArray(new int[2]); } //使用静态方法方便啊,不需要new对象了 public static void printArray(int[] array){
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]); } }}

3. main方法上面的"String[ ] args"有什么用?

分析 一下:谁负责调用main方法(JVM)

  • JVM调用main方法的时候,会自动传一个String数组过来
public class ArrayTest05 {
//这个方法程序员负责写出来,JVM负责调用的时候一定会传入一个String数组过来 public static void main(String[] args) {
//JVM默认传递过来的这个数组对象长度:默认0 //通过测试得出:args不是null System.out.println("JVM给传递过来的String数组参数,他这个数组长度是:"+args.length); /* //类似:以下代码表示的含义:数组对象创建了,但还是数组中没有任何数据 //String[] strs = new String[0]; String[] strs = {}; //静态初始化,里面没有东西 printlength(strs); String[] strs2 = new String[1]; System.out.println(strs2[0]); //默认初始化里面的一个数据为null */ //遍历数组 for (int i = 0; i < args.length; i++) {
System.out.println(args[i]); } } public static void printlength(String[] args){
System.out.println(args.length); //长度为0 }}

这个数组什么时候里面会有值?

  • 其实这个数组是留给用户的,用户可以在控制台上输入参数,这个参数自动会转换为"String[] args"
  • 例如这样的程序:java ArrayTest05 abc def xyz
  • 那么这个时候JVM会自动将"abc def xyz"通过空格的方式进行分离,分离完成之后,自动放到"String[] args"数组当中
  • 所以main方法上面的String[] args数组主要是用来接收用户输入参数的
  • 把abc def xyz 转换为字符串数组:{“abc”,“def”,“xyz”}

CMD中

在这里插入图片描述
IDEA中
在这里插入图片描述
模拟一个系统,假设这个系统要使用,必须输入用户名和密码

public class ArrayTest06 {
//用户名和密码输入到String[] args数组当中 public static void main(String[] args) {
if (args.length != 2){
System.out.println("使用该系统时请输入程序参数,参数中包括用户名和密码信息,例如:zhangsan 123"); return; } //程序执行到此处说明用户确实提供了用户名和密码 //接下来你应该判断用户名和密码是否正确 //取出用户名 String username = args[0]; //取出密码 String password = args[1]; //假设用户名是admin,密码是123的时候表示登录成功,其他一律失败 //判断两个字符串是否相等,需要使用equals方法 //if (username.equals("admin") && password.equals("123")){
//下面编写可以避免空指针异常,即使username和password都是null也不会出现空指针异常 if ("admin".equals(username) && "123".equals(password)){
System.out.println("登录成功,欢迎["+username+"]回来"); } else {
System.out.println("验证失败,用户名不存在或者密码错误"); } }}

非重点:以后一般都是有界面的,用户可以在界面上输入用户名和密码等参数信息。

4. 数组中存储引用数据类型

一维数组的深入,数组中存储的类型为:引用数据类型

  • 对于数组来说,实际上只能存储java对象的"内存地址",数组中存储的每个元素是“引用”。
package com.array;public class ArrayTest07 {
public static void main(String[] args) {
//array是一个数组 //array[0] 是数组中的一个元素 int[] array = {
1,2,3}; for (int i = 0; i < array.length; i++) {
int temp = array[i]; System.out.println(temp); } //创建一个Animal类型的数组 Animal a1 = new Animal(); Animal a2 = new Animal(); Animal[] animals = {
a1,a2}; //对Animal数组进行遍历 for (int i = 0; i < animals.length; i++) {
/* Animal a = animals[i]; a.move(); */ //代码合并 animals[i].move(); //这个move()方法不是数组的,是数组当中Animal对象的move()方法 } //动态初始化一个长度为2的Animal类型数组 Animal[] ans = new Animal[2]; //创建一个Animal对象,放到数组里的第一个盒子中 ans[0] = new Animal(); //Animal数组中只能存放Animal类型,不能存放Product类型 //ans[1] = new Product() //Animal数组中可以存放Cat类型的数据,因为Cat是一个Animal //Cat是Animal子类 ans[1] = new Cat(); //创建一个Animal类型的数组,数组中存储Cat和Brid Animal[] anis = {
new Cat(), new Bird()}; //该数组中存储了两个对象的内存地址 for (int i = 0; i < anis.length; i++) {
/* //这个取出来的可能是Cat,也可能是Bird,不过肯定是一个Animal //如果调用的方法是父类中存在的方法不需要向下转型,直接使用父类型引用调用即可 Animal an1 = anis[i]; an1.move(); */ //Animal中没有sing()方法 //anis[i].sing(); //调用子对象中特有的方法的话,需要向下转型 if (anis[i] instanceof Cat){
Cat cat = (Cat)anis[i]; cat.catchMouse(); } else if (anis[i] instanceof Bird){
Bird bird = (Bird)anis[i]; bird.sing(); } } }}class Animal{
public void move(){
System.out.println("Animal move..."); }}//商品类class Product{
}//子类猫class Cat extends Animal{
public void move(){
System.out.println("Cat move..."); } //特有的方法 public void catchMouse(){
System.out.println("猫抓老鼠。。"); }}//Bird子类class Bird extends Animal{
public void move(){
System.out.println("Bird fly...."); } //特有的方法 public void sing(){
System.out.println("鸟儿在歌唱"); }}

5. 数组扩容

在java开发中,数组长度一旦确定不可变,那么数组满了的怎么办?

  • java中数组的扩容是:先新建一个大容量的数组,然后将小容量的数组中的数据一个一个拷贝到大数组当中,小数组对象被垃圾回收。
  • 结论:数组扩容效率比较低,因为涉及到拷贝的问题。所以在以后的开发中请注意:尽可能少的进行数组的拷贝。
  • 可以在创建数组对象的时候预估以下多长合适,最好预估准确,这样可以减少数组的扩容次数。提高效率
    在这里插入图片描述
    在这里插入图片描述

6. 数组拷贝

package com.array;public class ArrayTest08 {
public static void main(String[] args) {
//java中的数组是怎么进行拷贝的? //System.arraycopy(5个参数); //拷贝源(从数组中拷贝) int[] src = {
1,11,22,3,4}; //拷贝目标(拷贝到这个目标数组上) int[] dest = new int[20]; //动态初始化一个长度为20的数组,每一个元素的默认值为0 /* //调用JDK,System类中的arraycopy方法,来完成数组的拷贝 System.arraycopy(src, 1, dest, 3, 2); //遍历目标数组 for (int i = 0; i < dest.length; i++) { System.out.println(dest[i]); //0 0 0 11 22 0 ...0 } */ System.arraycopy(src, 0, dest, 0, src.length); for (int i = 0; i < dest.length; i++) {
System.out.println(dest[i]); } //数组中存储的元素是引用类型的话,也可以拷贝 String[] strs = {
"hello","world","study","java","oracle","mysql","jdbc"};//字符串数组 String[] newStrs = new String[20]; System.arraycopy(strs,0,newStrs,0,strs.length); for (int i = 0; i < newStrs.length; i++) {
System.out.println(newStrs[i]); //hello world study java oracle mysql jdbc null... } Object[] objs = {
new Object(), new Object(), new Object()}; Object[] newObjs = new Object[5]; //这里拷贝的时候,是拷贝对象的地址 System.arraycopy(objs,0,newObjs,0,objs.length); for (int i = 0; i < newObjs.length; i++) {
System.out.println(newObjs[i]); //默认调用toString方法 /* 输出结果: java.lang.Object@3f99bd52 java.lang.Object@4f023edb java.lang.Object@3a71f4dd null null */ } }}

在这里插入图片描述

3. 二维数组

多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,特殊在,这个一维数组当中的每一个元素都是一个一维数组

  • 三位数组是一个特殊的二维数组,特殊在这个二维数组中每一个元素都是一个一维数组
  • 实际开发中使用最多的就是一维数组,二维数组很少使用,三位数组几乎不用

在这里插入图片描述

在这里插入图片描述

(1). 创建二维数组

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

以上二维数组a可以看成一个两行五列的数组

package com.pudding.array;public class ArrayDemo06 {
public static void main(String[] args) {
//[4][2] /* 1,2 array[0] 2,3 array[1] 3,4 array[2] 4,5 array[3] */ int[][] array = {
{
1,2},{
2,3},{
3,4},{
4,5}}; printArray(array[0]); //打印的是二维数组中的第一行的一维数组 System.out.println(); System.out.println(array[0][0]); //二维数组的第一行第一列的值 System.out.println(array[0][1]); for (int i = 0; i < array.length; i++) {
//外面空间数组长度 for (int j = 0; j < array[i].length; j++) {
//每一个一维数组的长度 System.out.println(array[i][j]); } } } //打印数组元素 public static void printArray(int[] arrays){
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+" "); } }}

(2). 初始化二维数组

1. 二维数组的静态初始化和动态初始化

静态初始化

int[][] arr = {
{
112,2.3}, {
3,43}, {
34,23,3,5} }; Object[][] arr = {
{
new Object(),new Object()}, {
new Object(),new Object(),new Object()}, {
new Object(),new Object()} };

动态初始化

int[][] arr = new int[3][4];   //三行四列Object[][] arr = new Object[4][4]; //四行四列Animal[][] arr = new Animal[2][2];//animal类型数组,里面可以存储animal类型对象,以及animal类型子类型

2. 二维数组length属性

package com.array;public class ArrayTest09 {
public static void main(String[] args) {
//一维数组 int[] array = {
100,200,300}; System.out.println(array.length); //3个 //二维数组 //以下代码当中:里面是4个一维数组 int[][] a = {
{
100,200,300}, {
30,20,40,50,60}, {
6,7,9,1}, {
0} }; System.out.println(a.length); //4个元素 System.out.println(a[0].length); //3个元素 System.out.println(a[1].length); //5个元素 System.out.println(a[3].length); //1个元素 }}

(3). 使用二维数组

1. 二维数组的元素访问

package com.array;/*关于二维数组中元素的:读和该    a[二维数组中的一维数组的下标][一维数组的下标]    a[0][0]:表示第一个一维数组中的第一个元素    注意对于a[3][100]来说,其中a[3]是一个整体,[100]是前面a[3]执行结束的结果然后再下标100. */public class ArrayTest10 {
public static void main(String[] args) {
//二维数组 int[][] a = {
{
11,23,54}, {
100,23,432,234}, {
0} }; //请取出以上二维数组中的第一个一维数组 int[] 我是第1个一维数组 = a[0]; int 我是第1个一维数组中的第1个元素 = 我是第1个一维数组[0]; System.out.println(我是第1个一维数组中的第1个元素); //11 //合并以上代码 System.out.println(a[0][0]); //11 //注意别越界 // System.out.println(a[2][1]); //ArrayIndexOutOfBoundsException //取出第二个一维数组当中第三个元素 System.out.println("第二个数组中第三个元素:"+a[1][2]); //432 //改 a[2][0] = 11111; System.out.println(a[2][0]); //11111 }}

2. 二维数组的遍历

package com.array;public class ArrayTest11 {
public static void main(String[] args) {
//二维数组 String[][] array = {
{
"java","oracle","c++","c#"}, {
"张三","李四","王五"}, {
"lucy","jack","rose"} }; //遍历二维数组 for (int i = 0; i < array.length; i++) {
//外层循环3次(负责纵向,也就是外面的一维数组) /* String[] 一维数组 = array[i]; //负责遍历一维数组 for (int j = 0; j < 一维数组.length; j++) { System.out.println(一维数组[j]+""); } */ //合并代码 //内存循环负责输出一行,负责遍历二维数组里面的一维数组 for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]+" "); } //换行 System.out.println(); } }}

3. 方法的参数是一个二维数组

package com.array;/** 动态初始化二维数组* */public class ArrayTest12 {
public static void main(String[] args) {
//3行4列:3个一维数组,每一个一维数组当中4个元素 int[][] array = new int[3][4]; //二维数组遍历 /* for (int i = 0; i < array.length; i++) { //循环3次 for (int j = 0; j < array[i].length; j++) { //循环4次 System.out.print(array[i][j]+" "); } System.out.println(); } */ //静态初始化 int[][] a = {
{
1,2,3,4}, {
4,5,6,76}, {
1,23,4} }; printArray(a); //没有这种语法 //printArray({
{1,2,3,4}, {4,5,6,76}, {1,23,4}}); //可以这样写 printArray(new int[][]{
{
1,2,3,4}, {
4,5,6,76}, {
1,23,4}}); } public static void printArray(int[][] array){
//二维数组遍历 for (int i = 0; i < array.length; i++) {
//循环3次 for (int j = 0; j < array[i].length; j++) {
//循环4次 System.out.print(array[i][j]+" "); } System.out.println(); } }}

4. 数组模拟题目练习

(1). 数组模拟栈数据结构

编写程序,使用一维数组,模拟数据结构

要求:    1. 这个栈可以存储java中的任何引用类型的数据    2. 在栈中提供push方法模拟压栈(栈满了,要有提示信息)、    3. 在栈中提供pop方法模拟弹栈(栈空了,也要有提示信息)    4. 编写测试程序,new栈对象,调用push、pop方法来模拟压栈弹栈的动作
  • Object[]这是一个万能的口袋,这个口袋中可以装任何引用数据类型的数据

5. Arrays类

4.1 概述

数组工具类java.util.Arrays

由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作

Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而不用使用对象来调用(注意:是不用,而不是不能)

4.2 Arrays具有以下常用的功能

  • 给数组赋值:通过fill方法
  • 对数组排序:通过sort方法,按升序
  • 比较数组:通过equals方法比较数组中元素值是否相等
  • 查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作
package com.pudding.array;import java.util.Arrays;public class ArrayDemo07 {
public static void main(String[] args) {
int[] a = {
1,23,43,6,12390,1323,23}; System.out.println(a); //对象的哈希code[I@154617c //打印数组元素Arrays.toString System.out.println(Arrays.toString(a)); printArray(a); Arrays.sort(a); //数组进行排序: 顺序 System.out.println(Arrays.toString(a)); Arrays.fill(a,2,4,0); //数组填充(将下标2-4填充为0) System.out.println(Arrays.toString(a)); } //重复造轮子 public static void printArray(int[] a){
for (int i = 0; i < a.length; i++) {
if (i==0){
System.out.print("["); } if (i==a.length-1){
System.out.print(a[i]+"]"); }else {
System.out.print(a[i]+", "); } } }}

5. 对数组的基本操作

(1). 遍历数组

(2). 对数组进行排序

5.2.1 冒泡排序

冒泡排序无疑是最为出名的排序算法之一,总共有八大排序

在这里插入图片描述

冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较,江湖中人人尽皆知。

我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度0(n2)

冒泡排序package com.pudding.array;import java.util.Arrays;public class ArrayDemo08 {
public static void main(String[] args) {
int[] a = {
1,2,6,23,12,33,-6}; int[] sort = sort(a); //调用完我们自己写的排序方法以后,返回一个排序后的数组 System.out.println(Arrays.toString(sort)); } //冒泡排序 //1. 比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置 //2. 每一次比较,都会产生出一个最大,或者最小的数字; //3. 下一轮则可以少一次排序 //4. 依次循环,直到结束! public static int[] sort(int[] array){
//临时变量 int temp = 0; //外层循环,判断我们这个要走多少次; for (int i = 0; i < array.length-1; i++) {
//内存循环,比较判断两个数,如果第一个数比第二个数大,则交换位置 for (int j = 0; j < array.length-1-i; j++) {
if (array[j+1] < array[j]){
temp = array[j+1]; array[j+1] = array[j]; array[j] = temp; } } } return array; }}

(3). 填充替换数组元素

(4). 复制数组

(5). 数组查询

(6). 稀疏数组

需求:编写五子棋游戏中,有存盘退出和续上盘的功能

在这里插入图片描述
其中黑子代表1,白子代表2,因为该二维数组的很多默认值0,因此记录了很多没有意义的数据。

解决方式:通过稀疏数组(压缩)

6.1 稀疏数组的介绍

当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组。

稀疏数组的处理方式:

  • 记录数组一共有几行几列,有多少个不同值
  • 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模

如下图:左边是原始数组,右边是稀疏数组

在这里插入图片描述

6.2 稀疏数组的应用

package com.pudding.array;public class ArrayDemo09 {
public static void main(String[] args) {
//1. 创建一个二维数组11*11, 0:没有棋子,1:黑棋,2:白棋 int[][] array1 = new int[11][11]; array1[1][2] = 1; array1[2][3] = 2; //输出原始的数组 System.out.println("输出原始的数组"); for (int[] ints : array1) {
for (int anInt : ints) {
System.out.print(anInt+"\t"); } System.out.println(); } System.out.println("==================="); //转换为稀疏数组保存 //获取有效值的个数 int sum = 0; for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (array1[i][j]!=0){
sum++; } } } System.out.println("有效值的个数:"+sum); //1. 创建一个稀疏数组的数组 int[][] array2 = new int[sum+1][3]; array2[0][0] = 11; //代表数组有多少行 array2[0][1] = 11; //代表数组有多少列 array2[0][2] = sum; //代表有效值的个数 //遍历原来的二维数组,将非零的值存放到稀疏数组中 int count = 0; for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if (array1[i][j]!=0){
count++; array2[count][0] = i; //获取原数组位置赋值给稀疏数组的第count行第1列 array2[count][1] = j; array2[count][2] = array1[i][j];//或者原数组的值赋值给稀疏数组的第count行第3列 } } } //输出稀疏数组 System.out.println("稀疏数组"); for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i][0]+"\t" +array2[i][1]+"\t" +array2[i][2]+"\t"); } System.out.println("==================="); System.out.println("还原数组"); //1. 读取稀疏数组的值 int[][] array3 = new int[array2[0][0]][array2[0][1]]; //2. 给其中的元素还原它的值 for (int i = 1; i < array2.length; i++) {
array3[array2[i][0]][array2[i][1]] = array2[i][2]; } //打印 System.out.println("输出还原的数组"); for (int[] ints : array3) {
for (int anInt : ints) {
System.out.print(anInt+"\t"); } System.out.println(); } }}结果如下:输出原始的数组0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ===================有效值的个数:2稀疏数组11 11 2 1 2 1 2 3 2 ===================还原数组输出还原的数组0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

转载地址:http://qqxzi.baihongyu.com/

你可能感兴趣的文章
栈实现(数据结构---数组,链表 C实现)
查看>>
POJ3903(dp,最长上升子序列,最基础题)
查看>>
POJ1836-Alignment(最长上升子序列)
查看>>
POJ 1251 Jungle Roads(最小生成树简单题)
查看>>
HDU 1690---Bus System(Floyd模板题+合理定义INF)
查看>>
POJ 2240---Arbitrage(Floyd的dp思想)
查看>>
Dijkstra算法---模板
查看>>
POJ 3680(费用流)
查看>>
校oj10532: 生成字符串(dp,最优状态转移)
查看>>
平衡二叉树(AVL树)
查看>>
POJ1521---哈夫曼编码,求最优WPL
查看>>
POJ---2010(Moo University - Financial Aid,优先队列)
查看>>
POJ---3662(Telephone Lines,最短路+二分*好题)
查看>>
L2-007. 家庭房产(并查集)
查看>>
L2-016. 愿天下有情人都是失散多年的兄妹(搜索)
查看>>
L2-019. 悄悄关注
查看>>
POJ 3468 A Simple Problemwith Integers(SplayTree入门题)
查看>>
营业额统计 HYSBZ - 1588 (伸展树简单应用)
查看>>
HDU 1890 Robotic Sort(伸展树---反转应用)
查看>>
POJ 3580 SuperMemo(伸展树的几个基本操作)
查看>>