1、数组
1-1、概念
- 是一种数据结构,根据下标来访问其中蕴含的数据,用于存储多个相同类型的变量,而不用定义多个变量
1-2、定义
1-2-1、动态初始化
定义的同时分配空间 如:int[ ] arr = new int[5]; 一条语句
定义后再根据条件需要分配空间 如:int[ ] arr;
arr = new int[6]; 两条语句
1-2-2、静态初始化
创建的同时赋值 如:int[ ] arr = new int[ ]{1,2,3,4,5};
其简化写法:int[ ] arr = {1,2,3,4,5};
最后一个值后面允许有逗号,方便为数组增加值
1-2-3、长度为0
int[ ] arr = new int[0];
int[ ] arr = new int[ ]{ };
注意长度为0和null意义不相同
1-2、赋值机制
问题:当将一个初始化好的数组A给另一个数组B保存时,修改数组A的值仍然会修改B的值,而基本数据类型则不会出现这种情况
基本数据类型的数据直接在栈中开辟存储数据,而数组存储是通过地址值,地址值指向真正的数据的方式来存储,将arr1给arr2保存两个数组都是存储同一个地址,自然操作的是同一个数据。
如图示:
1-3、数组相关操作
1-3-1、拷贝
- 需要创建一个新的数组逐个元素赋值,而不是直接用一个数组变量接收
public class Test {
public static void main(String[] args) {
int[] arr1 = {1,2,3};
int[] arr2 = arr1;//1、赋的是地址,并不是真正的拷贝
//2、真正的拷贝需要重写创建一个数据逐个元素赋值
int[] arr3 = new int[3];
for (int i = 0; i < 3; i++) {
arr3[i] = arr1[i];
}
//3、测试 arr1不变 arr3的值改变
arr3[2] =100;
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr3));
}
}
1-3-2、翻转
public class Test {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
//思路一:两个下标,首位元素依次交换
int i,j,temp;
for (i = 0,j=arr.length-1; i <= j; i++,j--) {
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
System.out.println(Arrays.toString(arr));
//思路二:再创建个数组,新数组用于保存逆序后的数据
//然后再让旧数组指向新数组(拷贝),完成旧数组的逆序
int[] old_arr = {1,2,3,4,5,6};
int[] new_arr = new int[old_arr.length];
int k,p;
for (k = 0,p =old_arr.length-1; p>=0; k++,p--) {
new_arr[p] = old_arr[k];
}
//让旧数组指向逆序后的数组
old_arr = new_arr;
System.out.println(Arrays.toString(old_arr));
}
}
1-3-3、扩容与缩减
- 创建新数组增加原先长度,缩减同理
- 由用户指定决定是否继续创建
public class Test {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
Scanner s = new Scanner(System.in);
int addnum;
do{
int[] arr2 = new int[arr.length+1];
for (int i = 0; i < arr.length; i++) {
arr2[i] = arr[i];
}
System.out.println("请输入要添加的数据");
arr2[arr.length] = s.nextInt();
arr = arr2;//改变指向旧数组
System.out.println("是否继续输入(Y/N)");
//charAt(int n)用于检索字符串特定下标下的字符
if( s.next().charAt(0)=='N'){
break;
}
}while (true);
System.out.println(Arrays.toString(arr));
}
}
2、排序
1、冒泡排序
- 类似两个指针分别指向第一、二元素,比较之后都向后移动,继续相邻间两两比较,由此可确定一个最大值。如果想确定第二大的值则需从头开始比较,但不再需比较最后一个已经确定是最大的元素
public class Test {
public static void main(String[] args) {
int[] arr = {24,12,37,58,47};
int i,j,temp;
//数组长度为5,则需进行四次排序,每次排序进行相邻元素间的两两比较
for(i=0;i<arr.length-1;i++){
//内循环-1是因为下标从0开始,
//-i是因为每一次外循环结束都确定了一个最大值,不再需要比较
for(j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println(Arrays.toString(arr));
/**
* {24,12,37,58,47,10}
* 第一轮排序,
* 第一次比较:{12,24,37,58,47} 第一个元素和第二个比 交换位置
* 第二次比较:{12,24,37,58,47} 第二个元素和第三个比 位置不变
* 第三次比较:{12,24,37,58,47} 第三个元素和第四个比 位置不变
* 第四次比较:{12,24,37,47,58} 第四个元素和第五个比 交换位置
* 结果:将最大数放在最后一位
*
* 第二轮排序:
* 第一次比较:{12,24,37,47,58} 第一个元素和第二个比 位置不变
* 第二次比较:{12,24,37,47,58} 第一个元素和第二个比 位置不变
* 第三次比较:{12,24,37,47,58} 第一个元素和第二个比 位置不变
* 结果:将第二大的数放在倒数第二位
* 注意:最后一个元素已经由第一轮排序决定,不再需要参与比较
*
*依次类推
*/
}
}
3、查找
3-1、顺序查找
- 遍历下标 一个个进行if判断判断数组中是否存在
3-2、二分查找
4、二维数组
4-1、定义
动态初始化1: int[][] arr = new int[2][3];
动态初始化2: int[][] arr;
arr = new int[2][3];
静态初始化: int[][] arr = { {1,2,3},{4,5,6} };
4-2、内存存在形式
- 一开始和一维数组一样在栈中的存储的是地址,但二位数组变量arr存储的地址指向的是一个存储地址的数组,其中每个元素地址都指向一个数组,此时数组里存储的才是真正的元素
由图可知和一维数组相比,二维的嵌套都发生在堆中
4-3、使用案例
4-3-1、动态创建二维数组
public class Test {
public static void main(String[] args) {
/** 动态创建二位数组
* 1
* 1 2
* 1 2 3
*/
int[][] arr = new int[3][];
//动态创建每个一维数组
for (int i = 0; i < 3; i++) {
//每次都要创建一维数组作为二维的元素
int[] a = new int[i+1];
//为一维数组赋值
for (int j = 0; j < i+1; j++) {
a[j] = j+1;
}
//让二位数组指向生成好的新数组
arr[i] = a;
}
//打印,由于二维数组内的每个一维数组大小不一致,
//故内循环打印一维数组元素的终止条件是变量
for (int i = 0; i < 3; i++) {
for (int j = 0; j <= i; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
}
4-3-2、杨辉三角
- 先确定二维数组的行数,再具体为每一行的一维数组开辟空间,再为其赋值
- 杨辉三角特点:每一行的首尾元素相同,其余元素为同列上一个和其前一个之和
public class Test {
public static void main(String[] args) {
/** 动态创建二位数组创建
* 1
* 1 1
* 1 2 1
* 1 3 3 1
* 1 4 6 4 1
* ...
*/
System.out.println("请输入要生成行数");
Scanner s = new Scanner(System.in);
int line = s.nextInt();
//先由用户输入确定要生成几个一维数组
int arr[][] = new int[line][];
int i,j;
for (i = 0; i < arr.length; i++){
//再为二维数组中的一维数组开辟空间
arr[i]= new int[i+1];
//为一维数组赋值
for (j = 0; j < arr[i].length; j++) {
//每一行的首尾元素都是1
if(j==0 || j==arr[i].length-1){
arr[i][0] = arr[i][j] =1;
}else {
//杨辉三角规律
arr[i][j] = arr[i-1][j] + arr[i-1][j-1];
}
}
}
//打印 外循环是二维数组长度,内循环是一维数组长度
for (i = 0; i < arr.length; i++) {
for (j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j]+"\t");
}
System.out.println();
}
}
}
4-4、练习
4-4-1、数组的声明
坑点在int[] y[],也是二维数组的定义方式 答案:be
4-4-2、升序数组插入仍是升序
- 先定位,后扩容
- 扩容涉及快慢指针的知识
//[10,12,45,90] 添加任意数据仍然是升序
public static void test(){
//扩容+定位
int[] arr = {10,12,45,90};//27
System.out.println("请输入要插入的数字:");
Scanner s = new Scanner(System.in);
int num = s.nextInt();
int i,j,flag=0,index=0;
//像得到要插入的位置
for(i=0;i<arr.length;i++){
if(arr[i]<=num){
index = i+1;//升序数组,位置在其后方
}
}
//扩容,利用快慢指针,当遇到要插入的位置时,让arr的指针j慢一拍
//以保证其能指向正确的数据
//
//10 12 45 90
int[] arrNew = new int[arr.length+1];
for(i=0,j=0;i<arrNew.length;i++){
//不是插入位置,正常添加数据,
//旧数组的指针j和新数组的指针i均正常自增
if(i!=index){
arrNew[i] =arr[j];
j++;
}else{//需要插入数,此时插入数据,
// 新数组指针正常移动但旧数组指针不动
//例如要插入的数据是5,则一开始会直接到此
//形成【5,0,0,0,0】 ,后续再正常赋值
arrNew[i] = num;
}
}
System.out.println(Arrays.toString(arrNew));
}
编排格式
文字大小
红色
蓝色
橙色
紫色
绿色
空格
表格第一行:背景颜色、对齐 | |
表格第二行:变大变颜色变高 | |
表格的第三行:居中 | 第二列 |