您的位置:首页 > 编程语言 > Java开发

Java二维数组及常见相关算法讲解

2015-06-02 20:20 246 查看
在学校里,由于一个班的人数不多,所以按照顺序编号即可,当人数增多时,例如对于学校里的人,在编号时就要增加层次,例如XX班XX号。在部队中也是这样,XX师XX团XX营XX连XX排XX班,这里的层次就比较深了。为了管理数据的方便,一般要加深管理的层次,这就是多维数组的由来。

    多维数组,指二维以及二维以上的数组。二维数组有两个层次,三维数组有三个层次,依次类推。每个层次对应一个下标。

    在实际使用中,为了使结构清晰,一般对于复杂的数据都是用多维数组。

    关于多维数组的理解,最终的是理解数组的数组这个概念,因为数组本身就是一种复合数据类型,所以数组也可以作为数组元素存在。这样二维数组就可以理解成内部每个元素都是一维数组类型的一个一维数组。三维数组可以理解成一个一维数组,内部的每个元素都是二维数组。无论在逻辑上还是语法上都支持“数组的数组”这种理解方式。

    通常情况下,一般用二维数组的第一维代表行,第二维代表列,这种逻辑结构和现实中的结构一致。

    和一维数组类似,因为多维数组有多个下标,那么引用数组中的元素时,需要指定多个下标。

 

1、 多维数组语法

    下面以二维数组为例,来介绍多维数组的语法。

 

1.1 多维数组声明

    多维数组的声明:数据类型[][] 数组名称;数据类型[] 数组名称[];数据类型   数组名称[][];以上三种语法在声明二维数组时的功能是等价的。同理,声明三维数组时需要三对中括号,中括号的位置可以在数据类型的后面,也可以在数组名称的后面,其它的依次类推。

    例如:int[][] map;char c[][];和一维数组一样,数组声明以后在内存中没有分配具体的存储空间,也没有设定数组的长度。

 

1.2 多维数组初始化

    和一维数组一样,多维数组的初始化也可以分为静态初始化(整体赋值)和动态初始化两种,其语法格式如下。

1.2.1 静态初始化

    以二维数组的静态初始化为例,来说明多维数组静态初始化的语法格式。示例代码如下:

                   int[][] m = {                             {1,2,3},                             {2,3,4}                    };

    在二维数组静态初始化时,也必须和数组的声明写在一起。数值书写时,使用两个大括号嵌套实现,在最里层的大括号内部书写数字的值。数值和数值之间使用逗号分隔,内部的大括号之间也使用逗号分隔。

    由该语法可以看出,内部的大括号其实就是一个一维数组的静态初始化,二维数组只是把多个一维数组的静态初始化组合起来。

    同理,三维数组的静态初始化语法格式如下:

                   int[][][] b = {                             {                                      {1,2,3},                                      {1,2,3}                             },                             {                                      {3,4,1},                                      {2,3,4}                             }                    };

    说明:这里只是演示语法格式,数值本身没有意义。

 

1.2.2 动态初始化

    二维数组动态初始化的语法格式:

    数据类型[][] 数组名称 = new 数据类型[第一维的长度][第二维的长度];

    数据类型[][] 数组名称;

    数组名称 = new 数据类型[第一维的长度][第二维的长度];

    示例代码:

                   byte[][] b = new byte[2][3];                    int m[][]; m = new int[4][4];

    和一维数组一样,动态初始化可以和数组的声明分开,动态初始化只指定数组的长度,数组中每个元素的初始化是数组声明时数据类型的默认值。例如上面初始化了长度为2X3的数组b,和4X4的数组m.

    使用这种方法,初始化出的第二维的长度都是相同的,如果需要初始化第二维长度不一样的二维数组,则可以使用如下的格式:

                   int n[][];                    n = new int[2][]; //只初始化第一维的长度                    //分别初始化后续的元素                    n[0] = new int[4];                    n[1] = new int[3];

    这里的语法就体现了数组的数组概念,在初始化第一维的长度时,其实就是把数组n看成了一个一维数组,初始化其长度为2,则数组n中包含的2个元素分别是n[0]和n[1],而这两个元素分别是一个一维数组。后面使用一维数组动态初始化的语法分别初始化n[0]和n[1].

 

1.3 引用数组元素

    对于二维数组来说,由于其有两个下标,所以引用数组元素值的格式为:

     数组名称[第一维下标][第二维下标]该表达式的

     该表达式的类型和声明数组时的数据类型相同。例如引用二维数组m中的元素时,使用m[0][0]引用数组中第一维下标是0,第二维下标也是0的元素。这里第一维下标的区间是0到第一维的长度减1,第二维下标的区间是0到第二维的长度减1.

 

1.4 获得数组长度

     对于多维数组来说,也可以获得数组的长度。但是使用数组名。length获得的是数组第一维的长度。如果需要获得二维数组中总的元素个数,可以使用如下代码:

                   int[][] m = {                             {1,2,3,1},                             {1,3},                             {3,4,2}                    };                    int sum = 0;                    for(int i = 0;i < m.length;i++){ //循环第一维下标                             sum += m[i].length;     //第二维的长度相加                    }

     在该代码中,m.length代表m数组第一维的长度,内部的m[i]指每个一维数组元素,m[i].length是m[i]数组的长度,把这些长度相加就是数组m中总的元素个数。

 

 

2 、多维数组使用示例

    多维数组在实际使用时,更多的在于数组的设计,在实际使用中,一般对于多维数组的统计相对来说比一维数组要少一些,更多的设计数组的大小,并规定数组中存储值的含义,在代码中按照值的规定使用数组。

    所以在实际使用多维数组以前,需要考虑清楚:

    需要几维数组

    每一维的长度是多少

    按照怎样的规则存储

    数组值的意义是什么

 

2.1 拉丁方阵

    要求:实现任意阶拉丁矩阵的存储和输出拉丁矩阵是一种规则的数值序列,例如4阶的拉丁矩阵如下所示:

1         2 3 4 2         3 4 1 3         4 1 2 4         1 2 3

    该矩阵中的数字很规则,在实际解决该问题时,只需要把数值的规律描述出来即可。

    实现思路:声明一个变量n,代表矩阵的阶,声明和初始化一个nXn的数组,根据数据的规律,则对应的数值为(行号 + 列号 + 1),当数值比n大时,取和n的余数。

    实现的代码如下:

                  int n = 6;                    int[][] arr = new int

;                    int data; //数值                    //循环赋值                    for(int row = 0;row < arr.length;row++){                             for(int col = 0;col < arr[row].length;col++){                                      data = row + col + 1;                                      if(data <= n){                                                arr[row][col] = data;                                      }else{                                                arr[row][col] = data % n;                                      }                             }                    }                    //输出数组的值                    for(int row = 0;row < arr.length;row++){                             for(int col = 0;col < arr[row].length;col++){                                      System.out.print(arr[row][col]);                                      System.out.print(' ');                             }                             System.out.println();                    }

    该代码中变量data存储行号+列号+1的值,每次在赋值时判别data的值是否小于等于n,根据判断的结果赋值对应数组元素的值。

    在解决实际问题时,观察数字规律,并且把该规律使用程序进行表达,也是每个程序员需要的基本技能。

 

2.2 杨辉三角

    要求:实现10行杨辉三角元素的存储以及输出。

    杨辉三角是数学上的一个数字序列,该数字序列如下:

                     1

1         1 1          2 1 1          3 3 1 1          4 6 4 1

    该数字序列的规律为,数组中第一列的数字值都是1,后续每个元素的值等于该行上一行对应元素和上一行对应前一个元素的值之和。例如第五行第二列的数字4的值,等于上一行对应元素3和3前面元素1的和。

    实现思路:杨辉三角第几行有几个数字,使用行号控制循环次数,内部的数值第一行赋值为1,其它的数值依据规则计算。假设需要计算的数组元素下标为(row,col),则上一个元素的下标为(row – 1,col),前一个元素的下标是(row – 1,col – 1)。

    实现代码如下:

                  int[][] arr = new int[10][10];                    //循环赋值                    for(int row = 0;row < arr.length;row++){                             for(int col = 0;col <= row;col++){                                      if(col == 0){ //第一列                                                arr[row][col] = 1;                                      }else{                                                arr[row][col] = arr[row - 1][col] + arr[row - 1][col - 1];                                      }                             }                    }                    //输出数组的值                    for(int row = 0;row < arr.length;row++){                             for(int col = 0;col <= row;col++){                                      System.out.print(arr[row][col]);                                      System.out.print(' ');                             }                             System.out.println();                    }

    该题目中数字之间的规律比较简单,主要是理解数组的下标基本的处理,加深对于数组下标的认识,控制好数组元素的值。

 

2.3 存储图形结构

    要求:根据数组中的值,在对应位置绘制指定的字符。规定0绘制空格,1绘制星号(*)。数组的值如下所示:

                            {                                      {0,0,0,1,0,0,0},                                      {0,0,1,0,1,0,0},                                      {0,1,0,0,0,1,0},                                      {1,0,0,0,0,0,1},                                      {0,1,0,0,0,1,0},                                      {0,0,1,0,1,0,0},                                      {0,0,0,1,0,0,0}                             }

    该题目是一个基本的数组应用,数组中的值存储的是控制信息,程序根据数组中的值实现规定的功能。

    实现思路:循环数组中的元素,判断数组中的值,根据值绘制对应的字符即可。

    实现的代码如下所示:

                  int[][] map = {

                                     {0,0,0,1,0,0,0},                                      {0,0,1,0,1,0,0},                                      {0,1,0,0,0,1,0},                                      {1,0,0,0,0,0,1},                                      {0,1,0,0,0,1,0},                                      {0,0,1,0,1,0,0},                                      {0,0,0,1,0,0,0}                    };                    //输出数组的值                    for(int row = 0;row < map.length;row++){                             for(int col = 0;col < map[row].length;col++){                                      switch(map[row][col]){                                      case 0:                                                System.out.print(' ');                                                break;                                      case 1:                                                System.out.print('*');                                                break;                                      }                             }                             System.out.println();                    }

    类似的代码在游戏开发中,可以用来代表游戏中的地图数据,或者俄罗斯方块等益智游戏中地图块的值。

 

2.4 螺旋数组

    要求:存储和输出nXm的螺旋数组,其中n和m为大于0的整数。

    以下是一些螺旋数组的示例:

1         2   3   4                    1   2   3   4   5 12 13 14 5                     14 15 16 17 6 11 16 15 6                     13 20 19 18 7 10 9   8   7                     12 11 10    9 8 4X4螺旋数组                        4X5螺旋数组

    对于螺旋数组来说,其中的数值很有规则,就是按照旋转的结构数值每次加1,实现该功能需要对数组和流程控制有角深刻的认识。

    实现思路:声明一个变量来代表需要为数组元素赋的值,对于其中的数字来说,每个数字都有一个移动方向,这个方向指向下一个元素,根据该方向改变数组的下标,如果到达边界或指向的元素已经赋值,则改变方向。

    实现代码如下:

                  int n = 4;                    int m = 5;                    int[][] data = new int
[m];                    int dire;   //当前数字的移动方向                    final int UP = 0;   //上                    final int DOWN = 1; //下                    final int LEFT = 2; //左                    final int RIGHT = 3;//右                    dire = RIGHT;                    int value = 1;    //数组元素的值                    int row = 0;     //第一维下标                    int col = 0;     //第二维下标                    data[0][0] = 1; //初始化第一个元素                    while(value < n * m){                             switch(dire){                                      case UP:                                                row--; //移动到上一行                                                if(row < 0){ //超过边界                                                         row++; //后退                                                         dire = RIGHT;                                                         continue; //跳过该次循环                                                }else if(data[row][col] != 0){//已赋值                                                         row++; //后退                                                         dire = RIGHT;                                                         continue; //跳过该次循环                                                }                                                break;                                      case DOWN:                                                row++; //移动到下一行                                                if(row >= n){ //超过边界                                                         row--; //后退                                                         dire = LEFT;                                                         continue; //跳过该次循环                                                }else if(data[row][col] != 0){//已赋值                                                         row--; //后退                                                         dire = LEFT;                                                         continue; //跳过该次循环                                                }                                                break;                                      case LEFT:                                                col--; //移动到前一列                                                if(col < 0){ //超过边界                                                         col++; //后退                                                         dire = UP;                                                         continue; //跳过该次循环                                                }else if(data[row][col] != 0){//已赋值                                                         col++; //后退                                                         dire = UP;                                                         continue; //跳过该次循环                                                }                                                break;                                      case RIGHT:                                                col++; //移动到后一行                                                if(col >= m){ //超过边界                                                         col--; //后退                                                         dire = DOWN;                                                         continue; //跳过该次循环                                                }else if(data[row][col] != 0){//已赋值                                                         col--; //后退                                                         dire = DOWN;                                                         continue; //跳过该次循环                                                }                                                break;                             }                             value++; //数值增加1                             data[row][col] = value;//赋值                                       }                    //输出数组中的元素                    for(int i = 0;i < data.length;i++){                             for(int j = 0;j < data[i].length;j++){                                      if(data[i][j] < 10){//右对齐                                                System.out.print(' ');                                      }                                      System.out.print(data[i][j]);                                      System.out.print(' ');                             }                             System.out.println();                    }

    在该代码中dire代表当前元素的移动方向,每个根据该变量的值实现移动,如果移动时超出边界或移动到的位置已赋值,则改变方向,并跳过本次循环,如果移动成功,则数值增加1,对数组元素进行赋值。

 

 

3、 数组综合练习

    1、计算两个矩阵A、B的乘积矩阵C.

    矩阵A={1,2,3,4,5,6};

    矩阵B={7,8,9,10,11,12}.

    两个矩阵的乘积仍然是矩阵。若A矩阵有m行p列,B矩阵有p行n列,则它们的乘积C矩阵有m行n列。C=A*B的算法:Cij= (i=0,1,……,m-1;j=0,1,……,n-1)

    设A、B、C矩阵用3个2维数组表示:a数组有3行2列,b数组有2行3列,则c数组有3行3列。

    如:

    c[0][0]= a[0][0]*b[0][0]+a[0][1]*b[1][0];

    c[1][0]= a[1][0]*b[0][1]+a[1][1]*b[1][1];

 

    2、计算并输出nXn的蛇形矩阵。(n>0)

    例如4X4的蛇形矩阵如下:

                            1   3   4 10                             2   5   9 11                             6   8 12 15                             7 13 14 16  

    3、使用1-9这9个数字填充一个3X3的数组,要求输出所有可能的情况。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: