02_陣列
注:本部分為自學內容,學習過程中整理筆記方便以後查閱。課件內容來自尚學堂,教程地址:https://www.bilibili.com/video/BV1Kb411W75N?p=63
2.1 陣列概述(陣列有序排列)
陣列(Array):是多個相同型別資料按一定順序排列的集合,並使用一個名字命名,並通過編號的方式對這些資料進行統一管理。
常見概念:
陣列名
下標(或索引)
元素
陣列的長度
概述:
陣列本身是引用資料型別,而陣列中的元素可以是任何資料型別,包括基本資料型別和引用資料型別。
建立陣列物件會在記憶體中開闢一整塊連續的空間,而陣列名中引用的是這塊連續空間的首地址。
陣列的長度一旦確定,就不能修改。
我們可以直接通過下標(或索引)的方式呼叫指定位置的元素,速度很快。
陣列的分類:
- 按照維度:一維陣列、二維陣列、三維陣列、…
- 按照元素的資料型別分:基本資料型別元素的陣列、引用資料型別元素的陣列(即物件陣列)
2.2 一維陣列的使用
2.2.1 一維陣列的使用:宣告
一維陣列的宣告方式:
type var[] 或 type[] var;
例如:
int a[];
int[] a1;
double b[];
String[] c; //引用型別變數陣列
注: Java語言中宣告陣列時不能指定其長度(陣列中元素的數), 例如: int a[5]; //非法
2.2.2 一維陣列的使用:初始化
- 動態初始化:陣列宣告且為陣列元素分配空間與賦值的操作分開進行
int[] arr = new int[3];
arr[0] = 3;
arr[1] = 9;
arr[2] = 8;
String names[];
names = new String[3];
names[0] = “錢學森”;
names[1] = “鄧稼先”;
names[2] = “袁隆平”;
- 靜態初始化:在定義陣列的同時就為陣列元素分配空間並賦值。
int arr[] = new int[]{ 3, 9, 8};
或
int[] arr = {3,9,8};
String names[] = {
“李四光”,“茅以升”,“華羅庚”
}
總結:陣列一旦初始化完成,其長度就確定了(定義陣列時要麼指定長度,要麼賦值)。
2.2.3 一維陣列的使用:陣列元素的使用
- 定義並用運算子new為之分配空間後,才可以引用陣列中的每個元素;
- 陣列元素的引用方式:陣列名[陣列元素下標]
- 陣列元素下標可以是整型常量或整型表示式。如a[3] , b[i] , c[6*i];
- 陣列元素下標從0開始;長度為n的陣列合法下標取值範圍: 0 —>n-1;如int a[]=new int[3]; 可引用的陣列元素為a[0]、a[1]、a[2]
- 每個陣列都有一個屬性length指明它的長度,例如:a.length 指明陣列a的長
度(元素個數)
- 陣列一旦初始化,其長度是不可變的
2.2.4 一維陣列的使用:陣列元素的預設初始化值
- 陣列是引用型別,它的元素相當於類的成員變數,因此陣列一經分配空間,其中的每個元素也被按照成員變數同樣的方式被隱式初始化。例如:
public class Test {
public static void main(String argv[]){
int a[]= new int[5];
System.out.println(a[3]); //a[3]的預設值為0
}
}
- 對於基本資料型別而言,預設初始化值各有不同
- 對於引用資料型別而言,預設初始化值為null(注意與0不同!)
2.2.5 一維陣列的記憶體解析:
記憶體結構簡圖:
解析:arr1在棧空間中宣告;new的結構在堆空間中說明,長度為4,堆開闢連續的空間,比如首地址為0x12ab,將首地址值賦給 arr1,通過棧空間地址值可以指向堆空間實體結構,然後是賦值操作。
Java中使用關鍵字new來建立陣列
step1:定義陣列,分配棧空間
public class Test{
public static void main(String args[]){
int[] s;
s = new int[10];
for ( int i=0; i<10; i++ ) {
s[i] =2*i+1;
System.out.println(s[i]);
}
}
}
step2:初始化
public class Test{
public static void main(String args[]){
int[] s;
s = new int[10];
//int[] s=new int[10];
//基本資料型別陣列在顯式賦值之前,
//Java會自動給他們賦預設值。
for ( int i=0; i<10; i++ ) {
s[i] =2*i+1;
System.out.println(s[i]);
}
}
}
step3:賦值
public class Test{
public static void main(String args[]){
int[] s;
s = new int[10];
for ( int i=0; i<10; i++ ) {
s[i] =2*i+1;
System.out.println(s[i]);
}
}
}
練習1:輸出聯絡方式
public class ArrayTest {
public static void main(String[] args) {
int[] arr = new int[] { 8, 2, 1, 0, 3 };
int[] index = new int[] { 2, 0, 3, 2, 4, 0, 1, 3, 2, 3, 3 };
String tel = "";
for (int i = 0; i < index.length; i++) { // index.length=11
tel += arr[index[i]];
}
System.out.println("聯絡方式:" + tel); // 18013820100
}
}
練習2:
從鍵盤讀入學生成績,找出最高分,並輸出學生成績等級。
成績>=最高分-10 等級為’A’
成績>=最高分-20 等級為’B’
成績>=最高分-30 等級為’C’
其餘 等級為’D’
提示:先讀入學生人數,根據人數建立int陣列,存放學生成績。
package com.atguigu.contact;
import java.util.Scanner;
public class ArrayDemo1 {
public static void main(String[] args) {
// 1.使用Scanner讀取學生個數
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入學生人數:");
int number = scanner.nextInt();
// 2.建立陣列,儲存學生成績,動態初始化
int[] scores = new int[number];
// 3.給陣列中的元素賦值
System.out.println("請輸入" + number + "個學生成績");
for (int i = 0; i < scores.length; i++) {
scores[i] = scanner.nextInt();
}
// 4.獲取陣列中的元素的最大值
int maxscore = 0;
for (int i = 0; i < scores.length; i++) {
if (scores[i] > maxscore) {
maxscore = scores[i];
}
}
// 5.根據每個學生與最高分的差值,得到每個學生的 等級,並輸出登記和成績
char level;
for (int i = 0; i < scores.length; i++) {
if (maxscore - scores[i] <= 10) {
level = 'A';
} else if (maxscore - scores[i] <= 20) {
level = 'B';
} else if (maxscore - scores[i] <= 30) {
level = 'C';
} else {
level = 'D';
}
System.out.println("student " + i + " score is " + scores[i] + ",gread is " + level);
}
}
}
--------優化:將第3步和第4步合併,少一次遍歷--------
public class ArrayDemo1 {
public static void main(String[] args) {
// 1.使用Scanner讀取學生個數
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入學生人數:");
int number = scanner.nextInt();
// 2.建立陣列,儲存學生成績,動態初始化
int[] scores = new int[number];
// 3.給陣列中的元素賦值
System.out.println("請輸入" + number + "個學生成績");
int maxscore = 0;
for (int i = 0; i < scores.length; i++) {
scores[i] = scanner.nextInt();
// 4.獲取陣列中的元素的最大值
if (scores[i] > maxscore) {
maxscore = scores[i];
}
}
// 5.根據每個學生與最高分的差值,得到每個學生的 等級,並輸出登記和成績
char level;
for (int i = 0; i < scores.length; i++) {
if (maxscore - scores[i] <= 10) {
level = 'A';
} else if (maxscore - scores[i] <= 20) {
level = 'B';
} else if (maxscore - scores[i] <= 30) {
level = 'C';
} else {
level = 'D';
}
System.out.println("student " + i + " score is " + scores[i] + ",gread is " + level);
}
}
}
2.3 多維陣列的使用
- 如果說可以把一維陣列當成幾何中的線性圖形,那麼二維陣列就相當於是一個表格,像右圖Excel中的表格一樣。
- 對於二維陣列的理解,我們可以看成是一維陣列array1又作為另一個一維陣列array2的元素而存在。其實,從陣列底層的執行機制來看,其實沒有多維陣列。
package com.atguigu.contact;
public class ArrayTest02 {
public static void main(String[] args) {
// 一維陣列
int[] arr = new int[] { 1, 2, 3 };
// 二維陣列
// 靜態初始化
int[][] arr1 = new int[][] { { 1, 2, 3 }, { 4, 5, 9, 10 }, { 6, 7, 8 } };
// 動態初始化1
String[][] arr2 = new String[3][2];
// 動態初始化2
String[][] arr3 = new String[3][];
// 遍歷二維陣列
for (int i = 0; i < arr1.length; i++) {
for (int j = 0; j < arr1[i].length; j++) {
System.out.print(arr1[i][j] + " ");
}
System.out.println();
}
}
}
二維陣列初始化:
package com.atguigu.contact;
/*
* 二維陣列的使用:
* 規定:二維陣列分為外層陣列的元素,內層陣列的元素
* int[][] arr = new int[4][3];
* 外層元素:arr[0],arr[1]等
* 內層元素:arr[0][0],arr[1][2]等
*
* 陣列元素的預設初始化:
* 針對於初始化方式一:int[][] arr = new int[4][3];
* 外層元素的初始化值為:地址值
* 內層元素的初始化值為:與一維陣列初始化情況相同
* 針對於初始化方式二:int[][] arr = new int[4][];
* 外層元素的初始化值為:null
* 內層元素的初始化值為:不能呼叫,否則報錯。
*/
public class ArrayTest03 {
public static void main(String[] args) {
int[][] arr = new int[4][3];
System.out.println(arr[0]); // [I@15db9742 地址值
System.out.println(arr[0][0]); // 0;其他型別跟一維陣列相同
System.out.println(arr); //[[I@6d06d69c
double[][] arr1 = new double[4][];
System.out.println(arr1[1]); // null 內層元素沒有初始化
System.out.println(arr1[1][0]); //報錯:java.lang.NullPointerException 空指標異常
}
}
楊輝三角:
package com.atguigu.contact;
/*
* 使用二維陣列列印一個 10 行楊輝三角。
*
* 【提示】
1. 第一行有 1 個元素, 第 n 行有 n 個元素
2. 每一行的第一個元素和最後一個元素都是 1
3. 從第三行開始, 對於非第一個元素和最後一個元素的元素。即:
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
*/
public class YangHuiTest {
public static void main(String[] args) {
// 1.宣告並初始化二維陣列,動態
int[][] yangHui = new int[10][];
// 2.給陣列元素賦值
for (int i = 0; i < yangHui.length; i++) {
yangHui[i] = new int[i + 1];
// 2.1 給首末元素賦值
yangHui[i][0] = yangHui[i][i] = 1;
// 2.2 給每行非首末元素賦值
if (i > 1) {
for (int j = 1; j < yangHui[i].length - 1; j++) {
yangHui[i][j] = yangHui[i - 1][j - 1] + yangHui[i - 1][j];
}
}
}
// 3.遍歷二維陣列
for (int i = 0; i < yangHui.length; i++) {
for (int j = 0; j < yangHui[i].length; j++) {
System.out.print(yangHui[i][j] + " ");
}
System.out.println();
}
}
}
2.4 陣列中涉及的常見演算法
- 陣列元素的賦值(楊輝三角、回形數等)
- 求數值型陣列中元素的最大值、最小值、平均數、總和等
- 陣列的複製、反轉、查詢(線性查詢、二分法查詢)
- 陣列元素的排序演算法
陣列的複製:
2.4.1 二分法查詢演算法
//二分法查詢:要求此陣列必須是有序的。
int[] arr3 = new int[]{-99,-54,-2,0,2,33,43,256,999};
boolean isFlag = true;
int number = 256;
//int number = 25;
int head = 0;//首索引位置
int end = arr3.length - 1;//尾索引位置
while(head <= end){
int middle = (head + end) / 2;
if(arr3[middle] == number){
System.out.println("找到指定的元素,索引為:" + middle);
isFlag = false;
break;
}else if(arr3[middle] > number){
end = middle - 1;
}else{//arr3[middle] < number
head = middle + 1;
}
}
if(isFlag){
System.out.println("未找打指定的元素");
}
2.4.2 排序演算法
排序:假設含有n個記錄的序列為{R1,R2,…,Rn},其相應的關鍵字序列為{K1,K2,…,Kn}。將這些記錄重新排序為{Ri1,Ri2,…,Rin},使得相應的關鍵字值滿足條Ki1<=Ki2<=…<=Kin,這樣的一種操作稱為排序。
- 通常來說,排序的目的是快速查詢。
衡量排序演算法的優劣:
1.時間複雜度:分析關鍵字的比較次數和記錄的移動次數
2.空間複雜度:分析排序演算法中需要多少輔助記憶體
3.穩定性:若兩個記錄A和B的關鍵字值相等,但排序後A、B的先後次序保持不變,則稱這種排序演算法是穩定的。
排序演算法分類:內部排序和外部排序。
- 內部排序:整個排序過程不需要藉助於外部儲存器(如磁碟等),所有排
序操作都在記憶體中完成。 - 外部排序:參與排序的資料非常多,資料量非常大,計算機無法把整個排
序過程放在記憶體中完成,必須藉助於外部儲存器(如磁碟)。外部排序最
常見的是多路歸併排序。可以認為外部排序是由多次內部排序組成。
說明:滿足確定性的演算法也稱為:確定性演算法。現在人們也關注更廣泛的概念,例如考慮各種非確定性的演算法,如並行演算法、概率演算法等。另外,人們也關注並不要求終止的計算描述,這種描述有時被稱為過程(procedure)。
#氣泡排序
介紹:
氣泡排序的原理非常簡單,它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。
排序思想:
- 比較相鄰的元素。如果第一個比第二個大(升序),就交換他們兩個。
- 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。這步
做完後,最後的元素會是最大的數。 - 針對所有的元素重複以上的步驟,除了最後一個。
- 持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要
比較為止。
package com.atguigu.contact;
/*
* 陣列的氣泡排序
*/
public class BubbleSortTest {
public static void main(String[] args) {
int[] arr = new int[] { 43, 32, 76, -98, 0, 64, 33, -21, 32, 99 };
// 氣泡排序
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int i = 0; i < arr.length - 1; i++) {
System.out.print(arr[i] + " ");
}
}
}
#快速排序
介紹:
快速排序通常明顯比同為O(nlogn)的其他演算法更快,因此常被採用,而且快排採用了分治法的思想,所以在很多筆試面試中能經常看到快排的影子。可見掌握快排的重要性。
快速排序是迄今為止所有內排序演算法中速度最快的一種。氣泡排序的升
級版,交換排序的一種。快速排序的時間複雜度為O(nlog(n))。
排序思想:
- 從數列中挑出一個元素,稱為"基準"(pivot),
- 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準
值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽結束之後,
該基準就處於數列的中間位置。這個稱為分割槽(partition)操作。 - 遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數
列排序。 - 遞迴的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好
了。雖然一直遞迴下去,但是這個演算法總會結束,因為在每次的迭代
(iteration)中,它至少會把一個元素擺到它最後的位置去。
private static void subSort(int[] data, int start, int end) {
if (start < end) {
int base = data[start];
int low = start;
int high = end + 1;
while (true) {
while (low < end && data[++low] - base <= 0)
;
while (high > start && data[--high] - base >= 0)
;
if (low < high) {
swap(data, low, high);
} else {
break;
}
}
swap(data, start, high);
subSort(data, start, high - 1);//遞迴呼叫
subSort(data, high + 1, end);
}
}
#排序演算法效能對比
1.從平均時間而言:快速排序最佳。但在最壞情況下時間效能不如堆排序和歸併排序。
2.從演算法簡單性看:由於直接選擇排序、直接插入排序和氣泡排序的演算法比較簡單,將其認為是簡單演算法。對於Shell排序、堆排序、快速排序和歸併排序演算法,其演算法比較複雜,認為是複雜排序。
3.從穩定性看:直接插入排序、氣泡排序和歸併排序時穩定的;而直接選擇排序、快速排序、 Shell排序和堆排序是不穩定排序
4.從待排序的記錄數n的大小看:n較小時,宜採用簡單排序;而n較大時宜採用改進排序。
#排序演算法的選擇
(1)若n較小(如n≤50),可採用直接插入或直接選擇排序。
當記錄規模較小時,直接插入排序較好;否則因為直接選擇移動的記錄數少於直接插入,應選直接選擇排序為宜。
(2)若檔案初始狀態基本有序(指正序),則應選用直接插入、冒泡或隨機的快速排序為宜;
(3)若n較大,則應採用時間複雜度為O(nlgn)的排序方法:快速排序、堆排序或歸併排序。
2.5 Arrays工具類的使用
java.util.Arrays類即為運算元組的工具類,包含了用來運算元組(比如排序和搜尋)的各種方法。
package com.atguigu.contact;
import java.util.Arrays;
/*
* java.util.Arrays:運算元組的工具類,裡面定義了很多運算元組的方法
*/
public class ArraysTest {
public static void main(String[] args) {
// 1.boolean equals(int[] a,int[] b) :判斷兩個陣列是否相等
int[] arr1 = new int[] { 1, 2, 3, 4 };
int[] arr2 = new int[] { 1, 3, 2, 4 };
boolean isEuales = Arrays.equals(arr1, arr2);
System.out.println(isEuales); // false
// 2.boolean equals(int[] a,int[] b) :輸出陣列資訊
System.out.println(Arrays.toString(arr1)); // [1, 2, 3, 4]
// 3.void fill(int[] a,int val):將指定值填充到陣列之中
Arrays.fill(arr1, 10);
System.out.println(Arrays.toString(arr1)); // [10, 10, 10, 10]
// 4.void sort(int[] a) :對陣列進行排序。
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2)); // [1, 2, 3, 4]
// 5.int binarySearch(int[] a,int key) :對排序後的陣列進行二分法檢索指定的值
int[] arr3 = new int[] { -98, -34, 2, 34, 54, 66, 79, 105, 210, 333 };
int index = Arrays.binarySearch(arr3, 210);
if (index >= 0) {
System.out.println(index); // 8
} else {
System.out.println("未找到");
}
}
}
2.6 陣列使用中的常見異常
相關文章
- JavaSE 陣列:一維陣列&二維陣列Java陣列
- 陣列,陣列類,SyStem類陣列
- 陣列結構之陣列陣列
- Java陣列03:陣列使用Java陣列
- 陣列1——求一個陣列的最大子陣列陣列
- 陣列--移除陣列中指定的元素,不改變原陣列和改變原陣列陣列
- 陣列二:使用陣列可變函式為陣列排序陣列函式排序
- 指標陣列和陣列指標與二維陣列指標陣列
- Javascript - 陣列和陣列的方法JavaScript陣列
- 陣列指標,指標陣列陣列指標
- 陣列指標 指標陣列陣列指標
- 陣列陣列
- 02_初識jQueryjQuery
- 記一次陣列操作:陣列 A 根據陣列 B 排序陣列排序
- [求解]陣列,分成倆個陣列,陣列值之和的相差最小。陣列
- 矩陣和陣列矩陣陣列
- PHP陣列轉換為js陣列PHP陣列JS
- iOS 字典轉陣列,陣列轉字典iOS陣列
- 2-7 陣列:動態陣列陣列
- scala陣列與java陣列對比陣列Java
- 指標陣列與陣列指標指標陣列
- 陣列指標和指標陣列陣列指標
- 陣列演算法-差分陣列陣列演算法
- 稀疏陣列、佇列陣列佇列
- PHP 陣列搜尋 sdk & 陣列分頁PHP陣列
- PHP xml 轉陣列 陣列轉 xml 操作PHPXML陣列
- 陣列(ArrayPool陣列池、Span<T>結構)陣列
- golang 陣列去重 移除陣列指定元素Golang陣列
- js 一維陣列轉二維陣列JS陣列
- js 二維陣列轉一維陣列JS陣列
- 【陣列】977. 有序陣列的平方陣列
- 陣列去重和陣列扁平化陣列
- 二維陣列和稀疏陣列互轉陣列
- PHP二維陣列轉一維陣列PHP陣列
- [瘋狂Java]陣列:Arrays(陣列工具類)Java陣列
- 陣列004 動態建立一維陣列陣列
- JavaScript 陣列JavaScript陣列
- 陣列方法陣列