Java 基础(数组) 三

462 阅读4分钟

数组

数组是多个相同类型数据一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理

数组常见概念

  • 数组名
  • 元素
  • 下标(索引)
  • 数组的长度(固定):元素的个数

数组的特点

  • 数组是有序排列的
  • 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型
  • 创建的数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址
  • 数组的长度一旦确定,就不能修改
  • 可以通过数组下标的方式调用指定位置的元素

一维数组的使用

一维数组的声明和初始化

调用数组的指定位置的元素

获取数组的长度

遍历数组

数组元素的默认初始化值

数组的内存解析

二维元素的使用

对于二维数组的理解,我们可以看成是一维数组arr1又作为另一个一维数组arr2的元素而存在;其实,从数组底层运行机制来看,没有多维数组。

二维数组的声明和初始化

// 1. 静态初始化
int[][] arr1 = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8}};
// 2.1 动态初始化
String[][] arr2 = new String[3][2]; // 三行,两列
// 2.2 
String[][] arr3 = new String[3][]; // 三行,未知列
// 变化
int[] arr4[] = new int[][]{{1,2}, {3, 4, 5}, {6, 7}};
int[] arr5[] = {{1, 2}, {3, 4, 5}, {6, 7}}; // 类型推断

调用二维数组指定位置的元素

Syetem.out.println(arr1[0][1]); // 2
Syetem.out.println(arr2[1][1]); // null
Syetem.out.println(arr3[1][0]); // NullPointerException
arr3[1] = new String[]{1, 2, 3};
arr3[0] = new String[2];

获取数组的长度

System.out.println(arr4.length); // 3
System.out.println(arr4[0].length); // 2

遍历数组

// 两层 for 循环
for(int i = 0; i < arr4.length; ++i) {
	for(int j = 0; j < arr4[i].length; ++j) {
    	System.out.println(arr4[i][j]);
    }
}

数组元素的默认初始化值

规定:二维数组分为 外层数组元素,内层数组元素

针对初始化方式一:int[][] arr = new int[4][3];

  • 外层元素的初始化值为:地址值
  • 内层元素的初始化值为:与一维数组初始化情况相同

针对初始化方式二:int[][] arr = new int[4][];

  • 外层元素的初始化值为:null(引用类型)
  • 内层元素的初始化值为:error
int[][] arr = new int[4][3];
System.out.println(arr); // 十六进制的地址值 [[I@adc6461
System.out.println(arr[0]); // 十六进制的地址值 [I@46ad435
System.out.println(arr[0][0]); // 0
// float
float[][] arr1 = new float[4][3];
System.out.println(arr1[1]); // [F@ac4131
System.out.println(arr1[1][1]); // 0.0
// booelan false
// String null

数组的内存解析

int[][] arr = new int[4][];
// arr 保存数组首地址
arr[1] = new int[]{1, 2, 3};
// arr[1]元素 保存内存数组首地址,并赋值
arr[2] = new int[4];
arr[2][1] = 30;

小结:

一维数组初始化的两种方式

// 1. 动态初始化
int[] arr1 = new int[5];
// 2. 静态初始化
String[] str1 = new String[]{"Tom", "Jerry", "tage"};
  • 数组一旦初始化,其长度就是固定的,不可修改

二维数组初始化的两种方式

// 1. 
int[][] arr2 = new int[4][5]; // 内层元素个数相同
int[][] arr3 = new int[4][]; // 内层元素个数不同时
// 2.
String[][] str2 = new String[][]{{1, 2}, {3, 4, 5}, {6. 7}};

遍历二维数组

int[][] arr = new int[][]{{1, 2, 3}, {4, 5}, {6, 7, 8}};
for(int i = 0; i < arr.length; ++i) {
	for(int j = 0; j < arr[i].length; ++j) {
    	System.out.print(arr[i][j] + "\t");
    }
    System.out.println();
}

不同类型一维数组元素的默认初始化值

  • 整型: 0
  • 浮点型: 0.0
  • 字符型: 0(ASCII)
  • 布尔型: false
  • 字符串型: null
  • 引用类型: null

数据结构

  • 数据与数据之间的逻辑关系: 集合、一对一、一对多、多对多

  • 数据的存储结构:

    1. 线性表(一对一): 顺序表(数组)、链表、栈(先进后出)、队列(先进先出)

    2. 树形结构(一对多): 二叉树

    3. 图形结构

算法

  • 排序算法

  • 搜索算法

数组中涉及的常见算法

数组元素的赋值(杨辉三角、回形数...)(面试)

// 杨辉三角
class YTri {
	public static void main(String[] args) {
		int[][] arr = new int[10][];

		for(int i = 0; i< arr.length; ++i) {

			arr[i] = new int[i + 1];

			for(int j = 0; j < arr[i].length; ++j) {
				if(j == 0 || j == (arr[i].length - 1)) {
					arr[i][j] = 1;
				}else {
					arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
				}
				System.out.print(arr[i][j] + "\t");
			}

			System.out.println();
		}
	}
}
// 创建一个长度为6的int数组,要求元素的值在 1 - 30 之间随机,并且元素值各不相同
class ArrSJ {
	public static void main(String[] args) {
		int[] arr = new int[6];

		for(int i = 0; i < arr.length; ++i) {

			boolean isWhile = false;

			do {
				int temp = (int)(Math.random() * (30 - 1 + 1) + 1);

				if(i == 0) {
					arr[i] = temp;
				}else {
					isWhile = false;
					for(int j = 0; j < i; ++j) {
						if(arr[j] == temp) {
							isWhile = true;
						}
					}
					if(!isWhile) {
						arr[i] = temp;
						
					}
				}
				
			}while(isWhile);
			
			System.out.print(arr[i] + "\t");
			
		}
	}
}

数值型数组中元素的最大值、最小值、平均值、总和等

// 获取随机的两位数,求最大、最小、平均、总和
// 随机两位整数 (int)(Math.random() * (b - a + 1) + a)
class SumArr {
	public static void main(String[] args) {
		int[] arr = new int[10];
		int min = 0;
		int max = 0;
		int sum = 0;
		for(int i = 0; i < arr.length; ++i) {

			arr[i] = (int)(Math.random() * (99 - 10 + 1) + 10);

			if(i == 0) {
				min = arr[i];
				max = arr[i];
			}else {
				if(min > arr[i]) {
					min = arr[i];
				}
				if(max < arr[i]) {
					max = arr[i];
				}
			}
			
			sum += arr[i];

			System.out.print(arr[i] + "\t");
		}
		System.out.println();
		System.out.println("sum = " + sum + "\t max = " + max + "\t min = " + min);
	}
}

数组的复制、反转、查找(线性查找、二分法查找)(面试)

// 数组复制
int[] arr1 = new[]{1, 8, 6, 4, 5};
int[] arr2 = new[arr1.length];
for(int i = 0; i < arr1.length; ++i) {
	arr2[i] = arr1[i];
    System.out.print(arr2[i] + "\t");
}
// 数组反转
int[] arr = new int[]{1, 5, 7, 8, 0};
for(int i = 0, j = arr.length - 1; i < j; ++i, --j) {
	int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
// 查找
// 1. 线性
String str = String[]{"jj", "gg", "ww", "xx", "oo"};
String str1 = "jj";
int idx = -1;
for(int i = 0; i < str.length; ++i) {
	// str1.equals(arr[i]) 对比字符串是否相同
	if(str1.equals(arr[i])) {
    		System.out.println("指定位置的元素的位置为:" + i);
            idx = i;
            break;
    }
}
if(idx == -1) {
	System.out.println("很遗憾,没有找到!");
}
// 2. 二分法(折半)
// 前提:数据必须有序
class ErFen {
	public static void main(String[] args) {
		int[] arr = new int[]{-8, -6, -3, -2, 1, 3, 5, 8, 9};
		
		int target = -5;
		int start = 0;
		int end = arr.length - 1;

		while(start <= end) {
			int middle = (start + end) / 2;
			
			if(target == arr[middle]) {
				System.out.println("target index = " + middle);
				break;
			}else if(target > arr[middle]) {
				start = middle + 1;
			// }else if(target < arr[middle]) {
			}else {
				end = middle - 1;
			}
		}

		if(start > end) {
			System.out.println("start > end : " + start + " : " + end);
		}
		
	}
}

数组元素的排序算法(面试)

排序:将数据按照关键字值进行某种顺序进行排序,这样的操作称为排序

// 冒泡
class Bubble {
	public static void main(String[] args) {
		int[] arr = new int[]{-9, 5, -2, 3, 0, 8, -12, 6, 46, 88};
	
		for(int i = 0, len = arr.length; i< len - 1; ++i) {
			for(int j = 0, leng = arr.length - 1 - i; j < leng; ++j) {
				if(arr[j] > arr[j + 1]) {
					int temp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = temp; 	
				}
				
			}
		}
		for(int i = 0, len = arr.length; i < len; ++i) {
			System.out.print(arr[i] + "\t");
		}

		System.out.println();

		for(int i = 0, len =  arr.length; i < len - 1; ++i) {
			for(int j = arr.length - 1; j > 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, len = arr.length; i < len; ++i) {
			System.out.print(arr[i] + "\t");
		}
	}
}
// 快速排序

  • 衡量排序算法的优劣

    1. 时间复杂度:分析关键字的比较次数和记录的移动次数

    2. 空间复杂度:分析排序算法中需要多少辅助内容

    3. 稳定性:当A和B的关键字值相等,但排序后A和B的先后次序保持不变,则称这种排序算法稳定

  • 排序算法分类:内部排序和外部排序

    1. 内部排序:整个排序过程不需要借助于外部存储器,所有排序操作在内存中完成

    2. 外部排序:参与排序的数据分厂多,数据量非常大,整个排序过程无法全部放在内存中完成,必须借助于外部存储器(如磁盘);外部排序最常见的是多路归并排序,可认为外部排序是由多次内部排序完成的

  • 十大内部排序算法(前八种常用)

    1. 选择排序

      • 直接选择排序、堆排序
    2. 交换排序

       - `冒泡排序``块速排序`
      
    3. 插入排序

       - 直接插入排序、折半插入排序、Shell(希尔)排序
      
    4. 归并排序

    5. 桶排序

    6. 基数排序

  • 算法的五大特征

    1. 输入

    2. 输出

    3. 有穷型(可接受时间)

    4. 确定性

    5. 可行性(可用纸笔计算结果)

Arrays工具类的使用

import java.util.Arrays;
public class Arrs {
	public static void main(String[] args) {
		int[] arr1 = new int[]{1, 2, 4, 3};
		int[] arr2 = new int[]{1, 2, 3, 4, 6, 5};
		
		// analys A and B is equal
		// 1. boolean equals(int[] a, int[] b)
		boolean isEquals = Arrays.equals(arr1, arr2);
		System.out.println("equals: arr1 == arr2 ? " + isEquals);

		// print out array info
		// 2. String toString(int[] a)
		String arrInfo = Arrays.toString(arr1);
		System.out.println("toString: " + arrInfo); // [1, 2, 4, 3]

		// replace value to all array element
		// 3. void fill(int[] a, int value)
		Arrays.fill(arr1, 8); // [8, 8, 8, 8]
		System.out.println("fill: " + Arrays.toString(arr1));

		// 4. sort(int[] a)
		Arrays.sort(arr2);
		System.out.println("sort: " + Arrays.toString(arr2)); // [1, 2, 3, 4]

		// er fen search
		// int binarySearch(int[] a, int key)
		int[] arr3 = new int[]{1, 3, 5, 7, 8, 10, 18};
		int idx = Arrays.binarySearch(arr3, 9);
		if(idx >= 0) {
			System.out.println("binarySearch: " + idx);
		}else {
			System.out.println("binarySearch: none " + idx);
		}
		
	}
}

数组使用中的常见异常

数组角标越界的异常: ArrayIndexOutOfBoundsException

int[] arr = new int[]{1, 2, 5, 8, 9};
for(int i = 0; i <= arr.length; ++i) {
	System.out.println(arr[i]);
    // i = 5 error: ArrayIndexOutOfBoundsException
}
System.out.println(arr[-1]); // error: ArrayIndexOutOfBoundsException

空指针异常: NullPointerException

// 1.
int[] arr1 = new int[]{1, 2, 3};
arr1 = null;
System.out.println(arr[0]); // error: NullPointerException

// 2.
int[][] arr2 = new int[4][];
System.out.println(arr2[0]); // null
System.out.println(arr2[0][0]); // error: NullPointerException

// 3.
String arr3 = new String[]{"aa", "bb", "cc"};
arr3[0] = null;
System.out.println(arr3[0].toString()); // error: NullPointerException