07-一維數組
-
7.1 引言
- 單個的數組變量可以引用一個大的數據集合。
-
7.2 數組的基礎知識
一旦數組被創建,他的大小是固定的。使用一個數組引用變量和下標來訪問數組中的元素。
- 7.2.1 聲明數組變量
- 為了在程序中使用數組,必須聲明一個引用數組的變量,并指明數組的元素類型。下賣弄是聲明數組變量的語法:
elementType[] arrayRefVar; //或者 elementType arrayRefVar[];//是允許這樣的,但是不是最好的方式
- elementType可以是任意數據類型,但是數組中所有的元素都必須具有相同的數據類型。
- 也可以用elementType arrayRefVar[]聲明數組變量。這種來自c/c++語言的風格被Java采納以適用于c/c++程序員。推薦使用elementType[] arrayRefVar。
- 為了在程序中使用數組,必須聲明一個引用數組的變量,并指明數組的元素類型。下賣弄是聲明數組變量的語法:
- 7.2.2 創建數組
- 不同于聲明基本數據類型變量,聲明一個數組變量時并不給數組分配任何內存空間。它只是創建一個對數組的引用的存儲位置。如果變量不包含對數組的引用,那么這個變量的值為null。除非數組已經被創建,否則不能給他分配任何元素。聲明數組變量之后,可以使用下面的語法用new操作符創建數組,并且將它的引用賦給一個變量:
arrayRefVar = new elementType[arraySize];
- 這條語句做了兩件事:
- 1、使用new elementType[arraySize]創建了一個數組;
- 2、把這個新創建的數組的引用賦值給變量arraySize。
- 聲明一個數組變量、創建數組、將數組引用賦值給變量這三個步驟可以合并在一條語句里。
elementType[] arrayRefVar = new elementType[arraySize]; //或者 elementType arrayRefVar[] = new elementType[arraySize];
- 一個數組變量看起來似乎是存儲了一個數組,但實際上他存儲的是指向數組的引用。嚴格的講,一個數組變量和一個數組是不同的,但多數情況下他們的差別是可以忽略的。因此,為了簡化,通常常可以說myList是一個數組,而不用更長的陳述:myList是一個含有double型元素數組的引用變量。
- 不同于聲明基本數據類型變量,聲明一個數組變量時并不給數組分配任何內存空間。它只是創建一個對數組的引用的存儲位置。如果變量不包含對數組的引用,那么這個變量的值為null。除非數組已經被創建,否則不能給他分配任何元素。聲明數組變量之后,可以使用下面的語法用new操作符創建數組,并且將它的引用賦給一個變量:
- 7.2.3 數組大小和默認值
- 當給數組分配空間時,必須指定該數組能夠存儲的元素個數,從而確定數組大小。創建數組之后就不能再修改它的大小了。可以使用arrayRefVar.length得到數組的大小。
- 當創建數組后,他的元素唄賦予默認值,數值型基本數據類型的默認值為0,char型的默認值為‘\u0000’,boolean型的默認值為false。
- 7.2.4 訪問數組元素
- 數組元素可以通過下標訪問。數組下標是基于0的,也就是說,其范圍從0開始到arrayRefVar.length-1結束。數組中的每個元素都可以使用下面的語法表示,稱為下標變量:
arrayRefVar[index];
- 數組元素可以通過下標訪問。數組下標是基于0的,也就是說,其范圍從0開始到arrayRefVar.length-1結束。數組中的每個元素都可以使用下面的語法表示,稱為下標變量:
- 7.2.5 數組初始化簡寫方式
- Java有一個簡捷的標記,稱作數組初始化簡寫方式,他使用下面的語法將聲明數組、創建數組和初始化數組結合到一條語句中:
elementType[] arrayRefVar = {value0,value1,...,valuek};
- 數組初始化簡寫方式中不使用操作符new。使用數組初始化簡寫方式時,必須將聲明、創建和初始化數組都放在一條語句中。
- Java有一個簡捷的標記,稱作數組初始化簡寫方式,他使用下面的語法將聲明數組、創建數組和初始化數組結合到一條語句中:
- 7.2.6 處理數組
- 處理數組元素時,經常會用到for循環,理由如下:
- 數組中所有元素都是同一類型的。可以使用循環以同樣的方式反復處理這些元素。
- 由于數組的大小是已知的,所以很自然的就使用for循環。
- 1、使用輸入值初始化數組
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、使用隨機數初始化數組
for (int i = 0;i < myList.length;i++){ myList[i] = Math.random() * 100; }
- 3、顯示數組
char[] city = {'D','a','l','l','a','s'}; System.out.println(city);
- 4、對所有元素求和
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、找出最大元素的最小下標值
double max = myList[0]; int indexOfMax = 0; for (int i = 1;i < myList.length;i++){ max = myList[i]; indexOfMax = 1; }
- 7、隨機打亂
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、移動元素
double temp = myList[0]; for (int i = 1;i < myList.length;i++){ myList[i - 1] = myList[i]; } myList[myList.length - 1] = temp;
- 9、簡化編碼
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]);
- 處理數組元素時,經常會用到for循環,理由如下:
- 7.2.7 foreach循環
- Java支持一個簡便的for循環,稱為foreach循環,即不使用下標變量就可以順序的遍歷整個數組。下面的代碼就可以顯示數組myList的所有元素:
for(double e : myList){ Syetem.out.println(e) }
- foreachde的語法是:
for(elementType element: arrayRefVar){ //Process the element }
- Java支持一個簡便的for循環,稱為foreach循環,即不使用下標變量就可以順序的遍歷整個數組。下面的代碼就可以顯示數組myList的所有元素:
- 7.2.1 聲明數組變量
-
7.3 示例學習:分析數字
- 編寫一個程序,找到大于平均值的項的數目。
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); } }
- 編寫一個程序,找到大于平均值的項的數目。
-
7.4 示例學習:一副牌
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 復制數組
- 要將一個數組中的內容復制到另外一個數組中,需要將數組的每個元素復制到另外一個數組中。
list2 = list1
- 上面的語句并不能將list1引用的數組內容復制到list2,而只是將list1的引用值復制給了list2.在這條語句之后,list1和list2都指向同一個數組。list2原先所引用的數組不能再引用,它就變成了垃圾,會被Java虛擬機自動收回(這個過程稱為垃圾回收)。
- 復制數組有三種方法:
- 1、使用循環語句逐個的賦值數組的元素;
- 2、使用System類中的靜態方法arraycopy;
- arraycopy的語法是:
arraycopy(sourceArray,srcPos,targeArray,tarPos,length);
- 參數srcPos和tarPos分別表示在源數組sourceArray和目標數組targetArray中的起始位置。從sourceArray復制到targetArray中的元素個數由參數length指定。
- arraycopy方法沒有給目標數組分配內存空間。復制前必須創建目標數組以及分配給他的內存空間。復制完成后,sourceArray和targetArray具有相同的內容,但占有獨立的內存空間。
- arraycopy的語法是:
- 3、使用clone方法賦值數組。
- 要將一個數組中的內容復制到另外一個數組中,需要將數組的每個元素復制到另外一個數組中。
-
7.6 將數組傳遞給方法
- 當一個數組傳遞給方法時,數組的引用被傳給方法。
- 和方法傳遞基本數據類型一樣,也可以給方法傳遞數組。
public static void printArray(int[] array){ for(int i = 0;i < array.length;i++){ System.out.print(array[i] + " "); } }
- 使用下述語法創建數組:
new elementType[]{value0,value1,...,valuek};
- 該數組沒有顯式的引用變量,這樣的數組稱為匿名函數。
- Java使用按值傳遞的方式將實參傳遞給方法。傳遞劇本數據類型變量的值與傳遞數組值有很大的不同:
- 對于基本數據類型參數,傳遞的是實參的值;
- 對于數組類型參數,參數值是數組的引用,給方法傳遞的是這個引用。從語義上來講,最好的描述為傳遞共享信息,即方法中的數組和傳遞的數組是一樣的。因此,如果改變方法中的數組,將會看到方法外的數組也改變了。
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 方法返回數組
- 當方法返回一個數組時,數組的引用被返回。
-
7.8 示例學習:統計每個字母出現的次數
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 可變長參數列表
- 具有同樣類型的數目可變的參數可以傳遞給方法,并將作為數組對待。方法中的參數聲明如下:
typeName...patameterName(類型名...參數名)
- 在方法聲明中,指定類型后緊跟著省略號(...)。只能個方法中指定一個可變長參數,同時該參數必須是最后一個參數。任何常規參數必須在他之前。
- Java將可變長參數當成數組對待。
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); } }
- 具有同樣類型的數目可變的參數可以傳遞給方法,并將作為數組對待。方法中的參數聲明如下:
-
7.10 數組的查找
- 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 數組的排序
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類包含一些使用的方法用于常見的數組操作,比如排序和查找。
- 可以使用sort或者parrallelSort方法對整個數組或部分數組進行排序。
- 可以調用sort(number)對整個數組numbers排序。可以調用sort(chars,1,3)對從chars[1]到chars[3-1]的部分數組進行排序。如果你的計算機有多個處理器,那么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方法)在數組中查找關鍵字。如果數組中不存在關鍵字,方法返回-(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方法檢測兩個數組是否嚴格相等。
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方法填充整個數組或部分數組。
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方法來返回一個字符串,該字符串代表了數組中的所有元素。
int[] list3 = {2,4,7,10}; System.out.println(java.util.Arrays.toString(list));
-
7.13 命令行參數
main方法的生命有點特殊,他具有String[]類型參數args。很明顯,參數args是一個字符串數組。main方法就像一個帶參數的普通方法。可以通過傳遞實參來調用一個普通方法。當然也是可以給main傳遞參數的。
- 7.13.1 向main方法傳遞字符串
- 運行程序時,可以從命令行給main方法傳遞字符串參數。例如,愛你的命令行用三個字符串arg0、arg1、arg2啟動程序TestMain:
java TestMain arg0 arg1 arg2
- 其中,參數arg0、arg1、arg2都是字符串,但是在命令行中出現時,不需要放在雙引號中。這些字符串用空格分隔。如果字符串包含空格,那就必須使用雙引號括住。
- 當調用main方法時,Java解釋器會創建一個數組存儲命令行參數,然后將該數組的引用傳遞給args。例如,乳溝調用具有n個參數的程序,Java解釋器創建一個如下所示的數組:
args = new String[n];
- 如果運行程序時沒有傳遞字符串,那么使用new String[0]創建數組。在這種情況下,哎數組是長度為0的空數組。args是對這個空數組的引用。因此,args不是null,args.length為0。
- 運行程序時,可以從命令行給main方法傳遞字符串參數。例如,愛你的命令行用三個字符串arg0、arg1、arg2啟動程序TestMain:
- 7.13.2 示例學習:計算器
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); } }
- 我們使用.符號用于乘法,而不是通常的符號。原因是當符號用于命令行時表示當前目錄下的所有文件。
- 7.13.1 向main方法傳遞字符串