Java学习笔记——数组

来源:互联网 发布:软件系统推广验收 编辑:程序博客网 时间:2024/05/28 04:53

简介

Java和许多高级语言都提供了一种称作数组的数据结构,可以用它来存储一个元素个数固定且元素类型相同的有序集。
单个的数组变量可以引用一个大的数据集合。

数组基础知识

数组是用来存储数据的集合,通常可以把数组看作一个存储具有相同类型的变量集合。
一旦数组被创建,它的大小是固定的。使用一个数组引用变量,通过下标来访问数组中的元素。

声明数组变量

为了在程序中使用数组,必须声明一个引用数组的变量,并指明数组的元素类型。
声明数组变量的语法:

elementType[] arrayRefVar;(元素类型[] 数组引用变量;)

elementType可以是任意数据类型,但是数组中所有的元素都必须具有相同的数据类型。
注意: 也可以用 elementType arratRefVar[] 声明数组变量。

创建数组

不同于基本数据类型的声明,声明一个数组变量时并不在内存中给数组分配任何空间。它只是创建一个对数组的引用的存储位置。如果变量不包含对数组的引用,那么这个变量的值为null。除非数组已经被创建,否则不能给它分配任何元素。
声明数组变量后,可以使用下面的语法用new操作符创建数组:

arratRefVar = new elementType[arratSize];

声明一个数组变量、创建数组、然后将数组引用赋值给变量这三个步骤可以合并为一个步骤:

elementType[] arrayRefVar = new elementType[arraySize];或elementType arrayRefVar[] = new elementType[arraySize];

注意: 一个数组变量看起来似乎是存储了一个数组,但实际上它存储的是指向数组的引用。

数组的大小和默认值

当给数组分配空间时必须指定该数组能够存储的元素个数,从而确定数组大小。创建数组之后,就不能再修改它的大小。可以使用arrayRefVar.length得到数组的大小。
当创建数组后,它的元素被赋予默认值,数值型基本数据类型的默认值为0,char型的默认值为‘\u0000’,boolean型的默认值为false。

访问数组元素

数组元素可以用过下标访问。数组下标是基于0的,即其范围从0开始到arrayRefVar.length - 1结束。
数组中的每个元素都可以使用下面的语法表示,称为下标变量:

arrayRefVar[index];

注意: 一些语言使用圆括号引用数组元素,例如arrayRefVar(9)。而Java语言使用方括号,例如arrayRefVar[9]。

创建数组后,下标变量与正常变量的使用方法相同。例如:下面代码将 myList[0] 和 myList[1] 的值相加赋给 myList[2]。

myList[2] = myList[0] + myList[1];

数组初始化语法

Java有一个简捷的标记,称作数组初始化语法,它使用下面的语法将声明数组、创建数组和初始化数组结合到一条语句中:

elementType[] arratRefVar = {value0, value1, value2, ..., valuek};

注意: 数组初始化语法中不使用操作符new。使用数组初始化语法时,必须将声明、创建和初始化数组都放在一条语句中。将它们分开会产生语法错误。因此,下面语句是错误的:

double[] myList;myList = {1.9, 2.9, 3, 4};

处理数组

处理数组时,经常会用到for循环,理由如下:
数组中所有元素都是同一类型的。可以使用循环以同样的方式反复处理这些元素。
由于数组的大小是已知的,所以很自然地就使用for循环。

假设创建如下数组:

double[] myList = new double[10];

下面是一些处理数组的例子:

① 使用输入值初始化数组

Scanner input = new Scanner(System.in);System.out.println("Enter " + myList.length + " value: ");for (int i = 0; i < myList.length; i++)     myList[i] = input.nextDouble();

② 使用随机数初始化数组

for(int i = 0; i < myList.length; i++) {    myList[i] = Math.random() * 100;}

③ 显示数组

for(int i = 0; i < myList.length; i++) {    System.out.prin(myList[i] + " ");}

注意: 对于char[]类型的数组,可以使用一条打印语句打印。例如下面的代码显示Dallas:

char[] city = {'D', 'a', 'l', 'l', 'a', 's'};System.out.println(city);

④ 对所有元素求和

double total = 0;for(int i = 0; i < myList.length; i++) {    total += myList[i];}

⑤ 找出最大元素

double max = myList[0];for(int i = 0; i < myList.length; i++) {    if(myList[i] > max) max = myList[i];}

⑥ 找出最大元素的最小下标值

double max = myList[0];int indexOfMax = 0;for(int i = 1; i < myList.length; i++) {    if(myList[i] > max) {        max = myList[i];        indexOfMax = i;    }}

⑦ 随机打乱

for(int i = myList.length - 1; i > 0; i--) {    int j = (int)(Math.random() * (i + 1));    double temp = myList[i];    myList[i] = myList[j];    myList[j] = temp;}

⑧ 移动元素

double temp = myList[0];for(int i = 1; i < myList.length; i++) {    myList[i - 1] = myList[i];}myList[myList.length - 1] = temp;

⑨ 简化编码

String[] months = {"January", "February", ..., "December"};System.out.print("Enter a month number(1 to 12): ");int monthNumber = input.nextInt();System.out.println("The month is " + months[monthNumber - 1]);

如果不使用 month 数组,则需要使用一个很长的多分支if-else语句来确定月份名称:

if(monthNumber == 1)    System.out.println("The month is January");else if(monthNumber == 2)    System.out.println("The month is February");...else     System.out.println("The month is December");

foreach循环

Java支持一个简便的for循环,称为foreach循环,即不使用下标变量就可以顺序地遍历整个数组。例如:

for (double e : myList) {    System.out.println(e);}

此代码可读作“对myList中每个元素e进行以下操作”。
注意: 变量e必须声明为与myList中元素相同的数据类型。

通常,foreach循环的语法为:

for(elementType element : arrayRefVar) {    //执行语句}

注意: 当需要以其他顺序遍历数组或改变数组中的元素时,还是需要使用下标变量。

注意: 越界访问数组是经常出现的程序设计错误,它会抛出一个运行错误ArrayIndexOutOfBoundException。为了避免错误发生,使用时应确保所使用的下标不超过arrayRefVar.length - 1。
经常会出现错误地使用下标1引用数组的第一个元素,但实际上第一个元素的下标应该是0。这称为下标过1错误。它是循环中该使用 < 的地方误用 <= 时发生的错误。例如:

for(int i = 0; i <= list.length; i++)     System.out.println(list[i]);

应该把 <= 替换为 < 。

实例学习:分析数字

编写一个程序,找到大于所有项平均值的那些项。

public class AnalyzeNumbers {    public static void main(String[] args) {        Scanner input = new Scanner(System.in);        System.out.println("Enter the number of items: ");        int n = input.nextInt();        double[] numbers = new double[n];        double sum = 0;        //输入数字        System.out.print("Enter the number: ");        for(int i = 0; i < n; i++) {            numbers[i] = input.nextDouble();            sum += numbers[i];        }        //计算平均值        doubel average = sum / n;        //记录大于平均值的数的个数        int count = 0;        for(int i = 0; i < n; i++) {            if(number[i] > average) {                count++;            }        }        System.out.println("Average is " + average);        System.out.println("Number of elements above the average is " + count);    }}

实例学习:一副扑克

编写一个程序,从一副扑克中随机选出4张牌

public class DeckOfCards {    public static void main(String[] args) {        int[] deck = new int[52];        String[] suits = {"Spades", "Hearts", "Diamonds", "Clubs"};        String[] ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};        //初始化deck,为deck的元素赋值:0到51        for(int i = 0; i < deck.length; i++)            deck[i] = i;        //洗牌        for(int i = 0; i < deck.length; i++) {            int index = (int)(Math.random() * deck.length);            int temp = deck[i];            deck[i] = deck[index];            deck[index] = temp;        }        //显示前四张扑克        for(int i = 0; i < 4; i++) {            String suit = suits[deck[i] / 13];            String rank = ranks[deck[i] % 13];            System.out.println("Card number " + deck[i] + ": " + rank + " of " + suit);        }    }}//输出://Card number 6: 7 of Spades//Card number 48: 10 of Clubs//Card number 11: Queen of Spades//Card number 24: Queen of Hearts

数组的复制

要将一个数组中的类容复制到另一个数组中,需要将数组的米格元素复制到另外一个数组中。

在程序中经常需要复制一个数组或数组的一部分。这种情况下可以选择使用赋值语句(=):

list2 = list1;

这条语句并不是把 list1 引用的数组内容复制给 list2, 而是将 list1 的引用赋值给 list2。这条语句之后,list1 和 list2 都指向同一个数组。

在Java中,赋值语句可以复制基本数据类型的变量,但不能复制数组。将一个数组变量赋值给另一个数组变量,实际上是将一个数组的引用复制给另一个变量,使两个变量都指向相同内存地址。

复制数组的三个方法:
① 使用循环语句,逐个元素进行复制操作。
② 使用 System 类中的静态方法 arraycopy。
③ 使用 clone 方法复制数组。

可以使用循环将源数组中的每个元素复制到目标数组中的对应元素。例如:

int[] sourceArray = {2, 3, 4, 5};int[] targetArray = new int[sourceArray.length];for(int i = 0; i < sourceArray.length; i++) {    targetArray[i] = sourceArray[i];}

另一种方法是使用 java.lang.System 类的 arraycopy 方法复制数组,而不是使用循环。arraycopy 语法如下:

arraycopy(sourceArray, srcPos, targetArray, tarPos, length);

其中,参数 srcPos 和 tarPos 分别表示在源数组 sourceArray 和目标数组 targetArray 中的起始位置。从 sourceArray 复制到 targetArray 中的元素个数由参数 length 指定。所以,可以改写上述循环:

System.arraycopy(sourceArray, 0, targetArray, 0, sourceArray.length);

arraycopy 方法没有给目标数组分配内存空间。复制前必须创建目标数组以及为它分配内存空间。复制完成后,sourceArray 和 targetArray 具有相同内容,但占有独立的内存空间。

注意: arraycopy 方法违反了 Java 命名习惯。根据命名习惯,该方法应该命名为 arrayCopy。

将数组传递给方法

当将一个数组传递给方法时,数组的引用被传递给方法。

正如给方法传递基本数据类型的值一样,可以给方法传递数组。例:

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

可以通过传递一个数组调用上面的方法。例如:

printArray(new int[]{3, 1, 2, 6, 4, 2});

注意: 前面的语句使用下述语法创建数组:

new elementType[] {value0, value1, ..., valuek};

该数组没有显式地引用变量,这样的数组被称为匿名数组。

Java使用按值传递的方式将实参传递给方法。传递基本数据类型变量的值与传递数组值有很大的不同。
1. 对于剧本数据类型参数,传递的是实参的值
2. 对于数组类型参数,参数值是数组的引用,给方法传递的是这个引用。从语义上来讲,最好的描述就是参数传递的是共享信息,即方法中的数组和传递的数组是一样的。所以,如果改变方法中的数组,将会看到方法外的数组也发生了变化。

public class Test {    public static void main(String[] args) {        int x = 1;        int[] y = new int[10];        m[x, y];        System.out.println("x is " + x);        System.out.println("y[0] is " + y[0]);    }    public static void m(int number, int[] numbers) {        number = 1001;        numbers[0] = 5555;    }}//输出//x is 1//y[0] is 5555

注意: 数组在Java中是对象。JVM将对象存储在一个称作堆的内存区域中,堆用于动态内存分配。

从方法中返回数组

当从方法中返回一个数组时,数组的引用被返回。
可以在调用方法时向方法传递一个数组。方法也可以返回一个数组。例:

public static int[] revers(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;}

可变长参数列表

具有同样类型的可变长度的参数可以传递给方法,并将作为数组对待。可以把类型相同但个数可变的参数传递给方法。方法中的声明如下:

typeName... parameterName

在方法声明中,指定类型后紧跟着省略号(…)。只能给方法中指定一个可变长参数,同时该参数必须是最后一个参数。任何常规参数必须在它之前。
Java 将可变长参数作为数组对待。可以将一个数组或数目可变的参数传递给可变长参数。

public class VarArgsDemo {    public static void main(String[] args) {        printMax(34, 3, 3, 2, 56);        printMax(new double[]{1, 2, 3, 4});    }    public static void printMax(double... numbers) {        if(numbers.length == 0) {            System.out.println("No argument passed");            return;        }        double resule = numbers[0];        for(int i = 1; i < numbers.length; i++)            if(numbers[i] > result)                result = numbers[i];        System.out.println("The max value is " + result);    }}

数组查找

查找是在数组中寻找特定元素的过程,查找是计算机程序设计中经常要完成的任务。有很多用于查找的算法和数据结构,经常使用的有:线性查找和二分查找。

线性查找

线性查找法将要查找的关键字 key 与数组中的元素逐个进行比对。这个过程持续到在列表中找到与关键字匹配的元素,或者查完列表也没有找到关键字为止。

public class LinearSeach {    public static int linearSearch(int[] list, int key) {        for(int i = 0; i < list.length; i++) {            if(key == list[i])                return i;        }    }}

线性查找法把关键字和数组中的每个元素进行比较。数组中的元素可以按任意顺序排列。如果关键字存在,那么在找到关键字之前,这种算法必须与数组中一半的元素进行比较。由于线性查找法的执行时间随着数组元素个数的增长而线性增长,所以对于大数组而言,线性查找法的效率不高。

二分查找法

二分查找法是另一种常见的对数值列表的查找方法。使用二分查找法的前提条件是数组中的元素必须已经排序完成。
二分查找法首先将关键字与数组的中间元素进行比较,考虑三种情况:
① 如果关键字小于中间元素,只需要在数组的前一半元素中继续查找。
② 如果关键字和中间元素相等,则匹配成功,查找结束。
③ 如果关键字大于中间元素,只需要在数组的后一半元素中继续查找关键字。
显然,二分法在每次比较之后就排除一半的数组元素。因此,对于一个有 1024(2^10) 个元素的数组,在最坏情况下,二分法只需要比较11次,而线性查找则需要1023次。

public class BinarySearch {    public static int binarySearch(int[] list, int key) {        int low = 0;        int high = list.length - 1;        while (high >= low) {            int mid = (low + high) / 2;        if(key < list[mid])            high = mid - 1;        else if(key == list[mid])            return mid;        else            low = mid + 1;        }        return -low - 1;    }}

注意: 线性查找法适用于在较小的数组或没有排序的数组中查找,但是对大数组而言效率不高。二分查找法的效率较高,但它要求数组已经排好序。

数组排序

如同查找一样,排序是计算机编程中非常普遍的一个任务。对于排序已经开发出很多不同的算法。

选择排序

假设要按升序排列一个数组。选择排序法先找到数列中最小的数,然后将它和第一个元素交换。接下来,在剩下的数中找到最小数,将它和第二个元素交换,直到数列剩下一个数为止。

public class SelectionSort {    public static void selectionSort(double[] list) {        for (int i = 0; i < list.length - 1; i++) {            double currentMin = list[i];            int currentMinIndex = i;            for(int j = i + 1; j < list.length; j++) {                if(currentMin > list[j]) {                    currentMin = list[j];                    currentMinIndex = j;                }            }            if(currentMinIndex != i) {                list[currentMinIndex] = list[i];                list[i] = currentMin;            }        }    }}
原创粉丝点击