数组

来源:互联网 发布:苹果 看书软件 编辑:程序博客网 时间:2024/05/29 18:22

    ----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------

数组

1数组的概念

    同一种类型数据的集合。其实数组就是一个容器。运算的时候有很多数据参与运算,那么首先需要做的是什么.不是如何运算而是如何保存这些数据以便于后期的运算,那么数组就是一种用于存储数据的方式,能存数据的地方我们称之为容器,容器里装的东西就是数组的元素, 数组可以装任意类型的数据,虽然可以装任意类型的数据,但是定义好的数组只能装一种元素, 也就是数组一旦定义,那么里边存储的数据类型也就确定了。

2 数组的好处

    存数据和不存数据有什么区别吗?数组的最大好处就是能都给存储进来的元素自动进行编号. 注意编号是从0开始。方便操作这些数据。

3数组的格式

     元素类型[] 数组名 = new 元素类型[元素个数或数组长度];

示例:int[] arr = new int[5]; 

1声明数组变量

为了使用数组必须在程序中声明数组,并指定数组的元素类型

=左半部分:

    先写左边明确了元素类型 是int ,容器使用数组,那么如何来标识数组?.那么用一个特殊的符号[]中括号来表示。想要使用数组是需要给数组起一个名字的,那么我们在这里给这个数组起名字为x .接着跟上等号。

代码体现:  

int [] x 

注意:int x[] 也是一种创建数组的格式。推荐使用int [] x 的形式声明数组。

2创建数组

=右半部分:

要使用一个新的关键字.叫做new。new 用来在内存中产生一个容器实体,数据要存储是需要有空间的,存储很多数据的空间用new 操作符来开辟,new int[3]; 这个3是元素的个数。右边这部分就是在内存中定义了一个真实存在的数组,能存储3个元素。

new int[3] 做了两件事情,首先使用new int[3] 创建了一个数组,然后把这个数组的引用赋值给数组变量x。

 

int [] x=new int[3];

x 是什么类型?

任何一个变量都得有自己的数据类型。注意这个x 不是int 类型的 。int 代表的是容器里边元素的类型。那么x 是数组类型的。

数组是一种单独的数据类型。数据类型分为2大派,分为基本数据类型和引用数据类型。 第二大派是引用数据类型。那么大家现在已经接触到了引用数据类型三种当中的一种。就是数组类型 [] 中括号就代表数组。

4、int[] arr = new int[5];在内存中发生了什么? 

运行任何一个程序,运行的时候都需要在内存中开辟空间.int[] arr = new int[5]; 这个程序在内存中是什么样?这就涉及到了java虚拟机在执行程序时所开辟的空间,那么java开辟启动了多少空间呢?继续学习java的内存结构。

 
1.1.1. 数组的定义 

 

格式1:

元素类型[] 数组名 = new 元素类型[元素个数或数组长度];

示例:int[] arr = new int[5];

      int arr[] =new int[5];

格式2:

元素类型[] 数组名 = new 元素类型[]{元素,元素,……};

int[] arr = new int[]{3,5,1,7};

int[] arr = {3,5,1,7};

 

注意:给数组分配空间时,必须指定数组能够存储的元素个数来确定数组大小。创建数组之后不能修改数组的大小。可以使用length 属性获取数组的大小。

遍历数组

 
1.1.2. 数组初始化 

数组的格式

int[] x = new int[3];

x[0] = 1;

x[1] = 2;

另一种定义:该形式可以直接明确数组的长度,以及数组中元素的内容

int[] x = { 1, 2, 3 };

 

int[] x=new int[]{1,2,3};

 

 

初始化方式1:不使用运算符new

int[] arr = { 1, 2, 3, 4, 5 };

int[] arr2 = new int[] { 1, 2, 3, 4, 5 };

初始化方式2: 

int[] arr3=new int[3];

arr3[0]=1;

arr3[1]=5;

arr3[2]=6;

 

如果数组初始化中不使用运算符new。需要注意:下列写法是错误的。

int[] arr;

arr={1,2,3,4,5};

此时初始化数组,必须将声明,创建,初始化都放在一条语句中个,分开会产生语法错误。

所以只能如下写:

int[] arr={1,2,3,4,5};

 

 
1.1.3. 数组遍历 

数组中有一个属性可以获取到数组中元素的个数,也就是数组的长度. 数组名.length

public static void main(String[] args) {

int[] x = { 1, 2, 3 };

for (int i = 0; i < x.length; i++) {

System.out.println(x[y]);

}

 

 
1.1.4. 数组的常见异常 

一数组角标越界异常:注意:数组的角标从0开始。

public static void main(String[] args) {

int[] x = { 1, 2, 3 };

System.out.println(x[3]);

//java.lang.ArrayIndexOutOfBoundsException

}

 

 

 

二 空指针异常:

public static void main(String[] args) {

int[] x = { 1, 2, 3 };

x = null;

System.out.println(x[1]);

// java.lang.NullPointerException

}

 

数组:

什么时候使用数组:当元素较多时为了方便操作这些数组,会先进行来临时存储,所使用的容器就是数组。

特点:

数组长度是固定的。

 
1.1.5. 数组的常见操作 

1:定义一个遍历数组的函数

2:定义一个求数组和的功能函数

3:定义一个获取数组最大值的功能函数

4:定义一个获取数组最大值角标的功能函数

5:定义一个返回指定数在指定数组中包含的角标的功能函数

6:定义一个可以用于排序int数组的函数

 可以操作 {10,8,7,2,5};

1:冒泡

2:选择

7:定义一个可以将整数数组进行反序的功能函数。

8:二分查找(必须是有序的 ) 

基本操作:

1、获取最值(最大值,最小值)

2、排序(选择排序,冒泡排序)  

3、折半查找(二分查找)

 
1.1.5.1. 获取最值 

1获取最大值,

2获取最小值,

3使用0进行比较的问题(元素全是负数)。定义第三方变量的问题。

public static int getMax(int[] arr) {

int max = 0;

for (int x = 0; x < arr.length; x++) {

if (max < arr[x]) {

max = arr[x];

}

}

return max;

}

 

public static void main(String[] args) {

int[] x = new int[] { 2, 5, 6, 20, 100 };

int max=getMax(x);

System.out.println(max);

}

注意:如果数组中有负数(元素全是负数),还可以吗?

所以:初始化为0,正整数没问题如果是负数。那么就初始化为元素的任意一个元素

public static int getMax(int[] arr) {

int max = arr[0];

for (int x = 0; x < arr.length; x++) {

if (max < arr[x]) {

max = arr[x];

}

}

return max;

}

注意:定义变量时候初始化为0, 其实也是可以的。让变量作为角标就行了。

public static int getMax(int[] arr) {

int max = 0;

for (int x = 0; x < arr.length; x++) {

if (arr[max] < arr[x]) {

max = x;

}

}

return arr[max];

}

 

 
1.1.5.2. 数组的排序 

想要对一个数组排序例如int[] arr={4,5,2,1,7},按照从小到大的顺序(升序)排列。

1、冒泡排序(bubble sort)

   冒泡排序,每次两个相邻的值进行比较,内层循环结束,最后出现最大值

2、选择排序(selection sort)

选择排序先找到数组中最小的数,然后将它放在数组的最前边,然后在剩下的数组找到最小数,将它放在第一个数的后边,以此类推,知道该数组仅剩一个数为止。

 

 

/*

冒泡排序,每次两个相邻的值进行比较,内层循环结束,最后出现最大值。

内层循环 arr.length-1 避免角标越界

         arr.length-x 减少参与比较的数,因为这些数,已经是最大值,排在最后,没有必要参与比较。

*/

public static void bubbleSort(int[] arr){

for(int x=0;x<arr.length;x++){

for(int y=0;y<arr.length-1-x;y++){

if(arr[y]>arr[y+1]){

int temp=0;

temp=arr[y+1];

arr[y+1]=arr[y];

arr[y]=temp;

}

}

}

}

 

/*

选择排序。内循环结束 0角标位出现最小值。只要外层循环的值比内层循环值大,就互换位置。

0角标位的元素,和0角标位以后的每个元素进行比较,只要比他们大就互换,位置,这样可以保证0角标位置值最小。

然后,再进行1角标位置和1角标后的每个元素进行比较。

依次类推,

*/

public static void selectSort(int[] arr){

for(int x=0;x<arr.length-1;x++){

for(int y=x+1;y<arr.length;y++){

if(arr[x]>arr[y]){

int temp=arr[y];

arr[y]=arr[x];

arr[x]=temp;

}

}

}

}

 

 
1.1.5.3. 数组折半查找(二分查找) 

普通的查找适用于小数组或者没有排序的数组中,但是如果数组很大,效率会很低。二分查找效率较高,但是数组要排序。

数组折半查找必须对于有序数组。

本例中使用升序排列。二分查找首先将关键字与数组的中间元素进行比较。

如果关键字小于中间元素,只需要在数组的前一半元素中据需查找关键字。

如果关键字大于中间元素,只需要在数组的后一半元素中继续查找关键字。

如果关键字等于中间元素,则匹配成功查找结束。

所以二分查找的每次比较之后就会排除掉一半的数组元素

定义变量min 和max分别表示数组的头角标和尾角标第一次比较是min是0,max是数组.length-1。并且定义变量mid记录数组的中间元素的角标。mid=(min+max)/2;

重复的比较需要使用循环,使用while即可,控制循环的条件是min<=max 即可。

注意:为什么要用等号(=)如果数组中只有一个元素,这个查找就会漏掉这个元素。

练习:

对数组中的元素进行查找,获取该元素第一次在数组中出现的位置。

public static int getIndex(int[] arr, int key) {

for (int x = 0; x < arr.length; x++) {

if (arr[x] == key) {

return x;

}

}

return -1;

}

折半查找

通过定义变量,记录着头角标min,尾角标max,和中间角标mid,

初始化的变量为min = 0; max = arr.length - 1; mid = (max + min) / 2;

只要头角标小于等于尾角标,意味着还有数字可查。就可以一直进行循环判断和查找。

根据想要查找的key 进行判断,如果该数大于arr[midd] 那么意味着先要查找的数在midd角标的右边,需要重新计算头角标,从midd+1 开始。尾角标不变。

如果 key<arr[midd] 意味着想要查找的数在midd的左边,需要重新计算尾角标。

这样循环。通过if  else if 语句,如果if else if 都不满足,就是既不大于,又不小于,那么就是等于。说明查找的数正对应midd。直接return 就可以了。

 

要考虑没有查找到。通过返回-1 来表示没有找到查找的数。  

 

public static int halfSearch(int[] arr, int key) {

 

int max, min, mid;

min = 0;

max = arr.length - 1;

 

while (min <= max) {

mid = (max + min) / 2;

if (key > arr[mid])

min = mid + 1;

else if (key < arr[mid])

max = mid - 1;

else

return mid;

}

return -1;

}

 
1.1. 内存结构 

Java程序在运行时,需要在内存中的分配空间。为了提高运算效率,有对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。

栈内存

l  用于存储局部变量,当数据使用完,所占空间会自动释放。

堆内存

l  数组和对象,通过new建立的实例都存放在堆内存中。

l  每一个实体都有内存地址值

l  实体中的变量都有默认初始化值

l  实体不在被使用,会在不确定的时间内被垃圾回收器回收

方法区,本地方法区,寄存器

java启动时一共在内存中开辟了5块空间,来进行自己数据的存储如方法区,本地方法区,寄存器,同时还有两个区域栈内存和堆内存。现在我们了解一下栈内存和堆内存。

 

栈内存:

public static void main(String[] args) {

int x = 0;

show();

}

public static void show() {

int x = 10;

System.out.println(x);

}

加载类,main方法进栈,初始化x ,show方法进栈,show出栈,main方法执行完毕.

当在主函数中定义了int x=3主函数运行的时候会在栈内存中开辟一块空间 就是 x=3; 这个区域就属于主函数区域。那么这个变量是在栈内存中的。

那么如果在main函数中调用show函数,show 函数也会在栈内存中开辟空间, show 函数中定义了变量x=3.那么会不会重复呢?是不会重复的 。当show函数一被执行完,,就在栈内存中消失了,所以show中的局部变量也跟着消失了。

局部变量, 定义在方法中的变量,定义在方法参数上变量,定义在for循环的变量全都是局部的。局部变量都是在栈内存中的。

内存为什么划分这么多空间?为什么把内存空间划分那么的细。因为每一片内存空间处理方式不一样。对于栈内存中数据只要用完就会自动释放。但是堆内存不是,这就是数据处理方式不一样。

堆内存:

int [] x=new int[3]; 就和栈内存有很大的不同了.这行代码在内存中是怎样的?

首先 int [] x  在栈内存中开辟了空间 了,记住凡是局部变量都是在栈内存中的,那么局部变量会在栈内存中开辟空间  定义了一个x 。

new 出来的实体都在堆内存里。实体包括数组和对象。

new 就在堆内存中开辟了空间,那么堆中的数据和栈内存中的数据是怎么联系起来的呢.

在栈中的变量 x如何和堆中的内存空间建立联系?

1 堆内存的首地址值(引用).

堆内存的特点.堆内存的每一个实体都有自己的存放位置.内存中都是地址值.用地址来标识数据存放的位置.那么数组在内存中存放的时候总有一个起始位置,这个起始位置用16进制表示(二进制表示太长) 0x0066 那么这个地址就作为数组在堆内存中存放的首地址值.那么用0x0066 标识数组在堆内存的位置的话,只需要0x0066 赋值给x  注意赋值并不是数组,而是数组的首地址.这样一赋完值x就有值了,就叫做x 指向了 这个数组.或者叫x 引用了这个数组..这就是引用数据类型,数组并没有存到x 变量中去,只是把首地址值赋给了x 变量.

这就是堆内存的第一个特点,堆内存中的每一个数组都有一个首地址值.就像教室一样,教室上边有门牌号码.。我告诉你门牌号,就可以找到这个房间。

 

2  堆内存中的变量都有默认初始化值。

public static void main(String[] args) {

int[] x = new int[3];

System.out.println(x[0]); // 0

System.out.println(x[1]); // 0

System.out.println(x[2]); // 0

}

并没有往数组中存入数据,只是确定了数组的存放元素的个数。那么仍旧有默认的初始化值。

堆内存的第二个特性.堆内存的实体是用于封装数据的.而堆内存中的数据都有默认初始化值.在不赋值的情况下都有默认值。

int 型默认是0  double是0.0  float是0.0f   如果是 boolean类型的默认是false。

 

public static void main(String[] args) {

int[] x = new int[3];

x=null;

}

 

如果不需要让x 指向具体的值,怎么办?

可以使用常量中的null ,只有引用数据类型才可以使用null   

x=null ;是指 x不在指向具体的值了,不在指向数组的首地址值。那么跟数组就没有关系了。没关系后数组在堆内存中就没人使用了。当一个实体在堆内存中没有任何引用指向它的时候,我们就视它为垃圾。垃圾不会立刻被jvm 在内存中清除掉。而是不定时的时间内jvm 启动一个垃圾回收机制。将数组实体在堆内存中清除。

 

总结:

栈内存和堆内存是有很大的不同.

栈内存中的数据是自动释放,堆内存是垃圾回收.

 

练习:

public static void main(String[] args) {

int[] x = new int[3];

int[] y = x;

y[1] = 80;

x = null;

}

 

 

 

第一行 声明并创建了一个数组x x持有数组在堆内存中的引用.

第二行声明了数组y, 并把x 持有的引用赋值给了y. 所以y和x 也指向同一个数组

第三行 y[1]=80 ;数组中1角标位的值变为了80 。

注意了:两个引用指向了同一个数组。y 把数组的指定角标位的值改变了,那么 x 回来访问该角标的值的时候,是改变后的值。

第四 给x重新赋值为null. x=null 的时候x 不再指向数组,y 仍然指向数组。仍然有引用指向数组.

 

    ----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------ 

 

0 0