一、數組(一維): 對於聲明變數,int score1 = 81; 等等這些操作,如果我們有四個成績,是不是可以定義變數score 1、2、3、4呢?但是,如果我們要定義400個成績又當如何呢? 這就可以用到數組了,數組可以指定一個長度,然後在數組裡可以存放這個長度範圍的同類型數組,可以將數組理解為 ...
一、數組(一維):
對於聲明變數,int score1 = 81; 等等這些操作,如果我們有四個成績,是不是可以定義變數score 1、2、3、4呢?但是,如果我們要定義400個成績又當如何呢?
這就可以用到數組了,數組可以指定一個長度,然後在數組裡可以存放這個長度範圍的同類型數組,可以將數組理解為是一個巨大的“盒子”,裡面可以按順序存放多個類型相同的數據。不過,因為它是由長度範圍的,所以長度在聲明完成之後就是不能變化的了,對於一些總是需要增加一些信息進去的情況,就不適合於用數組了。如電話簿。你也許會想,能不能一開始就聲明一個很長很長的長度用來放數據,但是聲明很長是需要占記憶體的,會拖慢程式的運行速度。(對於這一"缺點",會在之後的集合中得到很好的應用)
那麼,如何使用 Java 中的數組?Java 中操作數組只需要四個步驟:
1、 聲明數組
語法: 數據類型[ ] 數組名; 或者 數據類型 數組名[ ];
其中,數組名可以是任意合法的變數名,如:
int[] scores;
double aArray[];
String[] names;
2、 分配空間
簡單地說,就是指定數組中最多可存儲多少個元素
語法: 數組名 = new 數據類型 [ 數組長度 ];
其中,數組長度就是數組中能存放元素的個數,如:
scores = new int[5];
aArray = new double[5];
names = new String[5];
其實,我們也可以將上面的兩個步驟合併,在聲明數組的同時為它分配空間,如:
int[] scores = new int[5];
關於該分配空間的過程是一個動態創建數組的過程
3、 賦值
分配空間後就可以向數組中放數據了,數組中元素都是通過下標來訪問的,並且註意的是數組中的索引(即下標)是從0開始,到數組長度-1結束。例如向 scores 數組中存放學生成績
scores[0] = 81;
scores[1] = 85;
scores[2] = 87;
scores[3] = 89;
scores[4] = 92;
4、 處理數組中數據
我們可以對賦值後的數組進行操作和處理,如獲取並輸出數組中元素的值
System.out.println("scores數組中的第一個元素是: " + scores[0]);
在 Java 中還提供了另外一種直接創建數組的方式,它將聲明數組、分配空間和賦值合併完成,關於此種方式,稱做靜態創建數組。語法格式為:
數據類型 數組名[] = { 需要給數組賦值的內容(多個以逗號隔開) }; 如:
int scores[] = {81, 85, 87, 89, 92};
它等價於:
int[] scores = new int[]{81, 85, 87, 89, 92};
二、下麵再介紹一些關於數組的基本操作:
- 遍曆數組:
關於遍曆數組主要有一維和二維兩種,分別以for迴圈和foreach迴圈進行遍歷。代碼如下:
package com.rocking;
public class TraverseArray {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = new int[]{1, 2, 3, 5, 98, 45, 15 ,546 , 49};
int aa[][] = new int[][]{{12, 26, 56}, {15, 65, 48, 89}, {45, 29, 75, 64, 19}};
//遍歷一維數組(for 與 foreach兩種方式)
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
System.out.println("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>");
for (int i : a) {
System.out.print(i+" ");
}
System.out.println("\n/////////////////////////////");
//遍歷二維數組(for 與 foreach兩種方式)
for (int i = 0; i < aa.length; i++) {
for (int j = 0; j < aa[i].length; j++) {
System.out.print(aa[i][j]+" ");
}
}
System.out.println("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
for (int[] i : aa) {
for (int j : i) {
System.out.print(j+" ");
}
}
}
}
可以看到,foreach語句進行遍歷稍微簡單一些。如果要引用數組或者集合的索引,則foreach語句無法做到,foreach僅僅老老實實地遍曆數組或者集合一遍
關於foreach語句,需要將Compiler Compliance Level調成1.5或以上的等級。預設的是1.4;否則使用foreach語句會報如下的錯誤。[Syntax error, 'for each' statements are only available if source level is 1.5 or greater]。具體操作為:右鍵你建立的項目名,選擇最下麵的Properties,在打開的面板中選擇Java Compiler。將右邊JDK Compliance下的覆選框取消選中,再將Compiler Compliance Level的等級調成1.5或以上,點擊OK即可。
- 填充替換數組元素:
數組中的元素定義完成之後,可以通過Arrays類提供的fill()方法來對數組中的元素進行替換。該方法通過各種重載的形式可完成任意類型的數組元素的替換。
fill()方法有如下兩種參數類型,①、fill(int[] a, int value)和②、fill(int[] a, int fromIndex, int toIndex, int value).
方法①可以將指定的int值分配給int型數組的每個元素;方法②將指定的int值分配給int型數組指定範圍中的每個元素。指定的範圍是從索引fromIndex(包括)一直到索引toIndex(不包括)。如果fromIndex == toIndex,則填充範圍為空。如果指定的索引位置大於或等於要進行填充的數組的長度,則會報出ArrayIndexOutOfBoundsException(數組越界異常)
代碼如下:
package com.rocking;
import java.util.Arrays;
public class LearnArrayFill {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = new int[]{1, 2, 3, 5, 98, 45, 15 ,56 , 49};
Arrays.fill(a, 6); //將數組中的所有元素都替換為value的值6
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+" ");
}
System.out.println();
int b[] = new int[]{98, 3, 5, 45, 15 ,46 ,1, 2, 49};
Arrays.fill(b, 3, 5, 99); //將數組a中的a[3](包括第4個)到a[5](不包括第6個)之間的元素替換為value的值6
for (int i : b) {
System.out.print(i+" ");
}
}
}
- 對數組進行排序:
通過Arrays類提供的靜態方法sort()即可實現對指定類型數組按數字升序進行排序。
主要有以下兩種重載方式:
①、sort(Object[] a)
該形式是以升序的方式對數組中的所有元素進行排序。
②、sort(Object[] a, Object fromIndex, Object toIndex)
該形式是將索引位置從fromIndex(包括)到toIndex(不包括)內的元素按照升序的順序進行排序。
import java.util.Arrays;
public class LearnArraysSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
int array[] = new int[]{98, 3, 5, 45, 15 ,46 ,1, 2, 49};
int[] a = {98, 3, 5, 45, 15 ,46 ,1, 2, 49};
Arrays.sort(array); //使用sort(Object[] array)重載形式,將數組中的所有元素按照升序的順序排序
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+">>");
//1>>2>>3>>5>>15>>45>>46>>49>>98>>
}
System.out.println("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
Arrays.sort(a, 3, 6); //將索引位置從fromIndex(包括)到toIndex(不包括)內的元素按照升序的順序進行排序。
for (int i : a) {
System.out.print(i+"<<");
//98<<3<<5<<15<<45<<46<<1<<2<<49<<
}
System.out.println("\n\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
String aa[] = {"AAB", "AAb", "aaB", "535", "001", "納尼", "嗦嘎", "aab"};
Arrays.sort(aa);
for (String str : aa) {
System.out.print(str+"///");
//001///535///AAB///AAb///aaB///aab///嗦嘎///納尼///
}
}
}
在上述代碼中,String類型的數組的排序演算法是按照字典編碼順序排的,因此我們可以看到:數字排列在字母的前面,字母排列在漢字的前面;並且大寫字母排列在小寫字母的前面。
- 複製數組:
對數組進行複製,需要用到Arrays類的copyOf()或copyOfRange()方法;
copyOf(Object[] original, int newLength):複製數組到指定的長度。
copyOfRange(Object[] original, int fromIndex, int toIndex):將指定數組的指定長度複製到另一個新的數組中。
關於複製就有粘貼,所以這些數組調用了複製的方法,就需要有一個新的數組來接收它。
一言不合就貼代碼:
import java.util.Arrays;
public class LearnArraysCopy {
public static void main(String[] args) {
// TODO Auto-generated method stub
int array11[] = new int[]{98, 3, 5, 45, 15 ,46 ,1, 2, 49};
String array21[] = {"AAB", "001", "納尼", "aaB", "535", "嗦嘎", "aab", "AAb"};
//將數組array21中的長度為5的數組元素複製到新的數組array22中
String[] array22 = Arrays.copyOf(array21, 5);
for (String str : array22) {
System.out.print(str+"<<>>");
//AAB<<>>001<<>>納尼<<>>aaB<<>>535<<>>
}
System.out.println("\n\n+++++++++++++++++++++++++++++++++++++++\n");
//將數組array11中的索引位置3(包括)到7(不包括)的元素複製到新的數組array12中
int[] array12 = Arrays.copyOfRange(array11, 3, 11);
for (int i = 0; i < array12.length; i++) {
System.out.print(array12[i]+">><<");
//45>><<15>><<46>><<1>><<2>><<49>><<0>><<0>><<
}
}
}
可以看到:我們可以將toIndex(newLenght)的數值設置為大於數組的長度,那麼在新數組中就會以0(null)代替後面沒有的元素,但是,如果將fromIndex設置為大於數組長度的值,就會報ArrayIndexOutOfBoundsException(數組越界異常)
- 數組查詢:
對數組中元素的查詢可以用二分搜索法來搜索指定類型的數組,以獲得指定的值。不過使用二分查找法必須先對數組進行排序。如果沒有對數組進行排序,則結果是不確定的。如果數組包含多個帶有指定值的元素,則無法保證找到的是哪一個。
所以我們可以建立一個程式,如:LearnBinarySearch。然後在其中創建一個數組,首先調用Arrays類的sort()方法對數組進行排序。然後使用binarySearch()對key值進行查找。
如果數組中存在這個key值,那麼就返回該key值所在的索引值。如果key值不在,那麼就返回第一次大於該key值的數值所在位置(從1開始)的負值,註意此處說的是位置,從1開始;而不是索引的值(從0開始)。
當然,如果我們不先對數組進行排序又會怎麼樣呢?創建了一個數組 int array1[] = new int[]{98, 16, 9, 45, 13 ,46 ,1, 4, 49}; 然後分別對其中的每一個元素進行二分查找,返回的值只有13是返回一個4以及49返回一個8;其他的都是返回負值,然後不存在的數值返回的也是亂七八糟的負值。似乎沒有規律可循。
package com.rocking;
import java.util.Arrays;
public class LearnBinarySearch {
public static void main(String[] args) {
// TODO Auto-generated method stub
//創建一個一維數組
int array1[] = new int[]{98, 16, 9, 45, 13 ,46 ,1, 4, 49};
//首先對數組進行排序
Arrays.sort(array1);
//遍曆數組,查看現在數組的排序順序(方便在後面比較查找的數值的索引值)
for (int i = 0; i < array1.length; i++) {
System.out.print(array1[i]+" ");
}
System.out.println("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
//如果存在該數值,則返回一個查到的Key值的索引值
System.out.println(Arrays.binarySearch(array1, 46));
System.out.println("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
//如果數組中不存在該數值,則返回第一次大於該key值的數值所在位置(從1開始)的負值(註意是位置值而不是索引值)
//因為數組中的所有元素都比-5要大,所以返回的是數組中第一個元素的位置的負值,即-1
System.out.print(Arrays.binarySearch(array1, -5)+" ");
//第一次大於7的數值是9,處於第3位;於是返回-3
System.out.print(Arrays.binarySearch(array1, 7)+" ");
//第一次大於33的數值是45,處於第6位;於是返回-6
System.out.print(Arrays.binarySearch(array1, 33)+" ");
//第一次大於120的數值在數組中不存在,於是返回最大位置值+1的負值,即-10
System.out.println(Arrays.binarySearch(array1, 120)+" ");
System.out.println("\n<<<<<<<<<<<<<<>>>>>>>>>>>>>>\n");
NoSort ns = new NoSort();
ns.method();
}
}
class NoSort {
//在該方法中測試一下如果不先對數組進行排序,而進行二分查找會出現什麼結果
void method() {
int array1[] = new int[]{98, 16, 9, 45, 13 ,46 ,1, 4, 49};
System.out.println(Arrays.binarySearch(array1, 46));
System.out.println("\n<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
System.out.print(Arrays.binarySearch(array1, 7)+" ");
System.out.print(Arrays.binarySearch(array1, 33)+" ");
System.out.println(Arrays.binarySearch(array1, 47)+" ");
}
}
上述過程中用到的只是binarySearch()方法的一種重載形式,它還有一種重載形式是指定範圍內的查找;語法如下:
binarySearch(Object[] array, int fromIndex, int toIndex, Object key);
其中的array是數組名;fromIndex是開始查找的開始處索引值(包括);toIndex是查找的結束處索引值(不包括);key是要查找的元素
官方文檔中提到,使用該方法同樣需要先進行排序
package com.rocking;
import java.util.Arrays;
public class LearnBinarySearch2 {
public static void main(String[] args) {
int array1[] = new int[]{98, 16, 9, 45, 13 ,46 ,1, 4, 49};
Arrays.sort(array1);
int i = Arrays.binarySearch(array1, 2, 8, 46);
for (int j = 0; j < array1.length; j++) {
System.out.print(array1[j]+" ");
}
System.out.println("\n46所處的索引位置是:"+i);
}
}
註意:如果指定的範圍大於或等於數組的長度,會報出[ArrayIndexOutOfBoundsException]數組越界異常。
三、下麵介紹一些關於數組的排序演算法:
- 冒泡排序:
冒泡排序排序元素的過程總是將小數往前放,大數往後排;類似於水中上升的氣泡,故作冒泡排序。
基本思想:比較相鄰的元素值,如果兩個元素前面的比後面的大,則將前面的小數往後排,後面的大數往前移。具體的原理圖就不畫了(貼個關於冒泡排序的動畫效果的網址http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/maopaopaixu.htm)。再嘮叨一下程式的原理好了。
冒泡排序用到了雙重的for迴圈。其中外層迴圈是用於控制排序的輪數的,最多需要的是數組長度-1輪。內層迴圈是用於比較相鄰元素之間的數值大小,如果前面的元素大於後面的元素,則進行交換。對比的次數是和輪數有關的,每一輪的對比次數是不會超過數組長度-輪數的大小的。好了,又到了大家最喜歡的貼代碼的環節了。代碼如下:
package com.rocking;
public class MaoPao {
public static void main(String[] args) {
int score[] = {85, 90, 87, 100, 89, 81, 82, 92};
int temp;
for (int i = 1; i < score.length; i++){ //最多做n-1趟排序
for(int j = 0 ;j < score.length - i; j++){ //每一個數最多進行數組長度-1-排列的趟數
//升序過程,
if (score[j] > score[j+1]) {//如果前面的數值大於後面的數值,則將前面的數值換到後面的位置,而將後面的元素換到前邊的位置,因此需要添加一個temp變數用來轉換兩個位置的數
temp = score[j];
score[j] = score[j+1];
score[j+1] = temp;
}
}
for(int j = 0; j<score.length; j++) {
System.out.print(score[j] +" ");
}
System.out.println();
}
}
}
- 直接選擇排序:
直接選擇排序聽名字就知道其是選擇排序的一種,其排序速度比冒泡排序要快一些。
基本思想:在一個無序數組中,首先從前面第一個數開始,依次與後面的數值進行比較,假如是按從小到大的順序排列,則從前依次往後比較之後,不斷的用比較得到的新的最大的與後面的數進行比較。最終將兩兩比較後找到的最大的數值與最後一位數的位置進行互換。相當於是從數組中找到其中最大的一個數,將其位置與最後一位進行交換。然後除最末這個最大的數值,前面的數值又是一個無序組,在該無序組中,又找出最大的數值,與該無序組的最後一個數值進行位置交換,從而又在前面產生一個新的無序組。重覆以上步驟,最終得到了一個從小到大排列的數組。同樣貼上一個關於快速選擇排序演算法的網址http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/zhijiexuanze.htm
根據其基本思想,可知其與冒泡排序類似,也是最多進行數組長度array.length - 1輪排序,且每次排序需要比較的不超過array.length - i(輪數)次。因此,該演算法依舊是採用雙重迴圈進行排序,只不過是在內部的實現過程有些許差異罷了。
一言不合就貼代碼:
public class LearnFastChoiseSort {
public static void main(String[] args) {
LearnFastChoiseSort lfcs = new LearnFastChoiseSort();
lfcs.sort();
}
void sort() {
int array[] = new int[]{98, 3, 5, 45, 15 ,46 ,1, 2, 49};
//int max = array[0];
int temp;
int index;
for (int i = 1; i < array.length; i++) {
index = 0;
for (int j = 1; j <= array.length-i; j++) {
if (array[index] > array[j]) {
index = j;
}
temp = array[array.length - i];
array[array.length - i] = array[index];
array[index] = temp;
}
}
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}
}
}
- 反轉排序:
顧名思義,反轉排序是將數組中的元素由原來的順序反過來排序。
基本原理:將數組中的最後一個元素與第一個元素進行替換,將倒數第二個元素和第二個元素進行替換......知道把所有的數組元素替換完畢。
感覺這種排序實現起來還蠻容易的,拿代碼測試下:
public class LearnReversalSort {
public static void main(String[] args) {
int array[] = new int[]{98, 3, 5, 45, 15 ,46 ,1, 2, 49};
int temp;
for (int i = 1; i < array.length*0.5+1; i++) {
for (int j = i-1; j < i; j++) {
temp = array[j];
array[j] = array[array.length-i];
array[array.length-i] = temp;
}
}
for (int i : array) {
System.out.print(i+" ");
}
}
}
因為每次排序只交換兩個元素,即:只進行一次排序。且在第一輪是交換第一個與最後一個元素,第二趟是交換第二個和倒數第二個元素...以此類推。所以在內層for迴圈中採用int j = i-1; j < i; j++的條件。