------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
目录:一、数组的定义 二、数组的内存分配及特点 三、数组操作常见问题
四、数组操作常见操作 五、数组中的数组
一、数组的定义
概念:
同一种类型数据的集合。其实,数组就是一个容器。
数组的好处:
可以自动给数组中的元素从0开始编号,方便操作这些元素。
格式1:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
int arr[] = new int[5];
格式2:
元素类型[] 数组名 = new 元素类型[]{元素,元素,……};
int arr[] = new int[]{1,2,3,4,5};
二、数组的内存分配及特点
int[] arr = new int[4];
内存分配图:
内存的划分:
1.寄存器。
2. 本地方法区。
3. 方法区。
4. 栈内存。
用于存储局部变量,当变量所属的作用域一旦结束,所占空间会自动释放。
5. 堆内存。
数组和对象,通过new建立的实例都存放在堆内存中。
每一个实体都有内存地址值。实体中的变量都有默认初始化值,根据类型的不同而不同。整数类型是0,小数类型是0.0或0.0f,boolean类型是false,char类型是'\u0000'。
如果将数组的引用实体设置为null,也就是实体不再被使用,那么会在不确定的时间内被垃圾回收器回收。
三、数组操作常见问题
数组脚标越界异常(ArrayIndexOutOfBoundsException):访问到了数组中的不存在的脚标时发生。
空指针异常(NullPointerException):当引用型变量没有指向任何实体时,用其操作实体,就会发生该异常。
P.S.
直接打印数组的引用变量,打印出来的结果是数组初始地址的哈希值。
四、数组操作常见操作
对数组操作最基本的动作就是存和取。
核心思想:就是对角标的操作。
遍历并打印数组元素:
示例:遍历并打印数组元素
package com.itheima;
class Test{
public static void main(String[] args) {
int[] arr = {89,34,270,17};
for(int x = 0; x < arr.length; x += 1){
System.out.println("arr[" + x + "] = " + arr[x] + ";");
}
}
}
常见操作一:获取最值(最大值,最小值)
思路
1、需要进行比较,并定义变量记录住每次比较后较大的值。
2、对数组中的元素进行遍历取出,和变量中记录的元素进行比较。如果遍历到的元素大于变量中记录的元素,就用变量该记录住大的值。
3、遍历结果,该变量记录就是最大值。
两个明确:
明确一:有结果。是数组中的元素:int类型。
明确二:未知内容。数组。
package com.itheima;
import java.util.Scanner;
class Test{
public static void main(String[] args) {
int[] arr;
arr = new int[5];
System.out.println("please input:");
for(int i = 0;i < 5;i++){
Scannersc= newScanner(System.in);
arr[i] = (int)sc.nextInt();
}
int max = getMax(arr);
System.out.println("The max is:"+max);
}
public static int getMax(int[] arr){
int maxElement = arr[0];
for(int i = 0;i < arr.length;i++){
if(arr[i] > maxElement)
maxElement = arr[i];
}
return maxElement;
}
}
常见操作二:排序(选择排序,冒泡排序)
选择排序
思路:
1、首先拿数组第一个元素依次与除其自身外的其他每个元素顺序比较,如果第一个元素大于剩下的某个元素,就互换内容。
2、经过第一轮比较之后,此时,第一个元素就是数组中最小的元素。然后再拿第二个元素与除第一个元素和其自身的元素进行比较,如果第二个元素大于剩下的某个元素,就互换内容。此时,第二个元素就是数组中倒数第二小的元素。
3、依次类推,直到最后一个元素。
package com.itheima;
import java.util.Scanner;
class Test{
public static void main(String[] args) {
int[] arr;
arr = new int[5];
System.out.println("please input:");
for(int i = 0;i < 5;i++){
Scannersc= newScanner(System.in);
arr[i] = (int)sc.nextInt();
}
System.out.print("排序前数组:" );
printArray(arr);
selectSort(arr);
System.out.print("排序后数组:" );
printArray(arr);
}
public static void selectSort(int[] arr){
for(int x = 0; x < arr.length - 1; x++){
for(int y = x + 1; y < arr.length; y++){
if(arr[x] > arr[y]){
int temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
}
}
publicstaticvoidprintArray(int[]arr){
System.out.print("[" );
for(int x = 0; x < arr.length; x++){
if(x != arr.length - 1)
System.out.print(arr[x] + "," );
else
System.out.println(arr[x] + "]" );
}
}
}
P.S.
1、上面的selectSort方法之所以不用返回int数组的原因是因为:arr引用变量是对传入selectSort方法中作为参数的数组的引用,selectSort方法执行完毕之后,我们依然可以通过arr引用变量操作传入的数组。所以,没有必要再通过返回值获取。
2、上面的选择排序算法效率比较低,因为数组每一个元素与剩下的元素比较就是为了获得最小的元素并且与之互换。例如:{89,34,-270,17,3,100}这个数组,第一轮就要互换4次才能使第一个元素存储的是这个数组中最小的元素。如果是这样,那么更高效率的方式则是只需要通过两个变量,一个记录最小值,一个记录最小值所在的角标即可。等当前元素与余下的所有元素比较完,直接互换,这样只需互换一次就能达到目标,效率自然就会提高。
public staticvoidselectSort(int[]arr){
for(int x = 0; x < arr.length - 1; x++){
int num= arr[x];
int index = x;
for(int y = x + 1; y < arr.length; y++){
if(num > arr[y]){
num = arr[y];
index = y;
}
}
//如果最小的就是自己,就没有必要执行swap操作
if(index != x)
swap(arr,x,index);
}
}
publicstaticvoidswap(int[]arr,inta,int b){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
冒泡排序
思路:
1、首先在第一轮排序中,数组从第一个元素到倒数第二个元素依次与其右边的元素进行比较,如果左边的元素大于右边的元素,那么两个元素就互换。
2、经过第一轮比较,最大的元素就已经存储到数组最右边的结点中了。
3、第二轮排序则是从第一个元素到倒数第三个元素依次与其右边的元素进行比较,如果左边的元素大于右边的元素,那么两个元素就互换。
4、依照此方式,一直到只有第一和第二个元素互相比较而结束。
publicstaticvoidbubbleSort(int[]arr){
for(int x = 0; x < arr.length - 1; x++){
for(int y = 0; y < arr.length - 1 -x; y++){
if(arr[y] > arr[y+1]){
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] =temp;
}
}
}
}
常见操作三:折半查找(二分查找)
简单遍历查找方式
package com.itheima;
class Test{
publicstaticvoidmain(String[] args){
int[] arr= {4,1,5,7,8,4,2};
int index = getIndex(arr,2);
System.out.println("index = " + index);
}
publicstaticintgetIndex(int[]arr,intkey){
for(int x = 0; x < arr.length; x++){
if(arr[x] == key)
return x;
}
return -1;
}
}
P.S.
如果一个数组是无序的,那么可以通过简单遍历查找的方式查找到某个元素所在的角标。但是如果一个数组是有序的,那么就可以通过一种更高效的方式达到相同的目的,也就是二分查找。
思路:
1、设置三个变量记录角标:min、max、mid。min初始值为0,max为数组最大角标,mid为(max+min)/2。
2、查看mid角标的元素是否与待查找的值相等,如果相等,则直接返回角标值,程序终止执行。
3、如果待查找的值小于角标为mid的元素值,那么说明待查找的元素的位置可能在min与mid角标之间。设置max = mid - 1,mid = (max +min)/2,重复第1、2步的操作。
4、如果待查找的值大于角标为mid的元素值,那么说明待查找的元素的位置可能在mid与max角标之间。设置min = mid + 1,mid = (max +min)/2,重复第1、2步的操作。
5、如果数组中不存在待查找的元素,那么按照如上流程,最终min 角标值会大于max角标值,此时返回-1。
public staticintbinarySearch(int[]arr,intkey){
int max,min,mid;
min = 0;
max =arr. length- 1;
mid = (max + min)/2;
while(arr[mid]!=key){
if(key > arr[mid])
min = mid + 1;
else if (key< arr[mid])
max = mid - 1;
if(max < min)
return -1;
mid = (max + min)/2;
}
return mid;
}
P.S.
给定一个有序的数组,如果往该数组中存储一个元素,并保证这个数组还是有序的,那么这个元素的存储的角标如何获取?
可以先通过二分查找,返回min的值,然后将待插入元素存在角标为min的数组位置,数组中角标为min以及比min大的角标所在的数组元素全部往后顺延一个位置。
publicstaticintbinarySearch(int[]arr, intkey){
int max,min,mid;
min = 0;
max = arr. length - 1;
while(min <= max){
mid = (max + min) >> 1;
if(key > arr[mid])
min = mid + 1;
else if (key < arr[mid])
max = mid - 1;
else
return mid;
}
return min;
}