Java基础回顾《数组》
1、数组的概述
数组的定义
- 数据是相同类型数据的有序集合
- 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成
- 其中每一个数据称作一个数组元素,每一个数组元素可以通过下标来访问
数组的四个基本特点
- 数组的长度是确定的,数组一旦被创建,他的大小是不可以被改变的想要扩容的话只能重新创建一个数组
- 数组元素必须是相同类型,不允许出现混合类型
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型
- 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是一个对象,Java中对象是在堆中的因此数组无论保存原始类型还是其他对象类型,数组对象本身就在堆中
2、数组声明创建
dataType[] nums = new dataType[arraySize] 创建数组的方法
定义数组:
- int[] nums ;
- int nums[]; //c和c++的声明方式
package com.f_Array;
public class ArrayDemo01 {
public static void main(String[] args) {
// 变量的类型 变量的名字 = 变量的值;
// 数组类型=基础类型后[]
// 定义数组的方式一
int[] nums;//声明一个数组但没有分配空间
//数组的创建
int[] num = new int[10];// 声明一个数组并给他分配了空间下标是0-10
//方式二
int nums2[];// c 和 c++的数组申明方式 一般都用方式一为首选
// 给num 赋值
for (int i=0;i<num.length;i++){// 下标是从0开始的
num[i]=i;// 用循环给数组赋值
System.out.println(num[i]); //输出数组里面的值0-9
}
}
}
三种初始化以及内存分析
Java内存分析
- 堆,堆是用来存放New对象和数组的 可以被所有的线程共享,不会存放别的对象引用
- 栈,存放基本变量类型(包含这个基本类型的具体数值),引用对象的变量(会存放这个引用在堆里面的地址)
- 方法区,可以被所有线程共享 包含了所有的class 和static变量
如图:
初始化数组的方式
package com.f_Array;
public class ArrayDemo02 {
public static void main(String[] args) {
// 初始化数组的方式
// 1、静态初始化: 创建+赋值
int[] a = {1,2,3,4,5,6};
System.out.println(a[1]);
// 2、动态初始化: 包含默认初始化
// 数组的初始值都是0 String类型的初始值为null 需要我们去进行赋值
int[] b = new int[10];
b[0] = 10;
System.out.println(b[0]);
System.out.println(b[1]);
// String 类型
String[] c = new String[10];
c[0] ="helloworld";
System.out.println(c[0]);
System.out.println(c[1]);
}
}
3、数组使用
数组的常用方式
- For循环数组获取元素或者下标
- For-Each循环增强型for循环(只能获取到元素获取不到下标)
- 数组作方法入参
- 数组作返回值(一般是对数组进行修改比如数组的反转)
案例如下
package com.f_Array;
public class ArrayDemo04 {
public static void main(String[] args) {
// 数组进阶使用 数组作方法入参 数组做返回值
// 1、增强型for循环可以直接输出数组中的元素但是获取不到下标 array.for For-Each循环(增强型for循环)
System.out.println("=====================数组增强型for循环输出元素========================");
int[] array = {1,2,3,4,5,6};
for (int arr : array) {
System.out.print(arr+"\t");
}
// 数组做方法入参
System.out.println();// 换行
System.out.println("=================数组做方法入参结果如下================");
printArray(array); //方法调用
// 数组反转(数组做返回值的使用)
System.out.println();// 换行
System.out.println("=================数组反转结果如下================");
int[] reverse = reverse(array); // 定义一个int类型的reverse数组 数组的结果是调用reverse(array)方法后返回的结果
printArray(reverse);//调用printArray方法循环打印输出reverse数组中的元素
}
// 2、数组做方法入参打印数组元素
public static void printArray(int[] array){
for (int i =0;i<array.length;i++){
System.out.print(array[i]+"\t");
}
}
// 3、反转数组
public static int[] reverse(int[] array){
int[] result = new int[array.length];//定义了一个空数组
// 反转的操作 result[] = array[i];
for (int i =0,j=result.length-1;i<array.length;i++,j--){
result[j] = array[i];
}
return result;
}
}
4、多维数组
什么是多维数组?多维数据就是数组的数组可能听起来比较玄乎?先来看看二维数组
二维数组
可以理解成一个特殊的一维数组,其每一个元素都是一个一维数组
int arr[][] = new int[2][5]//创建一个二维数组arr
//二维数组arr可以看成一个两行五列的数组
5、Arrays类
Arrays类是一个数组的工具类我们已通过Jdk帮助文档去查看里面的方法,或者通过idea里面的strucTure进行查看,方法有很多不明白的时候可以去看jdk帮助文档里面的解释非常清楚
package com.f_Array;
import java.util.Arrays;
public class ArrayDemo06 {
public static void main(String[] args) {
// Arrays类的使用
int[] array = {1,2,3,564,68,65,8,1,53,4,891,98,489,165,65,18915};
System.out.println(array);// [I@4554617c hashCode编码
// 打印数组
System.out.println(Arrays.toString(array));
System.out.println("==========调用自己写的printArray方法==========");
printArray(array);
System.out.println();
System.out.println("===========sort对数组进行排序===========");
Arrays.sort(array);
System.out.println(Arrays.toString(array));
// fil填充
// Arrays.fill(array,0);
// System.out.println(Arrays.toString(array));//[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// 可以对方法进行重载
Arrays.fill(array,2,4,0);// 下标在2-4之间的数包括2 被0填充
System.out.println(Arrays.toString(array));
}
//工具类里面的方法都是已经写好的方法 我们自己也可以去写
public static void printArray(int[] array){
for (int i = 0; i<array.length;i++){
if (i==0){
System.out.print("[");
}
if (i==array.length-1){
System.out.print(array[i]+"]");
}else {
System.out.print(array[i]+", ");
}
}
}
}
6、冒泡排序
冒泡排序是最出名的排序算法之一,经常出现在面试,笔试手写
思路:两两进行比较,谁小或者谁大就往前移或则后移
Java中总共有八大排序 可以去作为了解
- 冒泡排序的代码还是相对比较简单的,两层循环,外循环冒泡轮数,里层依次比较
- 看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为0(n2)
package com.f_Array;
import java.util.Arrays;
public class ArrayDemo07 {
/**
* 冒泡排序
* 1、比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置
* 2、每一次比较都会产生出一个最大或者最小的数字
* 3、下一轮则可以少排序一次
* 4、依次循环知道结束
*/
public static void main(String[] args) {
int[] array = {1,5,3,6,489,324,5,9,6,666,8};
int[] sort = sort(array);
System.out.print(Arrays.toString(sort));
}
public static int[] sort(int[] array){
// 定义一个临时变量
int temp = 0;
// 外层循环判断我们这个要走多少次
for (int i = 0;i<array.length-1;i++){//i<array.length-1防止溢出 因为下标是从0开始的
// 内层循环,比较两个数,如果第一个数比第二个数大,则交换位置
for (int j =0;j<array.length-1-i;j++){ // 每进行一次比较下一次比较都可以少比较一个数
if (array[j+1]<array[j]){
//位置交换 通过第三方变量实现交换 把三个变量看成一个三角形 要想实现值的交换就要通过temp 变量来进行
// 可以理解成如何把两杯水通过第三个杯子来进行相互交换
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
}
return array;
}
}
想想如何优化=>
通过建立标识符减少一次比较,也可以对程序进行优化
package com.f_Array;
import java.util.Arrays;
public class ArrayDemo07 {
/**
* 冒泡排序
* 1、比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们就交换他们的位置
* 2、每一次比较都会产生出一个最大或者最小的数字
* 3、下一轮则可以少排序一次
* 4、依次循环直到结束
*/
public static void main(String[] args) {
int[] array = {1,5,3,6,489,324,5,9,6,666,8};
int[] sort = sort(array);
System.out.print(Arrays.toString(sort));
}
public static int[] sort(int[] array){
// 定义一个临时变量
int temp = 0;
// 外层循环判断我们这个要走多少次
for (int i = 0;i<array.length-1;i++){// i<array.length-1防止溢出 因为下标是从0开始的
// 内层循环,比较两个数,如果第一个数比第二个数大,则交换位置
boolean flag = false;// 通过flag标识减少没有意义的比较也就是已经是比较好的元素
for (int j =0;j<array.length-1-i;j++){ // 每进行一次比较 下一次比较都可以少比较一个数
if (array[j+1]<array[j]){
//位置交换 通过第三方变量实现交换 把三个变量看成一个三角形 要想实现值的交换就要通过temp 变量来进行
// 也可以理解成如何把两杯水通过第三个杯子来进行相互交换
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
flag = true;
}
}
if (flag==false){
break;
}
}
return array;
}
}
7、稀疏数组(数据结构)
个人理解
其实普通二维数组转稀疏数组就是把 普通数组看成一个几行几列的棋盘 ,一个普通数组创建之后如果不赋值那么他的默认值就是0
在这个棋盘里面分别下两颗子(也就是数组里面的值) 那么问题来了 如果是一个11行11列的数组,里面只存了两个值的话岂不是大材小用? 来看如下原始数组(棋盘)
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
这个时候稀疏数组的作用就来了 稀疏数组就是来压缩空间的,虽然他也是一个普通的二维数组但是他却固定了只有3列用来存储分别用来存储这两个棋子的横坐标,纵坐标,和有效值,这3列也有固定的下标 0(行), 1(列), 2(有效值)至于多少行,这就要看这个棋盘上有多少个有效值再加1,为什么加1 我们总不能把稀疏数组的第一行也算进去吧,他的第一行就是用来存储转换稀疏数组之前这个原始数组有
【多少行,多少列,几个有效值】=>11行 11列 2个有效值
11 | 11 | 2 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
转换后的值 => 原始数组有11行 11列 2个 有效值 第1行第2列的有效值是1 第2行第3列的有效值是2
11 | 11 | 2 |
---|---|---|
1 | 2 | 1 |
2 | 3 | 2 |
一瞬间就把一个11行11列的数组压缩成了 一个3行3列的数组
案例
package com.f_Array;
public class ArrayDemo08 {
public static void main(String[] args) {
// 稀疏数组使用案例
// 1.创建一个二维数组 11*11 0:没有棋子 1:表示黑棋 2:表示白棋
int[][] array1 = new int[11][11];
array1[1][2] = 1;
array1[2][3] = 2;
System.out.println("输出最原始得数组");
for (int[] ints : array1) {
for (int anInt : ints) {
System.out.print(anInt + "\t");
}
System.out.println();
}
// 转化为稀疏数组来保存
// 获取有效值的个数
int sum = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (array1[i][j] != 0) {
sum++;
}
}
}
System.out.println("有效值得个数是:" + sum);
//2.创建一个稀疏数组的数组
int[][] array2 = new int[sum + 1][3]; // 稀疏数组的数组结构
// 稀疏数组的头部
array2[0][0] = 11; // 行
array2[0][1] = 11; // 列
array2[0][2] = sum; // 有效值的个数
// 打印看一下稀疏数组的结构 方便理解
System.out.println("打印查看稀疏数组结构");
for (int[] ints : array2) {
for (int anInt : ints) {
System.out.print(anInt + "\t");
}
System.out.println();
}
/** 创建的稀疏数组的结构是这样的
* 行 列 有效值
* 11 11 2
* 0 0 0
* 0 0 0
*/
// 遍历二维数组将非零的值。存放到稀疏数组中
int count = 0;
for (int i = 0; i < array1.length; i++) {
for (int j = 0; j < array1[i].length; j++) {
if (array1[i][j] != 0) {
count++;
array2[count][0] = i; // 第几行第一个数字存横坐标 第几行
array2[count][1] = j; // 第几行第一个数字存纵坐标 第几列
array2[count][2] = array1[i][j]; // 第几行第一个数字的值 有效值
}
}
}
// 输出稀疏数组
System.out.println("稀疏数组的值");
for (int[] ints : array2) {
for (int anInt : ints) {
System.out.print(anInt + "\t");
}
System.out.println();
}
// 结果 由此可以看出稀疏数组存储的其实就是有效数字的坐标 n行 n列 有效值是多少
/**
* 11 11 2
* 1 2 1
* 2 3 2
*/
// 3.如何把稀疏数组转为普通数组?
System.out.println("==========================");
System.out.println("稀疏数组还原");
// 1.读取稀疏数组的元素
int[][] array3 = new int[array2[0][0]][array2[0][1]]; // 就相当于int[11][11]
// 2.给其中的元素还原值
for (int i =1;i<array2.length;i++){
array3[array2[i][0]][array2[i][1]] = array2[i][2]; // 行 列 值
}
// 3.打印输出查看是否还原
System.out.println("输出还原数组");
for (int[] ints : array3) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
}
}