一维数组

数组是一个定长的容器,可以放相同类型的数据。
数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型

专业解释

数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
线性表,顾名思义,线性表就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。
数组具有连续的内存空间和相同的数据类型

数组的声明

dataType[] arrayName;
注:数组在声明时不能指定数组长度,即dataType[n] arrayName;是不合法的

数组的创建

arrayName = new dataType[n];

动态创建(初始化)

dataType[] arrayName = new dataType[n];

静态创建(初始化)

dataType[] arrayName = new dataType[]{value1,value2,......,valueN};

数组的内存模型

数组的声明即数组变量名存储在栈中,数组的创建在堆中,即在堆中开辟连续的对应数组长度的空间(所有引用类型的创建都在堆中)
我眼中的数组和冒泡排序
所有引用类型的变量名存的都是地址。

数组创建后的初始默认值

引用类型的数组元素默认初始值是null
字符类型的数组元素默认初始值是空格(0对应的字符)
整数类型的数组元素默认初始值是0
浮点数类型的元素默认初始值是0.0
布尔类型的元素默认初始值是false

为什么数组索引值从0开始呢?

从数组存储的内存模型上来看,“下标”最确切的定义应该是“偏移(offset)”。如果用 a 来表示数组的首地址,a[0] 就是偏移为 0 的位置,
也就是首地址,a[k] 就表示偏移 k 个 type_size 的位置,所以计算 a[k] 的内存地址只需要用这个公式:

a[k]_address = base_address + k * type_size

但是,如果数组从 1 开始计数,那我们计算数组元素 a[k] 的内存地址就会变为:

a[k]_address = base_address + (k-1)*type_size
对比两个公式,我们不难发现,从 1 开始编号,每次随机访问数组元素都多了一次减法运算,对于 CPU 来说,就是多了一次减法指令。数组作为非常基础的数据结构,通过下标随机访问数组元素又是其非常基础的编程操作,效率的优化就要尽可能做到极致。所以为了减少一次减法操作,数组选择了从 0 开始编号,而不是从 1 开始。
也有可能是历史原因
C 语言设计者用 0 开始计数数组下标,之后的 Java、JavaScript 等高级语言都效仿了 C 语言,或者说,为了在一定程度上减少 C 语言程序员学习 Java 的学习成本,因此继续沿用了从 0 开始计数的习惯。实际上,很多语言中数组也并不是从 0 开始计数的,比如 Matlab。甚至还有一些语言支持负数下标,比如 Python。

数组与链表的区别

链表适合插入和删除,时间复杂度是O(1),数组支持随机访问,根据下标随机访问的时间复杂度为O(1)。

增强for循环遍历数组

按照数组下标顺序,依次将冒号右边数组中的每个元素赋值给冒号左边的变量,数组长度为for循环的次数
for(数组元素类型 变量名 : 数组名){
语句;
}

编写一个长度为5的整型数组,每个元素赋值为0-10的随机整数,遍历该数组,输出每个元素。
int[] arr = new int[5];
Random r = new Random();
for(int i = 0; i < arr.length; i++){
arr[i] = r.nextInt(10);
}
for(int t : arr){
System.out.println(t);
}

多维数组

数据类型是数组的数组
我眼中的数组和冒泡排序

动态初始化

数组名 = new 数据元素类型[ 行数 ] [ 列数 ] ;
行数不能为空

静态初始化

数组类型 数组名[ ][ ] = new 数据类型[ ][ ] { {元素11,元素12,…} , {元素21,… } }

一维数组冒泡排序

int[] arr = new int[]{4,45,1,13,89,7};
            int temp;
            for(int i = 0; i < arr.length; i++){
                  for(int j = 0; j < arr.length - 1;j++){
                        if(arr[j] > arr[j+1]){
                              temp = arr[j];
                              arr[j] = arr[j+1];
                              arr[j+1] = temp;
                        }
                  }
            }

优化

int[] arr = new int[]{4,45,1,13,89,7};
            int temp;
            boolean flag = false;
            for(int i = 0; i < arr.length; i++){
                  for(int 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;
                              flag = true;
                        }
                  }
                  //当没有数据交换时,证明数组已排序完成,退出子循环
                  if(!flag){
                        break;
                  }
            }

二维数组冒泡排序(两种方法)

创建二维数组

Random r = new Random();
            int[][] arr = new int[4][6];
            for(int i = 0; i < arr.length; i++){
                  for(int j = 0; j < arr[0].length;j++){
                        arr[i][j] = r.nextInt(100);
                        System.out.print(arr[i][j]+" ");
                  }
                  System.out.println();
            }
            int row = arr.length;
            int column = arr[0].length;

第一种方法

//二维数组转化为一维数组
int[] array = new int[row * column];
for(int i = 0; i < row; i++){
            for(int j = 0; j < column; j++){
                        array[i*column+j] = arr[i][j];
            }
}

//对一维数组进行冒泡排序
int temp;
boolean flag = false;
for(int i = 0; i < array.length; i++){
            for(int j = 0; j < array.length - i -1;j++){
                        if(array[j] > array[j+1]){
                                    temp = array[j];
                                    array[j] = array[j+1];
                                    array[j+1] = temp;
                                    flag = true;
                        }
            }
            if(!flag){
                        break;
            }
}
//输出排序后的一维数组
for(int i : array){
            System.out.print(i + " ");
}
System.out.println();
//将排序后的一维数组转化为二维数组
for(int i = 0; i < row; i++){
            for(int j = 0; j < column; j++){
                        arr[i][j] = array[i*column+j];
            }
}
//输出二维数组
for(int i = 0 ; i < arr.length;i++){
            System.out.println(Arrays.toString(arr[i]));
}

第二种方法


int temp = 0;
            boolean flag = false;
            //所有子数组完成排序需要的冒泡次数总和
            for(int t = 0; t < row * column; t++){    
                  //遍历父数组,即第一维数组(行)的遍历
                  for(int z = 0; z < arr.length; z++){      
                        //每个数组完成排序需要的冒泡次数
                        for(int i = 0; i < arr[0].length; i++){
                              //遍历子数组,并进行冒泡排序
                              for(int j = 0; j < arr[0].length - 1 -i;  j++){
                                    if(arr[z][j]>arr[z][j+1]){
                                          temp = arr[z][j];
                                          arr[z][j] = arr[z][j+1];
                                          arr[z][j+1] = temp;
                                          flag = true;
                                    }
                              }
                              //当没有数据交换时,证明数组已排序完成,退出子循环
                              if(!flag){
                                    break;
                              }
                        }
                        //输出每组的最大值
                        //System.out.println(arr[z][arr[0].length-1]);
                        //将每组的最大值与下一组的第一个值比较,若大于则交换
                        if(z < arr.length - 1 && arr[z][arr[0].length-1]  > arr[z+1][0]){
                              temp = arr[z][arr[0].length-1];
                              arr[z][arr[0].length-1] = arr[z+1][0];
                              arr[z+1][0] = temp;
                        }
                  }
            }
            //输出二维数组
            for(int i = 0 ; i < arr.length;i++){
                  System.out.println(Arrays.toString(arr[i]));
            }