数组的定义
-
1,java语言中的数组是一种引用数据类型,不属于基本数据类型。数组的父类是Object。
-
2,数组是一个容器,可以同时容纳多个元素。(数组是一个数据的集合)
-
3,数组当中可以存储基本数据类型的数据,也可以存储引用数据类型的数据。
-
4,数组是引用类型,所以数组对象是存在堆内存中的。
-
5,数组当中如果存储的是"java对象"的话,实际上存储的是对象的"引用(内存地址)",数组中不能直接存储java对象。
-
6,数组一旦创建,在Java语言中规定,长度不可变。(数组长度不可变)
-
7,数组分类:一维数组,二维数组,三维数组,多维数组...(一维数组使用较多,二维偶尔使用)
-
8,所有数组对象都有length属性(java自带的),用来获取数组中元素的个数。
-
9,java中的数组要求数组中元素类型统一;比如int类型数组只存储int类型,Person类型数组只存储Person类型。
-
10,数组在内存方面存储的时候,数组中的元素内存地址(存储的每个元素都是有规则的挨着排列的)是连续的,内存地址连续。 这是数组存储元素的特色,数组实际上是一种简单的数据结构。
-
11,数组中首元素的内存地址作为整个数组对象的内存地址。
-
12,数组中每个元素都有下标,下标从0开始,以1递增;最后一个元素的下标是:length - 1。 下标非常重要,我们对数组中元素进行"存取"的时候,都需要通过下标来进行。
-
13,数组的优点和缺点?
优点: 查询/查找/检索某个下标元素时效率极高,可以说是查询效率最高的一个数据结构。 为什么检索效率高? 1,每个元素的内存地址在空间存储上是连续的。 2,每个元素类型相同,所占用空间大小一样。 3,知道第一个元素内存地址,知道每个元素占用空间的大小,知道下标,所有通过一个 数学表达式就可以计算出某个下标元素的内存地址,直接通过内存地址定位元素,所以数组的 检索效率是最高的。 数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,因为数组中元素查找的时候 不会一个一个的找,是通过数学表达式计算出来的。(酸菜一个内存地址,直接定位的) 缺点: 1,由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或增加元素的时候, 效率较低,因为随机增删元素会涉及后面元素统一向前或向后移位的操作。 2,数组不能存储大数据量,因为很难在内存空间上找到一块特别大的连续空间。 注意:对于数组中最后一个元素的增删是没有效率影响的。
-
14,声明/定义一个一维数组
int[] array1; double[] array2; String[] array3; ...
-
15,初始化一个一维数组?
- 两种方式:静态初始化一维数组,动态初始化一维数组。
静态初始化语法格式:
int[] array = {1,2,3,4,5}
动态初始化语法格式:
int[] array = new int[5]; // 5表示数组的元素个数。 // 初始化一个5个长度int类型数组,每个元素默认值0. String[] names = new String[6] // 初始化一个6个长度String类型数组,每个元素默认值null
-
16,什么时候采用静态初始化方式,什么时候采用动态初始化方式?
当你创建数组的时候,确定数组中存储哪些具体元素时,采用静态初始化方式。 当你创建数组的时候,不确定将来数组中存储哪些数据,你可以采用动态初始化的方式,预先分配内存空间。
代码示例
public class Array01 {
public static void main(String[] args) {
//使用静态初始化方式声明一个int类型数组
int[] arr1 = {1,3,4,6,62};
// 数组中的length属性
System.out.println("数组中元素的个数:" + arr1.length);
// 使用下标对数组中的元素进行存取
// 取(读)
System.out.println("数组中第一个元素:" + arr1[0]);
System.out.println("数组中最后一个元素:" + arr1[arr1.length - 1]);
// 存(修改)
// 把第一个元素修改为11
arr1[0] = 11;
// 把最后一个元素修改为119
arr1[arr1.length - 1] = 119;
System.out.println("数组中第一个元素:" + arr1[0]);
System.out.println("数组中最后一个元素:" + arr1[arr1.length - 1]);
//遍历数组
for (int i = 0 ;i < arr1.length; i++ ){
System.out.println(arr1[i]);
}
// 下标为5表示第6个元素,数组中没有第6个元素,越界了;会出现异常
// System.out.println(arr1[6]);//ArrayIndexOutOfBoundsException(数组越界异常)
// 倒序遍历数组
for (int i = arr1.length - 1 ; i >=0 ; i-- ){
System.out.println("倒序-->" + arr1[i]);
}
// -------------------------------------------------------------------------------
// 初始化动态数组
int[] arr = new int[4];
for (int i = 0;i < arr.length; i++){
System.out.println("数组中下标" + i + "的元素是:" + arr[i]);
}
//初始化一个Object类型的数组,采用动态方式初始化
Object[] objs = new Object[3]; // 3个长度,动态初始化,每个元素默认值是null
for (int i = 0 ; i < objs.length; i++){
System.out.println(objs[i]);
}
}
}
数组存储 "引用数据类型"
- 一维数组的深入,数组中存储的类型为:引用数据类型
- 对于数组来说,只能存储java对象的"内存地址"。数组中存储的每个元素是"引用"。
代码示例
public class Array02 {
public static void main(String[] args) {
// 创建一个Animal类型的数组
Animal a1 = new Animal();
Animal a2 = new Animal();
Animal[] animals = {a1,a2};
// 对Animal数组进行遍历
for (int i = 0; i < animals.length; i++){
// Animal a = animals[i];
// a.move();
// 代码合并
animals[i].move();
}
//------------------------------------------------
// 动态初始化一个长度为2的Animal类型的数组
Animal[] animals2 = new Animal[2];
animals2[0] = new Animal();
// Animal数组中可以存储Cat类型数据,因为Cat是一个Animal。
// Cat 是Animal的子类。
animals2[1] = new Cat();
//------------------------------------------------
// 创建一个Animal类似的数组,数组中存储Cat和Bird
Animal[] animals3 = {new Cat(),new Bird()};
// 对Animal数组进行遍历
for (int i = 0; i < animals3.length; i++){
// 调用的方法是父类型中存在的方法不需要向下转型,直接使用父类引用调用即可。
animals3[i].move();
// 调用子类特有方法,父类中没有的方法 需要向下转型(多态)
if (animals3[i] instanceof Cat){
((Cat) animals3[i]).moveCat();
}else if (animals3[i] instanceof Bird){
((Bird) animals3[i]).moveBird();
}
}
}
}
class Animal{
public void move(){
System.out.println("Animal move--");
}
}
class Cat extends Animal{
public void move(){
System.out.println("Cat move--");
}
public void moveCat(){
System.out.println("猫在抓老鼠--");
}
}
class Bird extends Animal{
public void move(){
System.out.println("Bird move--");
}
public void moveBird(){
System.out.println("鸟儿在飞翔--");
}
}
数组的扩容
-
在java开发中,数组长度一旦确定不可变,那么数组满了怎么办?
- 数组满了,需要扩容。
- 先新建一个大容量的数组,然后将小容量数组中的数据一个一个的拷贝到大数组中。
-
数组扩容效率较低,因为涉及拷贝问题。所以在以后的开发中注意:尽可能少的进行数组的拷贝。
-
可以在创建数组对象的时候预估一下多长合适,最好预估准确,这样可以减少数组的扩容次数,提高效率。
代码示例
public class Array03 {
public static void main(String[] args) {
// java中的数组是如何进行拷贝的
// 拷贝源 (从这个数组中拷贝)
int[] arr = {1,3,5,7,6};
// 拷贝目标(拷贝到这个目标数组上)
int[] dest = new int[10];// 每个默认元素为0
// 调用JDK System类中的arraycopy方法,来完成数组的拷贝。
// 将arr数组中的数据从下标1开始,拷贝2个元素
// 放入dest数组中,从下标3开始。
System.arraycopy(arr,1,dest,3,2);
// 将arr数组中的数据全部拷贝到dest数组中,dest数组从下标0开始。
// System.arraycopy(arr,0,dest,0,arr.length);
for (int i = 0;i< dest.length; i++){
System.out.println("dest-->" + dest[i]);
}
}
}
二维数组
-
二维数组其实是一个特殊的一维数组,特殊在这个一维数组当中的每一个元素是一个一维数组。
-
三维数组是一个特殊的二维数组,特殊在这个二维数组中的每一个元素是一个一维数组。实际开发中
使用最多的是一维数组,二维数组也很少使用,三维数组几乎不用。 -
二维数组的静态初始化
int[][] array = {{1,2,3},{4,5,9,6},{5,6,7},...};
代码示例
public class Array04 {
public static void main(String[] args) {
// 一维数组
int[] array = {1,3,2,5,9};
int[] array1 = {32,23,54,95};
int[] array2 = {15,36,22,53,92,23,55};
// 二维数组
// 里面是3个一维数组
int[][]arr = {array,array1,array2};
System.out.println("二维数组长度:" + arr.length);// 3
for (int i = 0;i<arr.length;i++){
System.out.println(arr[i].length);// 输出arr中元素(一维数组)的长度: 5 4 7
}
System.out.println("--------------------------------------------------");
// 取二维数组中第1个元素(一维数组)中的第1个元素
System.out.println(arr[0][0]);
// 取二维数组中第2个元素(一维数组)中的第3个元素
System.out.println(arr[1][2]);
// 取二维数组中第3个元素(一维数组)中的第4个元素
System.out.println(arr[2][3]);
// 修改二维数组中第1个元素(一维数组)中的第1个元素
arr[0][0] = 320;
System.out.println(arr[0][0]);
System.out.println("--------------------------------------------------");
// 遍历二维数组
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("这是第" + (i + 1) + "个一维数组");
}
System.out.println("--------------------------------------------------");
// 动态初始化二维数组
// 3个一维数组,每个一维数组有4个元素
int[][] a34 = new int[3][4];
for (int a = 0;a<a34.length;a++){
for (int j = 0; j < a34[a].length; j++){
System.out.print( a34[a][j] + " " );
}
System.out.println("这是第" + (a + 1) + "个一维数组");
}
}
}
数组--冒泡排序算法
- 每次循环结束之后,都要找出最大的数据,放到参与比较的这堆数据的最右边。(冒出最大的那个气泡。)
- 核心:拿走左边的数字和右边的数字比对,当左边 > 右边,交换位置。
代码示例
public class Sort01 {
public static void main(String[] args) {
int[] arr = {2,8,6,3,1,9,4};
int count = 0;
// 使用冒泡排序算法进行排序
for (int i = arr.length-1 ; i > 0; i--) {
System.out.println("i-->" + i);
for (int j = 0; j < i ; j++) {
System.out.println("j=" + j + ";" + "arr[j]=" + arr[j] + ";" + "arr[j+1]=" + arr[j+1]);
if (arr[j] > arr[j+1]){
count++;
int temp ;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println("交换位置次数:"+ count);
// 排序之后遍历输出
for (int a = 0;a < arr.length;a++){
System.out.println(arr[a]);// 从小到大
}
}
}
数组--选择排序
-
每一次从这堆参与比较的数据当中找出最小值,拿着这个最小值和最前面的元素交换位置。
-
选择排序比冒泡排序好在: 每一次交换位置都是有意义的。
代码示例
public class Sort02 {
public static void main(String[] args) {
int[] arr = {2,8,6,3,1,9,4};
int count = 0;
// 使用选择排序算法进行排序(7条数据循环6次)
for (int i = 0 ; i < arr.length - 1; i++) {
int min = i;
for (int j = i+1; j < arr.length; j++){
if (arr[min] > arr[j]){
min = j;// 最小值元素的下标
}
}
int temp ;
// 当i和min相等时,不交换位置,
// 当i和min不相等是,表示有更小的元素,需要拿更小的元素和最左边的元素交换位置。
if (min != i){
count++;
// arr[min] 最小的元素
// arr[i] 最前面的元素
temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
}
// 相对于冒泡排序 交换位置次数变少了
System.out.println("交换位置次数:"+ count);
// 排序之后遍历输出
for (int a = 0;a < arr.length;a++){
System.out.println(arr[a]);// 从小到大
}
}
}
数组--元素的查找
- 数组元素查找有两种方式:
- 1,一个一个挨着找,直到找到为止。
- 2,二分法查找(算法),这个效率较高。
二分法查找是基于排序的基础之上的。(没有排序的数据是无法查找的)
代码示例
public class Search {
public static void main(String[] args) {
int[] arr ={2,34,55,66,22,42,68,88};
// 需求找到22的下标,如果没找到返回-1
// 一个一个挨着找
int index = ArrSearch(arr,68);
System.out.println(index== -1 ? "该元素不存在!":"该元素的下标是:"+index);
// --------------------------------------------------------------------
// 二分法查找
Arrays.sort(arr);// 对数组进行排序
int index2 = ArrUtilSearch(arr,42);
// 以下写法是sun公司封装好的二分法查询
//int index2 = Arrays.binarySearch(arr,42);
System.out.println(index2== -1 ? "该元素不存在!":"该元素的下标是:"+index2);
}
/**
* 从数组中查找目标元素的下标(二分法查找)
* @param array 被检索的数组(必须是已经排序的)
* @param i 目标元素
* @return -1表示该元素不存在,大于等于0的数表示元素的下标
*/
private static int ArrUtilSearch(int[] array, int i) {
int begin = 0;// 开始下标
int end = array.length -1; // 最后一个元素的下标
while (begin <= end){
int mid = (begin + end) / 2; // 中间元素下标
if (array[mid] == i){
return mid;
}else if (array[mid] < i){
// 目标元素在中间元素的右边
// 开始元素的下标重新赋值
begin = mid + 1;
}else {
// 目标元素在中间元素的左边
// 最后一个元素的下标需要重新赋值
end = mid - 1;
}
}
// 程序执行到此处,表示没有找到元素
return -1;
}
/**
* 从数组中检索某个元素的下标(一个一个的查找)
* @param array 被检索的数组
* @param a 被检索的元素
* @return -1表示该元素不存在,大于等于0的数表示元素的下标
*/
public static int ArrSearch(int[] array,int a){
for (int i = 0;i<array.length;i++){
if (array[i] == a){
return i;
}
}
// 程序执行到此处,表示没有找到元素
return -1;
}
}
网友评论