数组拷贝的方法有四种
分别为: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);
}
}