07-一維數(shù)組
-
7.1 引言
- 單個(gè)的數(shù)組變量可以引用一個(gè)大的數(shù)據(jù)集合。
-
7.2 數(shù)組的基礎(chǔ)知識(shí)
一旦數(shù)組被創(chuàng)建,他的大小是固定的。使用一個(gè)數(shù)組引用變量和下標(biāo)來訪問數(shù)組中的元素。
- 7.2.1 聲明數(shù)組變量
- 為了在程序中使用數(shù)組,必須聲明一個(gè)引用數(shù)組的變量,并指明數(shù)組的元素類型。下賣弄是聲明數(shù)組變量的語法:
elementType[] arrayRefVar; //或者 elementType arrayRefVar[];//是允許這樣的,但是不是最好的方式 - elementType可以是任意數(shù)據(jù)類型,但是數(shù)組中所有的元素都必須具有相同的數(shù)據(jù)類型。
- 也可以用elementType arrayRefVar[]聲明數(shù)組變量。這種來自c/c++語言的風(fēng)格被Java采納以適用于c/c++程序員。推薦使用elementType[] arrayRefVar。
- 為了在程序中使用數(shù)組,必須聲明一個(gè)引用數(shù)組的變量,并指明數(shù)組的元素類型。下賣弄是聲明數(shù)組變量的語法:
- 7.2.2 創(chuàng)建數(shù)組
- 不同于聲明基本數(shù)據(jù)類型變量,聲明一個(gè)數(shù)組變量時(shí)并不給數(shù)組分配任何內(nèi)存空間。它只是創(chuàng)建一個(gè)對(duì)數(shù)組的引用的存儲(chǔ)位置。如果變量不包含對(duì)數(shù)組的引用,那么這個(gè)變量的值為null。除非數(shù)組已經(jīng)被創(chuàng)建,否則不能給他分配任何元素。聲明數(shù)組變量之后,可以使用下面的語法用new操作符創(chuàng)建數(shù)組,并且將它的引用賦給一個(gè)變量:
arrayRefVar = new elementType[arraySize]; - 這條語句做了兩件事:
- 1、使用new elementType[arraySize]創(chuàng)建了一個(gè)數(shù)組;
- 2、把這個(gè)新創(chuàng)建的數(shù)組的引用賦值給變量arraySize。
- 聲明一個(gè)數(shù)組變量、創(chuàng)建數(shù)組、將數(shù)組引用賦值給變量這三個(gè)步驟可以合并在一條語句里。
elementType[] arrayRefVar = new elementType[arraySize]; //或者 elementType arrayRefVar[] = new elementType[arraySize]; - 一個(gè)數(shù)組變量看起來似乎是存儲(chǔ)了一個(gè)數(shù)組,但實(shí)際上他存儲(chǔ)的是指向數(shù)組的引用。嚴(yán)格的講,一個(gè)數(shù)組變量和一個(gè)數(shù)組是不同的,但多數(shù)情況下他們的差別是可以忽略的。因此,為了簡(jiǎn)化,通常??梢哉fmyList是一個(gè)數(shù)組,而不用更長的陳述:myList是一個(gè)含有double型元素?cái)?shù)組的引用變量。
- 不同于聲明基本數(shù)據(jù)類型變量,聲明一個(gè)數(shù)組變量時(shí)并不給數(shù)組分配任何內(nèi)存空間。它只是創(chuàng)建一個(gè)對(duì)數(shù)組的引用的存儲(chǔ)位置。如果變量不包含對(duì)數(shù)組的引用,那么這個(gè)變量的值為null。除非數(shù)組已經(jīng)被創(chuàng)建,否則不能給他分配任何元素。聲明數(shù)組變量之后,可以使用下面的語法用new操作符創(chuàng)建數(shù)組,并且將它的引用賦給一個(gè)變量:
- 7.2.3 數(shù)組大小和默認(rèn)值
- 當(dāng)給數(shù)組分配空間時(shí),必須指定該數(shù)組能夠存儲(chǔ)的元素個(gè)數(shù),從而確定數(shù)組大小。創(chuàng)建數(shù)組之后就不能再修改它的大小了。可以使用arrayRefVar.length得到數(shù)組的大小。
- 當(dāng)創(chuàng)建數(shù)組后,他的元素唄賦予默認(rèn)值,數(shù)值型基本數(shù)據(jù)類型的默認(rèn)值為0,char型的默認(rèn)值為‘\u0000’,boolean型的默認(rèn)值為false。
- 7.2.4 訪問數(shù)組元素
- 數(shù)組元素可以通過下標(biāo)訪問。數(shù)組下標(biāo)是基于0的,也就是說,其范圍從0開始到arrayRefVar.length-1結(jié)束。數(shù)組中的每個(gè)元素都可以使用下面的語法表示,稱為下標(biāo)變量:
arrayRefVar[index];
- 數(shù)組元素可以通過下標(biāo)訪問。數(shù)組下標(biāo)是基于0的,也就是說,其范圍從0開始到arrayRefVar.length-1結(jié)束。數(shù)組中的每個(gè)元素都可以使用下面的語法表示,稱為下標(biāo)變量:
- 7.2.5 數(shù)組初始化簡(jiǎn)寫方式
- Java有一個(gè)簡(jiǎn)捷的標(biāo)記,稱作數(shù)組初始化簡(jiǎn)寫方式,他使用下面的語法將聲明數(shù)組、創(chuàng)建數(shù)組和初始化數(shù)組結(jié)合到一條語句中:
elementType[] arrayRefVar = {value0,value1,...,valuek}; - 數(shù)組初始化簡(jiǎn)寫方式中不使用操作符new。使用數(shù)組初始化簡(jiǎn)寫方式時(shí),必須將聲明、創(chuàng)建和初始化數(shù)組都放在一條語句中。
- Java有一個(gè)簡(jiǎn)捷的標(biāo)記,稱作數(shù)組初始化簡(jiǎn)寫方式,他使用下面的語法將聲明數(shù)組、創(chuàng)建數(shù)組和初始化數(shù)組結(jié)合到一條語句中:
- 7.2.6 處理數(shù)組
- 處理數(shù)組元素時(shí),經(jīng)常會(huì)用到for循環(huán),理由如下:
- 數(shù)組中所有元素都是同一類型的。可以使用循環(huán)以同樣的方式反復(fù)處理這些元素。
- 由于數(shù)組的大小是已知的,所以很自然的就使用for循環(huán)。
- 1、使用輸入值初始化數(shù)組
double[] myList = new double[4]; java.util.Scanner input = new java.util.Scanner(System.in); System.out.print("Enter " + myList.length + " values: "); for (int i = 0;i < myList.length;i++) myList[i] = input.nextDouble(); - 2、使用隨機(jī)數(shù)初始化數(shù)組
for (int i = 0;i < myList.length;i++){ myList[i] = Math.random() * 100; } - 3、顯示數(shù)組
char[] city = {'D','a','l','l','a','s'}; System.out.println(city); - 4、對(duì)所有元素求和
double total = 0; for (int i = 0;i < myList.length;i++){ total += myList[i]; } - 5、找出最大元素
double max = myList[0]; for (int i = 0;i < myList.length;i++){ if (myList[i] > max)max = myList[i]; } - 6、找出最大元素的最小下標(biāo)值
double max = myList[0]; int indexOfMax = 0; for (int i = 1;i < myList.length;i++){ max = myList[i]; indexOfMax = 1; } - 7、隨機(jī)打亂
for (int i = 0;i < myList.length - 1;i++){ int j = (int)(Math.random() * myList.length); double temp = myList[i]; myList[i] = myList[j]; myList[j] = temp; } - 8、移動(dòng)元素
double temp = myList[0]; for (int i = 1;i < myList.length;i++){ myList[i - 1] = myList[i]; } myList[myList.length - 1] = temp; - 9、簡(jiǎn)化編碼
String[] months = {"January","Februry",....,"December"}; System.out.print("Enter a month number (1 to 12): "); int monthNumber = input.nextInt(); System.out.println("The month is " + months[monthNumber - 1]);
- 處理數(shù)組元素時(shí),經(jīng)常會(huì)用到for循環(huán),理由如下:
- 7.2.7 foreach循環(huán)
- Java支持一個(gè)簡(jiǎn)便的for循環(huán),稱為foreach循環(huán),即不使用下標(biāo)變量就可以順序的遍歷整個(gè)數(shù)組。下面的代碼就可以顯示數(shù)組myList的所有元素:
for(double e : myList){ Syetem.out.println(e) } - foreachde的語法是:
for(elementType element: arrayRefVar){ //Process the element }
- Java支持一個(gè)簡(jiǎn)便的for循環(huán),稱為foreach循環(huán),即不使用下標(biāo)變量就可以順序的遍歷整個(gè)數(shù)組。下面的代碼就可以顯示數(shù)組myList的所有元素:
- 7.2.1 聲明數(shù)組變量
-
7.3 示例學(xué)習(xí):分析數(shù)字
- 編寫一個(gè)程序,找到大于平均值的項(xiàng)的數(shù)目。
package chapter06; public class AnalyzeNumbers { public static void main(String[] args){ java.util.Scanner input = new java.util.Scanner(System.in); System.out.print("Enter the number of items: "); int n = input.nextInt(); double[] numbers = new double[n]; double sum = 0; System.out.print("Enter the numbers : "); for (int i = 0;i < n;i++){ numbers[i] = input.nextDouble(); sum += numbers[i]; } double average = sum / n; int count = 0; for (int i = 0;i < n;i++) if (numbers[i] > average) count++; System.out.println("Average is " + average); System.out.println("Number of elements above the average is " + count); } }
- 編寫一個(gè)程序,找到大于平均值的項(xiàng)的數(shù)目。
-
7.4 示例學(xué)習(xí):一副牌
package chapter06; public class DeckOfCards { public static void main(String[] args){ int[] deck = new int[52]; String[] suits = {"Spads","Hearts","Diamonds","clubs"}; String[] ranks = {"Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King"}; 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); } } } -
7.5 復(fù)制數(shù)組
- 要將一個(gè)數(shù)組中的內(nèi)容復(fù)制到另外一個(gè)數(shù)組中,需要將數(shù)組的每個(gè)元素復(fù)制到另外一個(gè)數(shù)組中。
list2 = list1 - 上面的語句并不能將list1引用的數(shù)組內(nèi)容復(fù)制到list2,而只是將list1的引用值復(fù)制給了list2.在這條語句之后,list1和list2都指向同一個(gè)數(shù)組。list2原先所引用的數(shù)組不能再引用,它就變成了垃圾,會(huì)被Java虛擬機(jī)自動(dòng)收回(這個(gè)過程稱為垃圾回收)。
- 復(fù)制數(shù)組有三種方法:
- 1、使用循環(huán)語句逐個(gè)的賦值數(shù)組的元素;
- 2、使用System類中的靜態(tài)方法arraycopy;
- arraycopy的語法是:
arraycopy(sourceArray,srcPos,targeArray,tarPos,length); - 參數(shù)srcPos和tarPos分別表示在源數(shù)組sourceArray和目標(biāo)數(shù)組targetArray中的起始位置。從sourceArray復(fù)制到targetArray中的元素個(gè)數(shù)由參數(shù)length指定。
- arraycopy方法沒有給目標(biāo)數(shù)組分配內(nèi)存空間。復(fù)制前必須創(chuàng)建目標(biāo)數(shù)組以及分配給他的內(nèi)存空間。復(fù)制完成后,sourceArray和targetArray具有相同的內(nèi)容,但占有獨(dú)立的內(nèi)存空間。
- arraycopy的語法是:
- 3、使用clone方法賦值數(shù)組。
- 要將一個(gè)數(shù)組中的內(nèi)容復(fù)制到另外一個(gè)數(shù)組中,需要將數(shù)組的每個(gè)元素復(fù)制到另外一個(gè)數(shù)組中。
-
7.6 將數(shù)組傳遞給方法
- 當(dāng)一個(gè)數(shù)組傳遞給方法時(shí),數(shù)組的引用被傳給方法。
- 和方法傳遞基本數(shù)據(jù)類型一樣,也可以給方法傳遞數(shù)組。
public static void printArray(int[] array){ for(int i = 0;i < array.length;i++){ System.out.print(array[i] + " "); } } - 使用下述語法創(chuàng)建數(shù)組:
new elementType[]{value0,value1,...,valuek}; - 該數(shù)組沒有顯式的引用變量,這樣的數(shù)組稱為匿名函數(shù)。
- Java使用按值傳遞的方式將實(shí)參傳遞給方法。傳遞劇本數(shù)據(jù)類型變量的值與傳遞數(shù)組值有很大的不同:
- 對(duì)于基本數(shù)據(jù)類型參數(shù),傳遞的是實(shí)參的值;
- 對(duì)于數(shù)組類型參數(shù),參數(shù)值是數(shù)組的引用,給方法傳遞的是這個(gè)引用。從語義上來講,最好的描述為傳遞共享信息,即方法中的數(shù)組和傳遞的數(shù)組是一樣的。因此,如果改變方法中的數(shù)組,將會(huì)看到方法外的數(shù)組也改變了。
package chapter06; public class TestPassArray { public static void main(String[] args){ int[] a = {1,2}; System.out.println("Before invoking swap"); System.out.println("array is {" + a[0] + ", " + a[1] + "}"); swap(a[0],a[1]); System.out.println("After invoking swap"); System.out.println("array is {" + a[0] + ", " + a[1] + "}"); } public static void swap(int n1,int n2){ int temp = n1; n1 = n2; n2 = temp; } public static void swapFirstTwoInArray(int[] array){ int temp = array[0]; array[0] = array[1]; array[1] = temp; } }
-
7.7 方法返回?cái)?shù)組
- 當(dāng)方法返回一個(gè)數(shù)組時(shí),數(shù)組的引用被返回。
-
7.8 示例學(xué)習(xí):統(tǒng)計(jì)每個(gè)字母出現(xiàn)的次數(shù)
package chapter06; public class CountLettersInArray { public static void main(String[] args){ char[] chars = createArray(); System.out.println("The lowercase letters are: "); displayArray(chars); int[] counts = countLetters(chars); System.out.println(); System.out.println("The occurrences of each letter are: "); displayCounts(counts); } public static char[] createArray(){ char[] chars = new char[100]; for (int i = 0;i < chars.length;i++) chars[i] = RandomCharacter.getRandomLowerCaseLetter(); return chars; } public static void displayArray(char[] chars){ for (int i = 0;i < chars.length;i++){ if ((i + 1) % 20 == 0) System.out.println(chars[i]); else System.out.println(chars[i] + " "); } } public static int[] countLetters(char[] chars){ int[] counts = new int[26]; for (int i = 0;i < chars.length;i++) counts[chars[i] - 'a']++; return counts; } public static void displayCounts(int[] counts){ for (int i = 0;i < counts.length;i++){ if ((i + 1) % 10 == 0) System.out.println(counts[i] + " " + (char)(i + 'a')); else System.out.println(counts[i] + " " + (char)(i + 'a') + " "); } } } -
7.9 可變長參數(shù)列表
- 具有同樣類型的數(shù)目可變的參數(shù)可以傳遞給方法,并將作為數(shù)組對(duì)待。方法中的參數(shù)聲明如下:
typeName...patameterName(類型名...參數(shù)名) - 在方法聲明中,指定類型后緊跟著省略號(hào)(...)。只能個(gè)方法中指定一個(gè)可變長參數(shù),同時(shí)該參數(shù)必須是最后一個(gè)參數(shù)。任何常規(guī)參數(shù)必須在他之前。
- Java將可變長參數(shù)當(dāng)成數(shù)組對(duì)待。
package chapter06; public class VarArgsDemo { public static void main(String[] args){ } public static void printMax(double...numbers){ if (numbers.length == 0){ System.out.println("No argument passed"); return; } double result = 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); } }
- 具有同樣類型的數(shù)目可變的參數(shù)可以傳遞給方法,并將作為數(shù)組對(duì)待。方法中的參數(shù)聲明如下:
-
7.10 數(shù)組的查找
- 7.10.1 線性查找法
package chapter06; public class LineearSearch { public static int linearSearch(int[] list,int key){ for (int i = 0;i < list.length;i++){ if (key == list[i]) return i; } return -1; } } - 7.10.2 二分查找法
package chapter06; 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; } } - 二分查找法的前提是列表必須以升序排好序了。
- 7.10.1 線性查找法
-
7.11 數(shù)組的排序
package chapter06; public class SelectionSort { public static void selectiongSort(double[] list){ for (int i = 0;i < list.length;i++){ double currentMin = list[i]; int currentMinIndex = 1; for (int j = i + 1;j < list.length;j++){ if (currentMin > list[j]){ currentMin = list[j]; currentMinIndex = j; } } if (currentMin != 1){ list[currentMinIndex] =list[i]; list[i] = currentMin; } } } } -
7.12 Arrays類
- java.util.Arrays類包含一些使用的方法用于常見的數(shù)組操作,比如排序和查找。
- 可以使用sort或者parrallelSort方法對(duì)整個(gè)數(shù)組或部分?jǐn)?shù)組進(jìn)行排序。
- 可以調(diào)用sort(number)對(duì)整個(gè)數(shù)組numbers排序??梢哉{(diào)用sort(chars,1,3)對(duì)從chars[1]到chars[3-1]的部分?jǐn)?shù)組進(jìn)行排序。如果你的計(jì)算機(jī)有多個(gè)處理器,那么parallelSort將更加高效。
double[] numbers = {6.0,4.4,1.9,2.9,3.4,3.5}; java.util.Arrays.sort(numbers); java.util.Arrays.parallelSort(numbers); char[] chars = {'a','A','4','F','D','P'}; java.util.Arrays.sort(chars,1,3); java.util.Arrays.parallelSort(chars,1,3); - 可以采用二分查找法(binarySearch方法)在數(shù)組中查找關(guān)鍵字。如果數(shù)組中不存在關(guān)鍵字,方法返回-(insertIndex+1)。
int[] list = {2,4,7,10,11,45,50,59,60,66,69,70,79}; System.out.println("1. Index is " + java.util.Arrays.binarySearch(list,11)); System.out.println("2. Index is " + java.util.Arrays.binarySearch(list,12)); char[] chars1 = {'a','c','g','x','y','z'}; System.out.println("3.Index is " + java.util.Arrays.binarySearch(chars,'a')); System.out.println("4.Index is " + java.util.Arrays.binarySearch(chars,'t')); - 可以采用equals方法檢測(cè)兩個(gè)數(shù)組是否嚴(yán)格相等。
int[] list1 = {2,4,7,10}; int[] list2 = {2,4,7,10}; int[] list3 = {4,2,7,10}; System.out.println(java.util.Arrays.equals(list1,list2));//true System.out.println(java.util.Arrays.equals(list2,list3));//false - 可以使用fill方法填充整個(gè)數(shù)組或部分?jǐn)?shù)組。
int[] list1 = {2,4,7,10}; int[] list2 = {2,4,7,7,7,10}; java.util.Arrays.fill(list1,5); java.util.Arrays.fill(list2,1,5,8); - 可以使用toString方法來返回一個(gè)字符串,該字符串代表了數(shù)組中的所有元素。
int[] list3 = {2,4,7,10}; System.out.println(java.util.Arrays.toString(list));
-
7.13 命令行參數(shù)
main方法的生命有點(diǎn)特殊,他具有String[]類型參數(shù)args。很明顯,參數(shù)args是一個(gè)字符串?dāng)?shù)組。main方法就像一個(gè)帶參數(shù)的普通方法??梢酝ㄟ^傳遞實(shí)參來調(diào)用一個(gè)普通方法。當(dāng)然也是可以給main傳遞參數(shù)的。
- 7.13.1 向main方法傳遞字符串
- 運(yùn)行程序時(shí),可以從命令行給main方法傳遞字符串參數(shù)。例如,愛你的命令行用三個(gè)字符串a(chǎn)rg0、arg1、arg2啟動(dòng)程序TestMain:
java TestMain arg0 arg1 arg2 - 其中,參數(shù)arg0、arg1、arg2都是字符串,但是在命令行中出現(xiàn)時(shí),不需要放在雙引號(hào)中。這些字符串用空格分隔。如果字符串包含空格,那就必須使用雙引號(hào)括住。
- 當(dāng)調(diào)用main方法時(shí),Java解釋器會(huì)創(chuàng)建一個(gè)數(shù)組存儲(chǔ)命令行參數(shù),然后將該數(shù)組的引用傳遞給args。例如,乳溝調(diào)用具有n個(gè)參數(shù)的程序,Java解釋器創(chuàng)建一個(gè)如下所示的數(shù)組:
args = new String[n]; - 如果運(yùn)行程序時(shí)沒有傳遞字符串,那么使用new String[0]創(chuàng)建數(shù)組。在這種情況下,哎數(shù)組是長度為0的空數(shù)組。args是對(duì)這個(gè)空數(shù)組的引用。因此,args不是null,args.length為0。
- 運(yùn)行程序時(shí),可以從命令行給main方法傳遞字符串參數(shù)。例如,愛你的命令行用三個(gè)字符串a(chǎn)rg0、arg1、arg2啟動(dòng)程序TestMain:
- 7.13.2 示例學(xué)習(xí):計(jì)算器
package chapter06; public class Calculator { public static void main(String[] args){ if (args.length != 3){ System.out.println("Usage:java Calculator operand1 operator operand2"); System.exit(1); } int result = 0; switch (args[1].charAt(0)){ case '+':result = Integer.parseInt(args[0]) + Integer.parseInt(args[2]);break; case '-':result = Integer.parseInt(args[0]) - Integer.parseInt(args[2]);break; case '.':result = Integer.parseInt(args[0]) * Integer.parseInt(args[2]);break; case '/':result = Integer.parseInt(args[0]) / Integer.parseInt(args[2]);break; } System.out.println(args[0] + ' ' + args[1] + ' ' + args[2] + " = " + result); } }- 我們使用.符號(hào)用于乘法,而不是通常的符號(hào)。原因是當(dāng)符號(hào)用于命令行時(shí)表示當(dāng)前目錄下的所有文件。
- 7.13.1 向main方法傳遞字符串