1、数组
1.1、概念
数组是同一种类型数据
的集合;即能够存放多个相同类型的数据的容器。
在Java中数组属于引用类型,即数组是一个对象。这里的数据类型不仅含八大基本数据类型,还包含引用数据类型,如数组里面可以存数组,数组里面可以存放字符串。
1.2、数组定义方式
数组是存放多个数据的容器,Java中需要使用new
关键字来创建容器,在创建容器时也要明确容器的大小,即容器中存放数据个数。
有以下格式:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
int[] arr = new int[3];//通过new关键字创建了一个长度为3,元素类型是int的数组实体。
元素类型 数组名[] = new 元素类型[]{元素1,元素2,....元素n};
元素类型 数组名[] = {元素1,元素2,....元素n};
1.3、数组内存
栈内存:用于存储局部变量,当数据使用完,所占空间会自动释放。
堆内存:数组和对象,通过new建立的实例都存放在堆内存中。
方法区:静态成员、构造函数、常量池、线程池
方法体中引用变量和基本变量都在栈上,其他都在堆中。
局部变量的引用型:会把对象存在堆中,而把引用存在栈中。
1.4、数组作用(用途)
在程序中常常需要使用数组,利用循环可以对数组中的数据进行批量操作,大大提高了效率,十分方便。
数组可以存储多个数据,而且可以对数据进行编号,从0开始。操作元素完成可以通过编号(索引)完成。
1.5、数组常见问题
1.5.1、数组角标越界异常
public class Demo10 {
public static void main(String[] args) {
int arr[] = new int[3];
System.out.println(arr[3]);
}
}
1.5.2、数组空指针异常
public class Demo10 {
public static void main(String[] args) {
int arr[] = new int[3];
//System.out.println(arr[3]);
arr = null;
System.out.println(arr[3]);
}
}
1.6、数组应用
1.6.1、数组遍历
数组遍历:
从角标0开始,主键递增的方位角标对应的每一位元素。
public class Demo{
public static void main(String[] args) {
int nums[] = {12,5,87,14,26};// 角标:0 1 2 3 4
for (int i = 0;i<5;i++){
System.out.println(nums[i]);
}
// Arrays.toString 快速打印数组内容 会打印 []
System.out.println(Arrays.toString(nums));
}
}
但是如果数组的内容异常庞大,这时候就需要确定数组的大小
。
System.out.println("nums数组的大小为:"+nums.length);
nums = new int[]{12,5,87,14,26,77,59,31,7,60,233,1514};
int arr_length = nums.length;
for (int i =0;i<arr_length;i++){
System.out.println(nums[i]);
}
1.6.2、数组求和
数组求和:
获取多个整数中最大值。
步骤:
- 定义变量记录
和
。 - 通过循环对数组进行遍历。
public class Demo {
public static int getSum(int []nums){
int res = 0;// 求和结果
int length = nums.length;// 获取长度
for (int i =0;i<length;i++){
res += nums[i];
}
return res;
}
// 数据类型... 形式参数 可变长度参数 就是数组
public static int getSum1(int... nums){
int res = 0;// 求和结果
int length = nums.length;// 获取长度
for (int i =0;i<length;i++){
res += nums[i];
}
return res;
}
public static void main(String[] args) {
int nums[] = {23,17,40,20};
int sum = getSum(nums);
System.out.println("数组的求和结果:"+sum);
}
}
1.6.3、数组求最值
数组求最值:
货物多个整数中最大值。
思路:
- 数据多了为了便于操作,先存储起来。需要容器,用
数组
。 - 多个数据需要进行比较。每次都有较大的数,需要记录下来和下一个数比较。
- 将数组中的元素都比一遍。最后,就获取到
最大值
。
步骤:
- 接收欲求最大值的数组。
- 定义一个变量记录住较大的数。
- 对数组进行遍历。让元素和较大的值进行比较。如果元素大于较大的数,用变量记录该元素。
- 遍历完成后,变量中记录就是
最大值
。
public class Demo02 {
/**
* 求数组最大值
*/
public static int getMax(int nums[]){
int max = nums[0];// 默认最大值为第一个元素
for (int i = 1;i<nums.length;i++){// 遍历数组的每一位
if (max<nums[i]){// 判断当前为是否比max大
max = nums[i];// 用大值替换max值
}
}
return max;
}
public static int getMaxIndex(int nums[]){
int max = 0;// 默认最大值为第一个元素的角标
for (int i = 1;i<nums.length;i++){// 遍历数组的每一位
if (nums[max]<nums[i]){// 判断当前为是否比max大
max = i;// 用大值的角标替换max值的角标
}
}
return nums[max];
}
public static void main(String[] args) {
int nums[] = {7,23,44,16,32,99,34,13};
Arrays.sort(nums);
//int max = getMaxIndex(nums);
//System.out.println("最大值是:"+max);
System.out.println(Arrays.toString(nums));
System.out.println(nums[nums.length-1]);
}
}
1.6.4、数组转字符串
数组转字符串:
将数组中的数字
编程字符串
输出。如[12,22,13,18,15]
拼接后"1222131815"
。
思路:
简单的方式就是利用了字符串和任何数据相加都是相连接。+
步骤:
明确1:结果是什么类型?字符串
类型。
明确2:参数有什么?一个 int
类型的数组。
1、定义字符串变量存储以后拼接的结果。
2、遍历数组。将每一个数组的元素
和字符串
相连接。
3、判断不是最后一个元素,后面连接逗号
,是最后一个元素,后面不连接逗号。
4、将连接后的字符串返回。
/**
* 数组和字符串
*/
public class Demo03 {
public static String getStr(int nums[]){
String str = "[";// 开头
for (int i =0 ;i<nums.length;i++){// 遍历每一位
if (i == nums.length-1){
str += nums[i];// 最后一位
}else{
str += nums[i]+", ";// 非最后一位,需要 ,和空格
}
}
str += "]";// 结尾
return str;
}
// 纯数字字符串转化为数组
public static int[] getArr(String str){
int str_length = str.length();// 获取字符串长度。
int arr[] = new int[str_length];// 数组长度和字符长度保持一致
for(int i = 0;i<str_length;i++){
char c = str.charAt(i);// 截取每一位
int num = Integer.parseInt(c+"");// 字符串类型转化为数字类型。
arr[i] = num;// 每一位赋值
}
return arr;
}
public static void main(String[] args) {
//int nums[] = {23,17,3,45,83};
//String str = getStr(nums);
//System.out.println(str);
//System.out.println(Arrays.toString(nums));
//字符串截取
//String str1 = "java OOP";
//System.out.println(str1.charAt(1));
String str = "65778723617";
int[] arr = getArr(str);
System.out.println(getStr(arr));
str = "65-778-7-23-61-7";
String[] split = str.split("-");
System.out.println(Arrays.toString(split));
}
}
1.6.5、数组反转
数组反转:
将数组中的数据进行反转,如[1,22,17,18,65]
反转后[65,18,17,22,1]
。
思路:
-
需要定义数组反转的功能:
明确1:函数运算的结果?
void
类型或者int[]
。明确2:参与运行的参数?一个,
int[]
数组。 -
数组反转
就是将数组中的值进行位置互换。互换的条件
是:- 0角标和length-1角标位置上的值互换。
- 1角标和length-2角标位置上的值互换。
- 以此类推。
-
互换到什么时候停止呢?只要头角标
大于等于
了尾角标就停止。 -
怎么互换呢?互换就是交换两个空间中的值,可以使用第三方变量。
(三元置换)
步骤:
- 定义功能,接收数组。
- 遍历数组,每遍历一次交换数组两个位置的上的值,
start
代表头角标,end
代表尾角标 - 交换每次遍历的两个空间
[start,end]
中的数据。
class ArrayTest4
{
public static void main(String[] args)
{
int[] arr = {1,22,17,18,65};
printArray(arr); // 输出
reverseArray(arr); // 反转
printArray(arr);// 输出
}
//1、定义功能,接受数组
public static void reverseArray(int[] arr)
{
//2、遍历数组,每遍历一次交换数组两个位置的上的值,
// start代表头角标,end代表尾角标
for (int start = 0,end=arr.length-1;start<end ;start++,end-- )
{
//3、交换每次遍历的两个空间中的数据
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
}
}
//此功能为打印数组
public static void printArray(int[] arr)
{
for (int i=0;i<arr.length ;i++ )
{
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
}
}
1.6.6、数组排序
1、选择排序
选择排序是排序中的一种。
算法原则(从小到大排序):
先用数组中第一个空间值和数组中剩余的其他空间值 依次做比较,在比较的过程有任何值比第一个空间值小
,就用第一个空间值
和当前这个空间值
换位置,直到所有值
和第一个空间值
全部比较完。第一个空间
中就放着最小值
。接着在使用数组第二个空间值
和数组中剩下空间中值做比较,比较方式和前一次相同。以此类推,比较完成。
规律:
第一个空间
和剩余空间
比一圈,第二个空间
在和剩余空间
比一圈,以此类推,到倒数第二个空间值和最后一个空间值比完,整个数组有有序了。正好符合了外循环循环一次,内循环执行一圈。即外循环控制每次到底使用哪个空间值和剩余空间比较,内循环提供剩余空间。
图解:
代码:
/**
* 选择排序。
*/
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;
}
}
}
}
2、冒泡排序
算法原理:
这种算法和生活中常见的水中气泡的浮沉类似。
规律:
- 数字
第一个
空间值和第二个
空间值比较,把较大的值存在第二个空间中,接着第二个空间值和第三个
空间值作比较,较大的值存在第三个空间中,以此类推直到倒数第二个空间和倒数第一个
空间比较,把较大值存放在最后一个空间中。 - 由于
最后一个
空间已经是最大值了,那么第二轮算法和第一轮一样,只是最后一次比较是倒数第三个空间和倒数第二个空间比较。把较大的值存在倒数第二个空间中。 - 以此类推。
图解:
代码:
/**
* 冒泡排序。
*/
public static void bubbleSort(int[] arr)
{
for(int x=0; x<arr.length-1; x++)// 决定了比较范围。
{
for(int y=0; y<arr.length-1-x; y++)// 从0开始比较到指定范围,范围逐渐缩小。
{
if(arr[y]>arr[y+1])// 两两比较 升序
{
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
1.6.7、数组查找
1、一般查找
从组中第一个空间
开始查找,每取出一个空间值和待查找的数值做比较若相等,就返回当前角标
;若数组遍历结束,没有找到相等的值,则返回-1
。
public static int searchKey(int[] arr,int key)
{
//遍历查找。
for(int x=0; x<arr.length; x++)
{
if(arr[x]==key) return x;// 找到就返回。
}
return -1;//-1,代表的是角标不存在的情况。
}
2、折半查找(二分法)
前提:
必须保证数组已经是有序
的。
思路:
- 通过角标先获取中间角标上元素。
- 让该元素和要找的数据比较。
- 如果要找的数大了,缩小范围,要找的范围应该是
中间的角标+1
= = = > ===> ===>尾角标
; 如果要找的数小了,要找的范围头角标
= = = > ===> ===>中间角标-1
。 - 不断如此重复,就可以找到元素对应的角标。
public static int binarySearch(int[] arr,int key)
{
//1,定义三个变量,记录头角标,尾角标,中间角标。
int max,min,mid;
min = 0;// 中
max = arr.length-1;// 大
mid = (max+min)>>1;// 小 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)>>1;
}
return mid;
}
2、二组数组
2.1、定义
格式:
int[][] arr = new int[3][2];
定义了名称为arr的二维数组, 二维数组
中有3个一维数组
,每一个一维数组
中有2个元素
, 一维数组的名称分别为arr[0], arr[1], arr[2]
。
2.2、图解
2.3、其他定义格式
int[][] arr = new int[3][];// 定义一维数组为null的二维数组。
二维数组中有3个一维数组,每个一维数组都是默认初始化值null。
arr[0] = new int[3];
arr[1] = new int[1];
arr[2] = new int[2];
// 统一赋值
可以对这个三个一维数组分别进行初始化。
int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};
定义一个名称为arr的二维数组,二维数组中的有三个一维数组,每一个一维数组中具体元素也都已初始化。
- 第一个一维数组 arr[0] = {3,8,2};
- 第二个一维数组 arr[1] = {2,7};
- 第三个一维数组 arr[2] = {9,0,1,6};
- 第n个一维数组的长度表示方式:arr[n-1].length;
2.4、应用求和
class Array2Demo
{
public static void main(String[] args)
{
int[][] arr = {{3,8,2},{2,7},{9,0,1,6}};
int sum = getSum(arr);
System.out.println("sum="+sum);
}
// 求二位数组的和值
public static int getSum(int[][] arr)
{
int sum = 0;
for (int i=0;i<arr.length ;i++ )// 遍历二维数组每一个一维数组
{
for (int j=0;j<arr[i].length ;j++ )// 遍历一维数组的每一个元素
{
sum += arr[i][j];
}
}
return sum;
}
}
3、数组使用心得
数组容器的特点:
1、固定长度 ;
2、元素都有索引;
什么时候使用容器:数据多了,必须先进行存储。然后进行操作。
什么时候使用数组:
数据多,数据个数确定,而且数据与顺序有对应关系。在分析需求时确定:
- 需求中的数据是否有对应的有序编号;
- 需求中的数据是否需要有序的编号;如果有,就用数组存储。