1.数组的简介
数组,是一种比较重要的数据结构,是用来存储一堆类型相同并且是有序的数据的容器(集合)。我们可以通过数组名以及一个不会越界的下标值(索引)来访问其中的元素。
数组,没有固定的类名,每一个数组都是对象。(基本数据类型的数据,称为值,不是对象)
数组的其他特点:
1.数组是一个固定长度的容器,长度一旦固定,将不能够改变。
2. 数组的长度,代表了数组中能够存储多少个元素,类似于容器的容量
3. 元素,即存储在数组中的每一个数据,称为是数组的元素。
2.数组的实例化
在定义一个数组时,要使用[ ],可以理解为要存储一堆数据。
定义数组的方法(即实例化):
1.使用new关键字的两种方式:(即动态初始化)
第一种方式: new+直接初始化具体元素
//new+直接初始化具体元素
String[] names = new String[]{"小红","小明","小强","张三","李四"};
第二种方式:new+长度
int[] nums = new int[5]; // byte,short,int,long对应的默认元素是0
System.out.println(Arrays.toString(nums));
double[] prices = new double[5]; // float double 对应的默认元素0.0
System.out.println(Arrays.toString(prices));
char[] chars = new char[5]; //char 对应的默认元素 \u0000
System.out.println(Arrays.toString(chars));
boolean[] bools = new boolean[5]; //boolean 对应的默认元素 false
System.out.println(Arrays.toString(bools));
String[] adds = new String[5]; //引用类型 对应的默认元素 null
System.out.println(Arrays.toString(adds));
2.静态初始化
数据类型[] 变量 = {元素1,元素2,...元素n}
注意:该方式不能先声明,在初始化
//使用静态初始化的方式,实例化一个数组, 注意:该方式不能先声明,再初始化
int[] numbers = {1,2,3,4,5};
3.数组元素的访问
(1).访问数组中的元素
数组一旦实例化后,就可以通过下标对数组中的元素进行访问。
下标:元素在数组中存储时候的索引(index),用来记录元素在数组中的位置
数组的访问 : 变量名.[index]
数组的长度: 数组变量名.length,比如names.length
,注意,length后面没有小括号。
public static void main(String[] args) {
String str = "hello world ";
System.out.println(str.length());//12 //后面带小括号可以用来查看字符串的长度
int[] arr = new int[5];
System.out.println(arr.length);//5 //不带小括号,查看数组的长度
}
下标从0开始,因此最后一个元素的下标是length-1
(2).常见的异常
1.数组下标越界异常:ArrayIndexOutOfBoundsException
该异常是在运行期间发生的,是因为输入的下标大于或等于数组的长度或者是小于0
运行时出现该异常,如果不做任何处理操作,那么jvm会暴力终止该程序。
2.空指针异常:NullPointerException
运行期间发生的 ,使用null去访问各种方法或者属性
比如: null.length() null.name等等操作
空指针异常以及处理的情况:
4.数组的常见操作
(1)遍历数组
1.使用for循环,遍历下标
public static void main(String[] args) {
int[] nums = {1,2,3,4,5,6};
//使用经典for循环,通过下标进行遍历
for (int i = 0; i < nums.length; i++) {
//i充当下标
System.out.print(nums[i]+" ");
}
}
2.使用foreach循环:也叫增强for循环。底层使用的是迭代器。
for(数据类型 变量名:遍历目标){
}
数据类型是指该数组的类型,遍历的目标可以是数组,集合,枚举等
public static void main(String[] args) {
int[] nums = {1,2,3,4,5,6};
//使用foreach循环遍历上面的数组nums
for(int n:nums){
System.out.print(n+" ");
}
}
总结: 比较两者的区别
- 增强for循环中,没有下标的概念
- 增强for循环中,不能对数组中的元素进行改动
- 增强for循环比遍历下标的执行效率要高
5.元素的排序
(1)选择排序
思想:
第一轮:拿0索引处的元素与后面的元素一一做比较,满足条件就交换。每次交换都保证0索引处是较小值。 一轮结束,0索引处,就是最小值
第二轮:拿1索引处的元素与后面的元素一一做比较,满足条件就交换。每次交换都保证1索引处是较小值。 一轮结束,1索引处,就是第二最小值
。。。。。。每轮依次比较下去。
比较的轮数: 元素个数-1
代码实现:
public static void selectionSort(int[] nums) {
//控制着轮数
for (int i = 0; i < nums.length -1 ; i++) {
//控制着每轮的比较
for (int j = i+1; j < nums.length ; j++) {
// nums[i]: 就是每轮要判断是否是最小的元素的位置。
// nums[j]: 就是依次要比较的后续元素
if(nums[i] > nums[j]){ //条件成立,做交换操作
//定义一个临时变量,保存i处的元素
int temp = nums[i];
// 将j处的元素存储i处
nums[i] = nums[j];
// 将临时变量里的原i处的元素,放入j处。
nums[j] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
}
(2)插入排序
思想:把第一个元素看成是已经排好序的,从第二个元素开始把元素存起来,分别和他前面的元素依次从右到左的进行比较,如果小于前面的元素则要进行插入,前面的元素向后移动,一直到最后一个元素
代码实现:
public static void insertionSort (int[] nums) {
int j;
// 从下标1开始,拿到对应的元素。 0位置上的元素是已经排好序的。
for (int i = 1; i < nums.length ; i++) {
int temp = nums[i]; // 把该元素存起来
// 从后面依次向前查找待插入的位置
for (j = i-1; j>=0 && temp < nums[j]; j--) {
// j位置上的元素比temp大,说明j位置的元素要向后移动,空出位置。
nums[j+1] = nums[j];
}
//循环退出时,j位置的元素应该小于或等于temp.那么j+1就是待插入的位置
nums[j+1] = temp;
}
System.out.println(Arrays.toString(nums));
}
(3)冒泡排序
冒泡排序:
从左到右,紧挨着的两个元素进行比较,满足条件就交换。
数组里有6元素。
第一轮: 能找到最大值,冒泡到最右边。 比较五次
第二轮: 第二大元素冒泡到倒数第二个为止比较4次
.............
第五轮: 第五大元素冒泡的正数的第二个为止。 最后一个数不再需要比较了
注意: 每一轮比较时,都是从最左边的两个元素开始的。
public static void bubbleSort(int[] nums) {
for (int i = 0; i < nums.length-1; i++) {
//内层是控制着每轮如何比较. 每次都要从左边开始比较,因此j从0开始
for (int j = 0; j < nums.length-1-i ; j++) {
// 如果前面的大于后面的,就做交换操作
if (nums[j] > nums[j+1]) {
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
System.out.println(Arrays.toString(nums));
}
(4)顺序查找法查找元素
思想:定义一个下标index,遍历整个数组中的元素,如果找到想找的元素则返回该元素的下标,否则返回-1。
代码实现:
public static int searchElement(int[] arr, int element) {
int index = -1;
for (int i = 0; i < arr.length; i++) {
if(arr[i] == element){
index = i;
break;
}
}
return index;
}
(5)二分查找法查找元素
思想:把0索引处的下标设为min,把最后一个元素的下标作为max,然后取两者的中间值mid,用mid处的元素和要查找的元素做对比,如果是直接输出mid,如果要查找的元素比mid处的元素要大,那么把mid+1作为下一轮比较的min,在和max取中间值mid(min<max),再进行比较,直到找到或返回-1;如果要查找的元素比mid处的元素要小,那么把mid-1作为下一轮比较的max,在和max取中间值mid(min<max),再进行比较,直到找到或返回-1。
代码实现:
public static int binarySearch(int[] arr, int element) {
int min = 0, max = arr.length - 1;
// min<=max时,表示还没有找到该元素, min=max时,是最后一次查找
while (min <= max) {
// 找到中间的元素下标
int mid = (min + max) / 2;
if (arr[mid] == element) {
//如果mid位置上的元素就是我们要找的,就返回下标
return mid;
}else if (arr[mid] < element) { // 表示要找的元素,在中间值的右侧
min = mid + 1; //将min设置为中间下标+1. 然后重新循环
}else { //表示要找的元素,在中间值的左侧
max = mid - 1; //将max设置为中间下标-1. 然后重新循环
}
}
//循环结束都没有遇到return,说明没有找到,就返回-1
return -1;
}
6.Arrays工具类的用法
(1) toString():
将数组转换为字符串形式。 "["+元素1+","+元素2+","+.....+"]"
直接用来输出数组:
public static void main(String[] args) {
int[] nums = {9,2,15,4,35,6};
System.out.println(Arrays.toString(nums));
}
(2). binarySearch():
在已排序的数组中查找指定元素的索引。
注意:该方法只能对已经升序排序的数组进行操作。
public static void main(String[] args) {
int[] nums = {2,3,4,5,6,7};
System.out.println(Arrays.binarySearch(nums,5));
}
(3). fill():
将数组的所有元素都设置为指定值。
public static void main(String[] args) {
int[] nums = new int[5];
//使用指定元素,填满整个数组
Arrays.fill(nums,100);
System.out.println(Arrays.toString(nums));//[100,100,100,100,100]
}
4. sort(数组):
对数组进行排序。这个排序是升序排序
//Arrays.sort(数组名): 只能对已经提前设置好排序规则的类的数组进行排序。
int[] nums2 = {2,3,4,1,5};
Arrays.sort(nums2);
System.out.println(Arrays.toString(nums2));
5. copyOf():
将一个数组的部分或全部元素复制到一个新数组中。
public static void main(String[] args) {
int[] nums = {1,2,3,4,5};
int[] nums2 = {2,3,4,1,5};
// 扩容: 将源数组的所有元素都拷贝到新数组的最前面,然后多余的位置是默认值, 注意:返回的 是一个新的数组
int[] nums3 = Arrays.copyOf(nums2,10); // [2,3,4,1,5,0,0,0,0,0]
System.out.println(Arrays.toString(nums3));
// 指定的长度一样,因此可以理解为,完全拷贝。新数组和源数组一模一样
int[] nums4 = Arrays.copyOf(nums2,nums.length); // [2,3,4,1,5]
System.out.println(Arrays.toString(nums4));
// 指定的长度小于源数组的长度,可以理解为部分拷贝。注意是从头开始拷贝
int[] nums5 = Arrays.copyOf(nums2,3);
System.out.println(Arrays.toString(nums5));//[2,3,4]
}