Java数组

一、IDEA项目结构:

1.层级关系:

project(工程)——module(模块)——package(包)——class(类)

一个project中可以创建多个module;

一个module中可以创建多个package;

一个package中可以创建多个class

2.Project和Module概念:

在IDEA中Project是最顶级的结构单元,然后就是Module;目前主流的大型项目结构基本都是多Module的结构,这类项目一般是按功能划分的。模块之间彼此可以相互依赖,有着不可分割的业务关系。因此对于一个Project来说:

(1)当为单Module项目的时候,这个单独的Module实际上就是一个Project;

(2)当为多Module项目的时候,多个模块处于同一个Project之中,此时彼此之间具有互相依赖的关联关系;

(3)当然多个模块没有建立依赖关系的话,也可以作为单独一个小项目运行;

3.Module和Package:

在一个Module中,可以有多个Package,Package的命名规则如下:

(1)不含有中文

(2)不要以数字开头

(3)给包取名时一般都是公司域名倒着写,并且都是小写

二、数组的概述

1.需要数组的原因:

将多个数据存储到一起,每个数据称为容器的元素

2.数组的概念:

数组是多个相同类型的数据按照一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理;

3.数组的特点:

(1)数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型

(2)创建数组对象会在内存中开辟一整块的连续空间,占据的空间大小取决于数组的长度和数组中元素的类型

(3)数组中元素在内存中是依次紧密排列的,有序的

(4)数组一旦初始化完成后其长度就是确定的,数组的长度一旦确定就不能修改

(5)可以通过下标或索引的方式调用指定位置的元素

(6)数组名中引用的是这块连续空间的首地址

三、一维数组:

1.一维数组的声明与初始化

静态初始化:数组变量和数组元素同时赋值,此时不需要确定数组的长度
数组类型[] 数组名 = new 数组类型[]{数组元素1,数组元素2,...,数组元素n};
数组类型[] 数组名 = {数组元素1,数组元素2,...,数组元素n};
动态初始化:数组变量和数组元素的赋值分开进行,此时要确定数组的长度
数组类型[] 数组名 = new 数组类型[数组长度];

2.数组元素的调用:

通过脚标的方式获取数组的元素,脚标的范围从0开始,到数组长度-1结束
数组名[脚标];

3.数组的长度:用来描述数组容器的容量大小

可以使用数组变量的length属性表示
数组名.length

 4.遍历数组:

for(int i = 0;i<数组名.length;i++)
{
    数组名[i];
}

5.数组元素的默认初始化值:

(1)整型数组元素的默认初始化值:0

(2)浮点型数组元素的默认初始化值:0.0

(3)字符型数组元素的默认初始化值:'\u0000'

(4)boolean型数组元素的默认初始化值:false

(5)引用数据类型数组元素的默认初始化值:null

6.一维数组的内存解析:

为了提高运算效率,Java虚拟机对空间进行了不同区域的划分,每一片区域都有特定的处理数据方式和内存管理方式

区域名称作用
虚拟机栈存储正在执行的每个Java方法的局部变量表等,存放可知长度的各种基本数据类型、对象引用、方法执行完会自动释放
堆内存存储对象(包括数组对象),new关键字创建的都存放在堆内存
方法区存储已被虚拟机加载的类信息、常量、(静态变量)、即时编译器编译后的代码等数据
本地方法栈当程序中调用了native的本地方法后,本地方法执行期间的内存区域
程序计数器程序计数器是CPU中的寄存器,包含每一个线程下一条要执行的指令地址

数组的内存结构:

四、多维数组:

1.概述:

Java语言里提供了支持多维数组的语法,二维数组可以看成是一维数组array1又作为另一个一维数组array2的元素存在;

2.二维数组的使用:

(1)二维数组的声明与初始化:

静态初始化:数组变量和数组元素同时赋值,此时不需要确定数组的长度
元素类型[][] 数组名 = new 元素类型[][]{{元素1_1,元素1_2,...,元素1_n},{元素2_1,元素2_2,...,元素2_n},...,{元素m_1,元素m_2,...,元素m_n}};
元素类型[][] 数组名 = {{元素1_1,元素1_2,...,元素1_n},{元素2_1,元素2_2,...,元素2_n},...,{元素m_1,元素m_2,...,元素m_n}};
动态初始化:数组变量的赋值和数组元素的赋值分开进行:
元素类型[][] 数组名 = new 元素类型[m][n];
元素类型[][] 数组名 = new 元素类型[m][];

(2)二维数组元素的调用:

调用内层元素:
二维数组名[外层索引][内层索引];
调用内层元素:
二维数组名[外层索引];

(3)二维数组元素的长度:

二维数组元素名.length;
二维数组元素名[外层索引].length;

(4)遍历二维数组:

for(int i = 0;i<二维数组名.length;i++)
{
    for(int j = 0;j<二维数组名[i].length;j++)
       {
            System.out.println(二维数组名[i][j]);
       }
}

(5)二维数组元素的默认初始化值:

元素类型[][] 数组名 = new 元素类型[m][n]
外层元素的默认值:相当于一个一维数组的地址值,默认存储地址值
内层元素的默认值:同一维数组的默认初始化值
元素类型[][] 数组名 = new 元素类型[m][];
外层元素的默认值:null
内层元素的默认值:空指针异常报错

五、数组中常见的算法操作:

1.数值型数组特征值的统计:

1.求最大值:
int max = arr[0]
for(int i =0;i<arr.length;i++)
{
    if(max<arr[i])
      {
        max =arr[i];    
      }
}
2.求最小值:
int min = arr[0]
for(int i =0;i<arr.length;i++)
{
    if(max<arr[i])
      {
        max =arr[i];    
      }
}
3.求和和平均值:
int sum = 0;
for(int i =0;i<arr.length;i++)
{
    sum+=arr[i];
}
int avgValue = sum / arr.length;

2.数组元素的赋值:

杨辉三角:
int[][] yangHui = new int[10][];
for(int i = 0;i<yangHui.length;i++)
{
    yangHui[i] = new int[i+1];
    yangHui[i] = yangHui[i][i] = 1;
    for(int j = 1;j<yangHui[i].length-1;j++)
       {
            yangHui[i][j] = yangHui[i-1][j] + yangHui[i-1][j-1];
       }
}

for(int i =0;i<yangHui.length;i++)
{
    for(int j = 0;j<yangHui[i].length;j++)
       {
            System.out.println(yangHui[i][j]); 
       }
}

3. 数组的反转:

for(int i = 0;i<arr.length/2;i++)
{
    int temp = arr[i];
    arr[i] = arr[arr.length-i-1];
    arr[arr.length - 1 - i] = temp;
}

4.数组的扩容与缩容

数组扩容:
int[] arr = new int[]{1,2,3,4,5};
int[] newArray = new int[arr.length<<1];
for(int i = 0;i<arr.length;i++)
{
    newArray[i] = arr[i];
}
arr = newArray;
数组缩容:
int[] arr = {1,2,3,4,5,6,7};
int deleteIndex = 4;
for(int i = deleteIndex;i<arr.length-1;i++)
{
    arr[i] = arr[i+1];
}
arr[arr.length - 1] = 0;

5.元素的查找:

线性查找:算法简单,但是执行效率低,执行复杂度为O(N)
boolean isFlag = true;
for(int i = 0;i<arr1.length;i++)
{
    if(target == arr1[i])
      {
          System.out.println("Found");
          isFlag = false;
          break;
  
      }
}
if(isFlag)
{
  System.out.println("Not Found");  
}
二分法查找:要求此数组必须是有序的,执行效率高,时间复杂度为O(logN),相对线性查找较为复杂
int[] arr2 = new int[]{1,2,3,4,5,6,7,8};
int target = 5;
int head = 0;
int end = arr2.length - 1;
boolean isFound = false;
while(head <= end){
    int middle = (head + end) / 2;
    if(target == arr2[middle])
    {
        System.out.println("Found");
        isFound = true;
        break;
    }else if(target > arr2[middle])
    {
        head = middle + 1;
    }else
    {
        end = middle - 1;
    }
}
if(!isFound)
{
    System.out.println("Not Found");
}

6.数组元素排序:

(1)概述:假设含有n个记录的序列为(R1,R2,...,Rn),其相应的关键字序列为(K1,K2,...,Kn),将这些记录重新排序为(Ri1,Ri2,...,Rin),使得相应的关键字满足条件Ki1<=Ki2<=...<=Kin,这样的一种操作称为排序,排序的目的是达到快速查找;

(2)衡量排序算法的优劣:

a.时间复杂度:分析关键字的比较次数和记录的移动次数,常见的时间复杂度由小到大依次为O(1)<O(log2n)<O(n)<O(nlog2n)<O(n^2)<...<O(2^n)<O(n!)<O(n^n)

b.空间复杂度:排序算法中需要多少辅助内存;

c.稳定性:若两个记录A和B的关键字相等,但排序后A和B的先后次序保持不变,则称这种排序算法是稳定的;否则是不稳定的

(3)排序算法分类:

a.内部排序:整个排序过程不需要借助于外部存储器,所有排序操作都在内存中完成

b.外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排序过程放在内存中完成,必须借助于外部存储器,最常见的是多路并归排序;

(4)十大内部排序算法:

排序方法时间复杂度(平均)时间复杂度(最坏)时间复杂度(最好)空间复杂度稳定性
插入排序O(n^2)O(n^2)O(n)O(1)稳定
希尔排序O(n^1.3)O(n^2)O(n)O(1)不稳定
选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
堆排序O(nlog2n)O(nlog2n)O(nlog2n)O(1)不稳定
冒泡排序O(n^2)O(n^2)O(n)O(1)稳定
快速排序O(nlog2n)O(n^2)O(nlog2n)O(nlog2n)不稳定
并归排序O(nlog2n)O(nlog2n)O(nlog2n)O(n)稳定
计数排序O(n+k)O(n+k)O(n+k)O(n+k)稳定
桶排序O(n+k)O(n^2)O(n)O(n+k)稳定
基数排序O(n*k)O(n*k)O(n*k)O(n+k)稳定
冒泡排序:
1.比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.这步做完后,最后的元素会是最大的数
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止;
int[] arr = {1,3,5,2,4,6,7,9,8};
for(int j = 0;j<arr.length - 1;j++)
{
    for(int i = 0;i<arr.length - 1 - j;i++)
       {
            if(arr[i]>arr[i+1])
            {
                int temp = arr[i+1];
                arr[i+1] = arr[i];
                arr[i] = temp;
            }

       }
}
快速排序:
1.从数列中挑出一个元素,称为"基准"(pivot);
2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
4.递归的最底部情形,是数列的大小,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的选代(iteration)中它至少会把一个元素摆到它最后的位置去。

 六、Arrays工具类的使用:

java.util.Arrays类即为操作数组的工具类,包含了用来操作数组的各种方法,比如:

1.数组元素拼接:
static String toString(int[] a):字符串表示形式由数组的元素列表组成,括在方括号中。相邻元素用字符', '分隔;
static String toString(Object[] a):字符串表示形式由数组的元素列表组成,括在方括号中。相邻元素用字符', '分隔;
元素将自动调用自己从Object继承的toString方法将对象转为字符串进行拼接,如果没有重写,将返回类型@hash值,如果重写则按重写返回的字符串进行拼接;
2.数组排序:
static void sort(int[] a):将a数组按照从小到大进行排序
static void sort(int[] a, int fromIndex, int toIndex):将a数组的[fromIndex,toIndex)部分按照升序排列
static void sort(Object[] a):根据元素的自然顾序对指定对象数组按升序进行排序
static <T>void sort(T[] a,Comparator<? super T>c):根据指定比较器产生的顺序对指定对象数组进行排序;
3.数组元素的二分查找
static int binarySearch(int[] a, int key)
static int binarySearch(Object[]a,Object key)
要求数组有序,在数组中查找key是否存在,如果存在返回第一次找到的下标,不存在返回负数。
4.数组的复制:
static int[] copyOf(int[] original,int newLength):根据original原数组复制一个长度为newLength的新数组,并返回新数组
static <T> T[] copyOf(T[] original,int newLength):根据original原数组复制一个长度为newLength的新数组并返回新数组
static int[] copyOfRange(int[] original, int from, int to):复制original原数组的[from,to)构成新数组,并返回新数组;
static <T>T[] copyOfRange(T[] original,int from,int to):复制original原数组的[from,to)构成新数组,并返回新数组
5.比较两个数组是否相等
static boolean equals(int[] a,int[] a2):比较两个数组的长度、元素是否完全相同;
static boolean equals(Object[] a,Object[] a2):比较两个数组的长度、元素是否完全相同;
6.填充数组:
static void fill(int[] a,int val):用val值填充整个a数组;
static void fill(Object a, Object val):用val对象填充整个a数组;
static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val值;
static void fill(Object[] a, int fromIndex, int tolndex, Object val):将a数组[fromIndex,toIndex)部分填充为val对象

七、数组使用中常见的异常:

1.数组角标越界异常:ArrayIndexOutOfBoundsException

2.空指针异常:NullPointerExeception

情况1:
int[] arr1 = new int[10];
arr1 = null;
System.out.println(arr1[0]);
情况2:
int[][] a = new int[10][];
System.out.println(a[0][0]);

一旦程序执行中出现了异常,程序就会终止执行,需要针对异常提供的信息修改对应代码,避免异常再次出现;

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值