陣列拷貝方法
陣列拷貝的方法有四種
分別為:for clone() System.arraycopy()Array.copyOf()
要研究陣列的拷貝,先看看淺拷貝與深拷貝的概念:
概括起來講,淺拷貝就是指兩個物件公用一個值,一個的改變了另一個也會隨之改變,深拷貝則是兩個物件雖然值相等,但是相互獨立互不影響。
1.for迴圈方法:
程式碼靈活,但效率低。
public class Arraycopy { public static void main(String[] args) { int[] array1 = new int[]{1, 2, 8, 7, 6}; int[] array2 = new int[array1.length]; for (int i = 0;i < array1.length;i++){ array2[i] = array1[i]; } System.out.println("array1 = " + Arrays.toString(array1)); System.out.println("array2 = " + Arrays.toString(array2)); System.out.println("======================"); array2[0] = 100; System.out.println("array1 = " + Arrays.toString(array1)); System.out.println("array2 = " + Arrays.toString(array2)); } }
由結果可以看出,當對複製陣列的某個元素進行改變時,並不影響被複制陣列對應元素,即對於基本資料型別來說for迴圈語句是深拷貝。
package com.me; class TestArray { private int val = 10; public void setVal(int val) { this.val = val; } public int getVal() { return this.val; } } public class TestDeom { public static void main(String[] args) { TestArray[] t1 = new TestArray[4]; t1[0] = new TestArray(); t1[1] = new TestArray(); t1[2] = new TestArray(); t1[3] = new TestArray(); TestArray[] t2 = new TestArray[4];//t2[0] for (int i = 0; i < t1.length; i++) { t2[i] = t1[i]; } for (int i = 0; i < t1.length; i++) { System.out.print(t1[i].getVal() + " "); } System.out.println(); for (int i = 0; i < t2.length; i++) { System.out.print(t2[i].getVal() + " "); } System.out.println(); t2[0].setVal(100000); System.out.println("==============="); for (int i = 0; i < t1.length; i++) { System.out.print(t1[i].getVal() + " "); } System.out.println(); for (int i = 0; i < t2.length; i++) { System.out.print(t2[i].getVal() + " "); } }
}
由結果可以看出,當對複製陣列的某個元素進行改變時,被複制陣列對應元素也隨之改變,即對於引用資料型別來說for迴圈語句是淺拷貝。
2.System.arraycopy()方法:
通過原始碼可以看到,其為native方法,即原生態方法。自然效率更高。
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
如果是陣列比較大,那麼使用System.arraycopy會比較有優勢,因為其使用的是記憶體複製,省去了大量的陣列定址訪問等時間
System.arraycopy()原始碼,可以看到是native方法:native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前檔案,而是在用其他語言(如C和C++)實現的檔案中。 可以將native方法比作Java程式同C程式的介面。
System.arraycopy是不安全的。
src:源陣列;
srcPos:源陣列要複製的起始位置;
dest:目的陣列;
destPos:目的陣列放置的起始位置;
length:拷貝元素的長度.
注意:src和dest必須是同類型或者可以進行轉換型別的陣列,否則會丟擲執行時異常ArrayStoreException.如果指定位置或長度計算得出的下標索引越界,則會丟擲異常 ArrayIndexOutOfBoundsException.
import java.util.Arrays;
public class ArrayCopysystem {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7,8,9};
int[] brray = Arrays.copyOf(array,array.length);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(brray));
brray[0] = 1000;
System.out.println("=================");
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(brray));
}
}
System.arraycopy() 在拷貝陣列的時候,採用的使用潛複製,複製結果是一維的引用變數傳遞給副本的一維陣列,修改副本時,會影響原來的陣列。
import java.util.Arrays;
public class ArrayCopysystem {
public static void main(String[] args) {
stArray[] t1 = new TestArray[4];
t1[0] = new TestArray();
t1[1] = new TestArray();
t1[2] = new TestArray();
t1[3] = new TestArray();
TestArray[] t2 = Arrays.copyOf(t1,t1.length);
for(int i = 0;i < t1.length;i++) {
System.out.print(t1[i].getVal()+" ");
}
System.out.println();
for(int i = 0;i < t2.length;i++) {
System.out.print(t2[i].getVal()+" ");
}
System.out.println();
t2[0].setVal(100000);
System.out.println("===============");
for(int i = 0;i < t1.length;i++) {
System.out.print(t1[i].getVal()+" ");
}
System.out.println();
for(int i = 0;i < t2.length;i++) {
System.out.print(t2[i].getVal()+" ");
}
}
3.Arrays.copyOf()方法:
同樣看原始碼,它的實現還是基於System.arraycopy(),所以效率自然低於System.arraycpoy()。
public static int[] copyOf(int[] original, int newLength) {
int[] copy = new int[newLength];
System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));return copy;}
例子:public class Arraycopy {
public static void main(String[] args) {
TestArray[] t1 = new TestArray[4];
t1[0] = new TestArray();
t1[1] = new TestArray();
t1[2] = new TestArray();
t1[3] = new TestArray();
TestArray[] t2 = new TestArray[4];//t2[0]
System.arraycopy(t1,0,t2,0,t1.length);
for(int i = 0;i < t1.length;i++) {
System.out.print(t1[i].getVal()+" ");
}
System.out.println();
for(int i = 0;i < t2.length;i++) {
System.out.print(t2[i].getVal()+" ");
}
System.out.println();
t2[0].setVal(100000);
System.out.println("===============");
for(int i = 0;i < t1.length;i++) {
System.out.print(t1[i].getVal()+" ");
}
System.out.println();
for(int i = 0;i < t2.length;i++) {
System.out.print(t2[i].getVal()+" ");
}
}}
public class Arraycopy {
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6,7,8,9};
int[] brray = new int[array.length];
System.arraycopy(array,0,brray,0,array
.length);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(brray));
brray[0] = 1000;
System.out.println("=================");
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(brray));
}
}
(1)copyOf()的實現是用的是arrayCopy();
(2)arrayCopy()需要目標陣列,對兩個陣列的內容進行可能不完全的合併操作。
(3)copyOf()在內部新建一個數組,呼叫arrayCopy()將original內容複製到copy中去,並且長度為newLength。返回copy;
4. Object.clone()方法:
從原始碼來看同樣也是native方法,但返回為Object型別,所以賦值時將發生強轉,所以效率不如之前兩種。
View code1 protected native Object clone()throwsCloneNotSupportedException;
import java.util.Arrays;
public class Clone {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] brray = array.clone();
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(brray));
brray[0] = 1000;
System.out.println("=================");
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(brray));
}
}
由結果可以看出,當對複製陣列的某個元素進行改變時,並不影響被複制陣列對應元素,即對於基本資料型別來說clone()方法實現陣列拷貝也屬於深拷貝。
import java.util.Arrays;
public class Clone {
public static void main(String[] args) {
TestArray[] t1 = new TestArray[4];
t1[0] = new TestArray();
t1[1] = new TestArray();
t1[2] = new TestArray();
t1[3] = new TestArray();
TestArray[] t2 = new TestArray[4];//t2[0]
for (int i = 0; i < t1.length; i++) {
t2[i] = t1[i];
}
for (int i = 0; i < t1.length; i++) {
System.out.print(t1[i].getVal() + " ");
}
System.out.println();
for (int i = 0; i < t2.length; i++) {
System.out.print(t2[i].getVal() + " ");
}
System.out.println();
t2[0].setVal(100000);
System.out.println("===============");
for (int i = 0; i < t1.length; i++) {
System.out.print(t1[i].getVal() + " ");
}
System.out.println();
for (int i = 0; i < t2.length; i++) {
System.out.print(t2[i].getVal() + " ");
}
}
}
由結果可以看出,當對複製陣列的某個元素進行改變時,被複制陣列對應元素也隨之改變,即對於引用資料型別來說clone()方法是淺拷貝。
時間複雜度有:
常數階O(1), 對數階O(log2n), 線性階O(n), 線性對數階O(nlog2n), 平方階O(n^2), 立方階O(n^3),..., k次方階O(n^k), 指數階O(2^n) 。
(1) for(i=1;i<=n;i++) //迴圈了n*n次,當然是O(n^2)
for(j=1;j<=n;j++)
s++;
(2) for(i=1;i<=n;i++)//迴圈了(n+n-1+n-2+...+1)≈(n^2)/2,因為時間複雜度是不考慮係數的,所以也是O(n^2)
for(j=i;j<=n;j++)
s++;
(3) for(i=1;i<=n;i++)//迴圈了(1+2+3+...+n)≈(n^2)/2,當然也是O(n^2)
for(j=1;j<=i;j++)
s++;
(4) i=1;k=0; while(i<=n-1){ k+=10*i; i++; }//迴圈了n-1≈n次,所以是O(n)
(5) for(i=1;i<=n;i++)
for(j=1;j<=i;j++)
for(k=1;k<=j;k++)
x=x+1;
//迴圈了(1^2+2^2+3^2+...+n^2)=n(n+1)(2n+1)/6≈(n^3)/3,不考慮係數,自然是O(n^3)另外,在時間複雜度中,log(2,n)(以2為底)與lg(n)(以10為底)是等價的,因為對數換底公式:log(a,b)=log(c,b)/log(c,a)所以,log(2,n)=log(2,10)*lg(n),忽略掉係數,二者當然是等價的。
練習
將奇數放在偶數前面
import java.util.Arrays;
public class Part {
public static void main(String[] args) {
int[] a = {8,4,1,6,7,4,9,6,4};
sort(a);
System.out.println(a);
System.out.println(Arrays.toString(a)); } // 排序實現
public static void sort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] % 2 == 0) {//能被2整除的數都是偶數,反之為奇數
int j= i + 1;
while (i< a.length) {
if (a[j] % 2 != 0) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
break;
}
j++;
} //說明後面的全部均為偶數,沒必須要往下迴圈。
if (j == a.length) {
break;
}
}
}
}}
一個數組是有序的,給定一個key:數字 有兩個數字的和加起來等於key 找到這兩個數字的下標
import java.util.Scanner;
public class Key {
public static void main(String[] args) {
int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9};
Scanner scanner = new Scanner(System.in);
int key = scanner.nextInt(); //輸入key的值
int i = 0;
int j;
int temp = 0;
for (; i < a.length - 1; i++) { //遍歷一遍陣列
temp = key - a[i]; //確定要尋找的數的值
for (j = i + 1; j < a.length; j++) { //開始查詢temp
if (temp == a[j]) { //如果找到,就輸出出來
System.out.println(key + "等於第" + (i + 1) + "個與第" + (j + 1) + "個數的和");
}
}
}
}
}
一個整形陣列,除了兩個數字只出現一次外
其他數字都是兩次。{1,3,1,2,3,4} 找到這兩個數字
import java.util.Arrays;
import java.util.Scanner;
public class Subscript {
public static void main(String[] args)
{
int[] a={2,4,3,6,3,2,5,5};
int[] a1={0};
int[] a2={0};
FindNumsAppearOnce(a,a1,a2);
}
public static void FindNumsAppearOnce(int [] array,int num1[] , int num2[])
{
if(array==null||array.length==0)
return;
int number=0;
for(int i:array)
{
number^=i;
}
int index=getBit1(number);
int number1=0;
int number2=0;
for(int i:array)
{
if(get1(i,index))
number1^=i;
else
number2^=i;
}
num1[0]=number1;
num2[0]=number2;
System.out.print(num1[0]);
System.out.print(" ");
System.out.println(num2[0]);
}
private static boolean get1(int i, int key)
{
i= i>>key;
return (i&1)==0;
}
private static int getBit1(int number)
{
int key=0;
while((number&1)==0)
{
number=number>>1;
key++;
}
return key;
}
}
熟悉Arrays這個類裡面的方法
Arrays.equals(): 比較兩個陣列是否相同,返回布林;
Arrays.deepEqual(): 進行深度(多維陣列)比較;
Arrays.binerySearch(): 查元素在陣列中的位置;
可以使用二分搜尋法來搜尋指定的陣列,以獲得指定物件,該方法返回要搜尋元素的索引值。
binerySearch()方法提供多種過載形式,用於滿足各種型別的查詢需要。
Arrays.copyOf(): 複製一個數組,就是進行擴容,它可以直接傳回一個新的陣列物件。
跟他相似的有Arrays.copyOfRange()和SystemasList();
Arrays.toString(): 返回一個受指定陣列內容的字串表達形式,和他相似的有Arrays.deepToString();
Arrays.fill(): 用於填充陣列,
fill(a,val)
a是陣列變數,給陣列中的每個值都賦為val
Arrays.Sort(): 將陣列排好序。
根據傳出引數的長度的大小來判斷用哪種排序方法。
如何排序陣列並插入某個元素?
import java.util.Arrays;
public class Interpposition {
public static void maopao(int[] array){
int tmp;//定義一個臨時量
for (int i = 0; i<array.length; i++) {{//外層迴圈控制排序趟數
for (int j = 0; j <array.length-1-i; j++)
{//內層迴圈控制每一趟排序多少次
if(array[j]>array[j+1])
{
tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
//比較兩個相鄰的元素,將值大的元素交換至右端。
}
}
}
}
public static void main(String[] args) {
int[] array = {1,76,28,24,3,6,4,9};
int cha = 22;//插入的數
int[] array1 = new int[array.length+1];
array1[0] = cha;//將要插入的數放在陣列的第一位
System.out.println("原陣列為:");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]+" ");
}//輸出原陣列
System.out.println();
for (int i = 0; i< array.length; i++) {
array1[i+1] = array[i];//插入數字後,將原陣列的數統一後移一位
}
maopao(array1);//使用冒泡法給array1排序
System.out.println("插入後的排序為:");
for (int i = 0; i < array1.length; i++) {
System.out.print(array1[i]+" ");
}
System.out.println();//輸出排序後的新陣列
}
}
如何搜尋陣列中的最小值和最大元素?
import java.util.Arrays;
import java.util.Collections;
public class Big {
public static void main(String[] args) {
int numbers[] = new int[] { 28, 21, 11, 41, 34,69, 15 };
int s = numbers[0];//把第一個數賦值給s;
int l = numbers[0];//把第一個數賦值給l;
for (int i = 1; i < numbers.length; i++) {
if (numbers[i] > l)//如果這個數大於當前的最大數
l = numbers[i];//此時這個數為最大數
else if (numbers[i] < s)//如果這個數小於最小數
s = numbers[i];//此時這個數為最小數
}
System.out.println("Largest Number is : " + l);//輸出最大數
System.out.println("Smallest Number is : " + s)//輸出最小數
}
}
如何合併兩個陣列(合併到一個新的陣列)?
import java.util.Arrays;
public class Combine {
public static void main(String[] args) {
//定義兩個陣列並初始化
int[] a = {1,2,3,4,5};
int[] b = {6,7,8,9,10};
int[] c = new int[a.length+b.length];//引入一個新的陣列
System.arraycopy(a, 0, c, 0, a.length);
//使用Arrays.copyOf()方法將陣列a中的值複製到陣列c中
System.arraycopy(b, 0, c, a.length, b.length);
//使用Arrays.copyOf()方法將陣列b中的值複製到陣列c中
System.out.println(Arrays.toString(c));//輸出陣列c
}
}
}
如何刪除陣列指定元素?
import java.util.Arrays;
import java.util.Scanner;
public class Delet {
public static void main(String[] args) {
//把最後一個元素替代指定的元素,然後陣列縮容
Scanner sc = new Scanner(System.in);//建立一個新物件
int[] arr = new int[]{1, 2, 4, 5, 9, 8, 0};
System.out.println(Arrays.toString(arr));
System.out.println("請輸入要刪除第幾個元素:");
int n = sc.nextInt();
sc.close();
//把最後一個元素替代指定的元素
arr[n - 1] = arr[arr.length - 1];
//陣列縮容
arr = Arrays.copyOf(arr, arr.length - 1);//把縮容後的陣列複製
System.out.println(Arrays.toString(arr));
}
}
如何填充陣列(一次填充,部分填充)?
import java.util.Arrays;
import com.sun.deploy.util.ArrayUtil;
public class Sortxu {
public static void main(String[] agrs){
int array[] = new int[6];//建立新物件
Arrays.fill(array, 100);//一次填充數字100
for (int i=0, n=array.length; i < n; i++) {
System.out.print(array[i] + ",");//輸出填充了的陣列
}
System.out.println();
Arrays.fill(array, 3, 6, 50);//部分填充
for (int i=0, n=array.length; i< n; i++) {
System.out.print(array[i] + ",");//輸出
}
}
}
** 如何從陣列中查詢常見的元素? **
import java.util.Scanner;
public class Find {
public static void main(String[] args) {
//定義並初始化陣列
int[] arr = {22,33,44,55,66,7,2,5,24};
//定義並初始化Scanner物件,用於獲取輸入鍵盤輸入的內容
Scanner scanner = new Scanner(System.in);
//輸出資訊
System.out.print("請輸入需要查詢的數字:");
//獲取鍵盤輸入要查詢的數字
int target = scanner.nextInt();
//迴圈陣列
for(int i = 0; i < arr.length; i++) {
//如果輸入的數字跟當前陣列的元素的值相同
if(target == arr[i]) {
//輸入所在位置,從1開始
System.out.println(target + "位於數字的第" + (i + 1) + "位");
//結束
return;
}
}
//如果找不到的話就提示一下
System.out.println("陣列中不存在數字:" + target);
}
}