java 数据结构之数组

一、数组基础、使用、操作

package DataStructures;
import java.util.*;

public class Array_array {
	
	/*
	 * 数组
	 * 定义:数组是一组同种类型的数据的集合
	 * Note:
	 * 1.数组的下标索引是从0开始
	 * 2.数组中的元素可以是任意数据类型,但是所有的元素的类型相同,例如int,float,double,char,String等
	 * 3.常用一维和二维数组,其他的高维数组不经常用,但是使用方法类似
	 * 4.数组是引用数据类型,引用数据类型使用之前要进行声明以及初始化。数组变量不是数组本身,而是指向堆内存中的数组对象
	 * 5.声明一个数组将在内存空间中为其分配一个连续空间,数组的名字代表的是这连续空间的首地址,通过首地址能访问数组中所有元素
	 * 6.数组的使用:声明数组、初始化(分配空间以及赋值)、操作数组
	 * 7.int[] 就是一种数据类型,与 int 类型、String 类型相似,一样可以使用该类型来定义变量,也可以使用该类型进行类型转换等。
	 *   使用 int[] 类型来定义变量、进行类型转换时与使用其他普通类型没有任何区别。int[] 类型是一种引用类型,创建 int[] 类型的
	 *   对象也就是创建数组,需要使用创建数组的语法。
	 */
	public static void main(String[] args) {
		
		//数组的定义和初始化
		//1.声明数组,指定数组的元素类型
		/*
		 * Note:
		 * 1.声明数组变量的时候有两种方式,但是java中更推荐第一种([]括号在元素数据类型之后)
		 * 2.不要忘记括号
		 * 3.此时只是声明数组变量,不需要给定数组的大小
		 */
		//以int类型数组为例
		int[] ar_i_1;
		int ar_i_2[];
		
		//2.分配空间
		/*
		 * Note:
		 * 1.声明数组后,要给数组变量分配存储空间,使用new关键字进行空间分配
		 * 2.[]中为数组长度,当确定数组的大小后,不能更改,且数组长度时必须的
		 * 3.当确定数组的长度后,系统根据数据中的元素的数据类型对数组分配初始值
		 * (1)byte\short\int\long --- 0
		 * (2)float\double --- 0.0
		 * (3)char --- \u0000
		 * (4)boolean --- false
		 * (5)引用类型(类、接口、数组) --- null
		 */
		ar_i_1 = new  int[2];
		ar_i_2 = new  int[5];
		
		//3.赋值
		/*
		 * Note:
		 * 1.数组是一个有序的集合,除了对数组中单个元素单独的赋值,可以通过循环对数组元素进行赋值(操作)
		 */
		ar_i_1[0] = 11;
		ar_i_1[1] = 12;
		for(int i = 0; i < 5; i++) {
			ar_i_2[i] = i;
		}
		
		//数组其他初始化方式
		/*
		 * Note:
		 * 1.数组初始化可以分为两种方式:静态初始化和动态初始化
		 * (1)静态初始化:初始化时由程序员显示的指定数组元素的初始值,由系统决定数组长度
		 * (2)动态初始化:初始化有程序员指定数组长度,由系统为数组元素分配初始值
		 */
		//可以将1和2同时进行,之后再对数组进行赋值
		int[] ar_i_3 = new  int[5];
		//创建数组时同时对数组中元素赋值(使用new)
		/*
		 * Note:
		 * 1.这种初始化方式,不需要指定数组长度,如果指定数组长度并进行赋值,会报错
		 */
		int[] ar_i_4 = new int[] {1,2,3};
		//创建数组时同时对数组中元素赋值(不使用new)
		/*
		 * Note:
		 * 1.使用这种方式时,声明和初始化要同时进行,不能分开(不能省略数组变量的类型)
		 * int[] ar_i_5;
		 * ar_i_5 ={1,2,3};
		 */
		int[] ar_i_5 = {1,2,3};
		
		//二维数组
		/*
		 * Note:
		 * 1.二维数组的定义和初始化差不多,就不想详细解释
		 * 2.二维数组是存储一维数组的数组,即每个元素是一个数组
		 * 3.二维数组可以是不规则的,即每个元素为一个一维数组,每个一维数组的长度可以不一样
		 */
		char[][] ar_c1;
		char ar_c2[][];
		char[][] ar_c3 = new char[][] {{'1','2'},{'3','4'}};//定义时初始化
		char[][] ar_c4 = new char[][] {{'1','2'},{'1','2','3'}};//定义时初始化
		char[][] ar_c5 = new char[2][3];//定义并给定空间,随后进行初始化
		char[][] ar_c6 = new char[2][];//数组的二维长度为空,可以变化
		
		//数组元素的操作
		/*
		 * Note:
		 * 1.java.util包中的Array类包含了操作数组的各种方法,可以直接调用相关的方法,想要了解更多和详细的,可以查看java的API文档
		 * 2.关于对数组的操作,可以根据实际情况或者应用进行变换
		 */
		
		//数组有一个length属性,可以获得数组的长度
		int len_ar = ar_i_1.length;
		
		//数组的遍历或获取数组元素(数组元素查询)
		//获取全部元素(遍历整个数组)
		/*
		 * Note:
		 * 1.一维数组需要一重循环;二维数组需要二重循环....
		 */
		int[] arr1 = new  int[] {1,2,3,4,5,6,1,2,3};
		int[][] arr2 = new  int[][] {{11,12,13},{21,22}};
		PrintAllElement1(arr1);
		PrintAllElement2(arr2);
		
		//获取数组的单个元素
		//已知元素的位置,获取该位置元素的值
		int arr1_value = SelectElementValue1(arr1, 2);
		System.out.println(arr1_value);
		
		int arr2_value = SelectElementValue2(arr2, 1, 1);
		System.out.println(arr2_value);
		
		//已知元素的值,获取元素所在的位置
		/*
		 * Note:
		 * 1.一般通过值查找数组中该元素的位置时,如果数组中存在重复的元素的值,就会有多个位置,有的方法是返回查找的到的第一个元素
		 * 的位置,可以根据需求来更改算法。
		 * 2.返回的是数组的索引,如果需要的数组重元素的位置,需要进行变换
		 * 3.当数组较大时,遍历整个数组耗费时间较长,故可以其他方法减少查找的时间,如二分查找等
		 */
		int arr1_pos = SelectElementPosition1(arr1, 2);
		System.out.println(arr1_pos);
		
		int[] arr2_pos = new int[2];
		arr2_pos = SelectElementPosition2(arr2, 12);
		System.out.println(arr2_pos[0] + " " + arr2_pos[1]);
		
		//数组扩容(数组元素增加)
		/*
		 * 
		 * Note:
		 * 1.创建数组后,数组的大小不能更改,但申请一个较大的空间,会造成空间的浪费
		 * 2.扩容方法:思想就是创建一个新的长度的数组,并将原来的数组复制过去
		 * (1)通过创建新的数组同时增加数组的长度
		 * (2)Arrays.copyOf(原数组名,新的数组的长度)
		 * (3)System.arraycopy(原数组名,起始下标,新数组名,起始下标,复制长度)
		 */
		int[] arr3 = new int[10];
		arr3 = ArrayCapacity(arr1, 10);
		for(int i = 0; i < arr3.length; i++)
			System.out.print(arr3[i] + " ");
		System.out.println();
		
		int[] arr4 = Arrays.copyOf(arr1, 10);
		for(int i = 0; i < arr4.length; i++)
			System.out.print(arr4[i] + " ");
		System.out.println();
		
		int[] arr5 = new int[20];
		System.arraycopy(arr1, 0, arr5, 0, arr1.length);
		for(int i = 0; i < arr5.length; i++)
			System.out.print(arr5[i] + " ");
		System.out.println();
		
		//数组元素删除
		/*
		 * Note:
		 * 1.数组元素被删除后,数组的长度发生变化,可以根据数组扩容的思想进行相应的操作(需要新的存储空间),也可以进行覆盖(不许新的存储空间)
		 * 2.第一种方法简单容易理解,删除元素后,数组还保持原先的顺序,但是需要开辟新的存储空间,而且需要知道新的开辟的空间的大小
		 * 3.第二种方法是通过删除这个元素后,后边的元素去覆盖这个位置的元素
		 * (1)有序:被删除位置元素之后的元素依次向前移动进行覆盖
		 * (2)无序:可以选择从数组最后边选择元素进行覆盖
		 * 4.可以根据索引删除数组元素,也可以根据元素值删除
		 * (1)根据索引删除,可以明确知道删除元素的个数
		 * (2)根据元素的值来删除数组元素(删除的元素有多个重复的,使用创建新数组的方法不知道新数组的大小,使用覆盖的方法会更方便)
		 */
		int[] arr6 = new int[arr1.length - 1];
		arr6 = RemoveElement1(arr1, 1);
		PrintAllElement1(arr6);

		int arr_po = RemoveElement2(arr1, 1);
		for(int i = 0; i < arr1.length - arr_po; i++)
			System.out.print(arr1[i] + " ");
		System.out.println();
		
		//数组元素修改
		/*
		 * Note:
		 * 大多数情况下是根据索引进行数组元素的值的修改,其他情况以后想到了在更新
		 */
		arr1[1] = 9;
		for(int i = 0; i < arr1.length; i++)
			System.out.print(arr1[i] + " ");
		System.out.println();
		
		//数组复制
		/*
		 * Note:
		 * 1.使用循环,一个一个元素的赋值
		 * 2.System.arraycopy()
		 * 3.Arrays.copyOf()
		 * 4.Object.clone()
		 * 效率:System.arraycopy() > Object.clone() > Arrays.copyOf() > 循环
		 * 1、2、3之前都用到过,就省略了,主要说说4
		 */
		int[] arr7 = new int[9];
		arr7 = arr1.clone();
		for(int i = 0; i < arr7.length; i++)
			System.out.print(arr7[i] + " ");
		System.out.println();
		/*
		 * Note:
		 * 还有一些会用直接赋值的方法,这是对数组的引用,指向同一个数组(对象),当对数组进行修改时,原数组也会发生变化
		 */
		int[] arr8;
		arr8 = arr1;
		for(int i = 0; i < arr8.length; i++)
			System.out.print(arr8[i] + " ");
		System.out.println();
		//Object.hashCode() 默认返回内存地址
		System.out.println(arr1.hashCode());
		System.out.println(arr8.hashCode());
		
		//数组连接
		/*
		 * Note:
		 * 根据需求的不同可以进行数组合并,简单的数组合并、去重合并、排序合并、去重并排序合并等等;
		 * 这里就简单的进行合并,后面可以根据需求进行合并;
		 * 合并的方法也有很多种,这里就根据前面提到的进行合并
		 */
		int[] arr9 = new int[] {9,8,7,6};
		int[] arr10 = new int[arr1.length + arr9.length];
		//将arr1数组复制到arr10中
		System.arraycopy(arr1, 0, arr10, 0, arr1.length);
		//将arr9数组复制到arr10中,接着arr1
		System.arraycopy(arr9, 0, arr10, arr1.length, arr9.length);
		for(int i = 0; i < arr10.length; i++)
			System.out.print(arr10[i] + " ");
		System.out.println();
		
		//数组反转
		/*
		 * Note:
		 * 1.可以将数组倒序复制到新的数组中
		 * 2.可以将数组的首尾相应元素互换,直至数组倒序
		 */
		int[] arr11 = new int[9];
		arr11 = ReverseArray1(arr1);
		for(int i = 0; i < arr11.length; i++)
			System.out.print(arr11[i] + " ");
		System.out.println();
		
		int[] arr12 = new int[9];
		arr12 = ReverseArray2(arr1);
		for(int i = 0; i < arr12.length; i++)
			System.out.print(arr12[i] + " ");
		System.out.println();
		
		//数组比较
		/*
		 * Note:
		 * 数组比较(是否相等,数组大小等),可以通过循环对相应位置的元素逐一比较,但是不能直接arr1==arr9进行比较
		 * java中Arrays类提供了比较的方法,可以直接调用
		 */
		System.out.println(Arrays.equals(arr1, arr9));
		
		//数组排序
		/*
		 * Note:
		 * 数组排序,有很多的方法,之后会专门在复习相关的排序算法,这里就不多讲了
		 * java中Arrays类提供了排序的方法,可以直接调用
		 */
		Arrays.sort(arr1);
		for(int i = 0; i < arr1.length; i++)
			System.out.print(arr1[i] + " ");
		System.out.println();
		
		//数组中经常出现的异常
		/*
		 * Note:
		 * 1.NullPointerException 空指针异常
		 * 原因:引用类型变量没有指向任何对象,而访问了对象的属性或者是调用了对象的方法
		 * 2.ArrayIndexOutOfBoundsException 索引值越界
		 * 原因:访问了不存在的索引值。
		 */
		
	}
	//获得一维数组全部的元素
	public static void PrintAllElement1(int[] arr) {
		for(int i = 0; i < arr.length; i++)
			System.out.print(arr[i] + " ");	
		System.out.println();
	}
	//获得二维数组全部的元素
	public static void PrintAllElement2(int[][] arr) {
		for(int i = 0; i < arr.length; i++) {
			for(int j =0 ; j < arr[i].length ; j++ ) {
				System.out.print(arr[i][j] + " ");
			}
			System.out.println();
		}
	}
	//查找数组中的元素---一维数组(已知位置,查找值)
	/*
	 * Note:
	 * 我们的习惯是从1开始,但是数组中是从0开始,要进行换算
	 */
	public static int SelectElementValue1(int[] arr, int pos) {
		int value = arr[pos - 1];
		return value;
	}
	//查找数组中的元素---二维数组(已知位置,查找值)
	public static int SelectElementValue2(int[][] arr, int xpos, int ypos) {
		int value = arr[xpos - 1][ypos - 1];
		return value;
	}
	//查找数组中的元素---一维数组(已知值,查找位置(返回第一个元素的位置))
	public static int SelectElementPosition1(int[] arr, int value) {
		int pos = 0;
		for(int i = 0; i < arr.length; i++) {
			if(arr[i] == value) {
				pos = i;
				break;
			}
		}
		//返回的是元素在数组中的索引
		return pos;
	}
	//查找数组中的元素---二维数组(已知位置,查找值)
	public static int[] SelectElementPosition2(int[][] arr, int value) {
		int[] pos = new int[2];
		for(int i = 0; i < arr.length; i++) {
			for(int j = 0; j < arr[i].length; j++) {
				if(arr[i][j] == value) {
					pos[0] = i;
					pos[1] = j;
					break;
				}
			}
		}
		return pos;
	}
	//数组扩容--第二个参数是扩容数组的长度
	public static int[] ArrayCapacity(int[] arr, int len) {
		int[] arr1 = new int[len];
		for(int i = 0; i < arr.length; i++) {
			arr1[i] = arr[i];
		}
		return arr1;
	}
	//删除元素--根据索引删除
	public static int[] RemoveElement1(int[] arr, int pos) {
		//根据索引删除元素,传入几个索引就减去几个空间(Note:可以加入判断索引值是否越界)
		int[] arrNew = new int[arr.length - 1];
		int j = 0;
		for(int i = 0; i < arr.length; i++) {
			if(i != pos) {
				arrNew[j] = arr[i];
				j++;
			}
		}
		return arrNew;
	}
	//删除元素--根据元素删除
	public static int RemoveElement2(int[] arr, int ele) {
		int pos = 0;
		for(int i = 0; i < arr.length; i++) {
			if(arr[i] == ele) {
				pos++;
				for(int j = i; j < arr.length - pos; j++) {
					arr[j] = arr[j + 1];
				}
			}
		}
		return pos;
	}
	//数组逆序(反转)--法一
	public static int[] ReverseArray1(int[] arr) {
		int[] arrNew = new int[arr.length];
		int j = 0;
		for(int i = arr.length - 1; i >= 0; i--) {
			arrNew[j] = arr[i];
			j++;
		}
		return arrNew;
	}
	//数组逆序(反转)--法二
	public static int[] ReverseArray2(int[] arr) {
		for(int i = 0; i < arr.length; i++) {
			int temp;
			temp = arr[i];
			arr[i] = arr[arr.length - 1 - i];
			arr[arr.length - 1 - i] = temp;
		}
		return arr;
	}
}

二、Arrays类

1.简介

该类包含用于操作数组的各种方法(如排序和搜索)。 该类还包含一个静态工厂,可以将数组视为列表。如果指定的数组引用为空,则该类中的方法都抛出一个NullPointerException ,除非另有说明。如果想要看更详细的内容可以查看java的API文档。

static String toString(type[] a)

返回指定数组的内容的字符串表示形式。

static void sort(type[] a, int fromIndex, int toIndex)

按照数字顺序排列指定的数组(可以指定范围,默认升序)

static void parallelSort(type[] a,int fromIndex, int toIndex)

按照数字顺序排列指定的数组(可以指定范围)

static int hashCode(type[] a)

根据指定数组的内容返回哈希码

static void fill(type[] a, int fromIndex, int toIndex, type val)

将指定类型的元素分配给指定数组的每个元素(可以指定范围)

static boolean equals(type[] a, type[] a2)

如果两个指定的数组彼此 相等 ,则返回 true 。

static int[] copyOf(int[] original, int newLength)

复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。

static int[] copyOfRange(int[] original, int from, int to)

将指定数组的指定范围复制到新数组中。

static type binarySearch(type[] a, type key)

使用二叉搜索算法搜索指定数组的指定值。

static type binarySearch(type[] a, int fromIndex, int toIndex, type key)

使用二叉搜索算法搜索指定值的指定数组的范围。

上一篇:归并排序+面试题


下一篇:C# 数组的声明和初始化