Java范例大全
上QQ阅读APP看书,第一时间看更新

第4章 数组

数组是一种重要的数据结构。一个数组是具有同一数据类型的对象的集合。数据类型可以是简单类型,也可以是类。数组可以是一维的,也可以是多维的,通过其下标可以访问数组元素。数组提供了一种将有联系的信息进行分组的有效方法。本章将详细讲解数组的应用。

实例13 一维数组复制、插入和合并

本质上讲,数组是一组相关的存储单元,这些存储单元在逻辑上被看作是相互独立的若干元素,它们具有相同的名字和数据类型。数组中的元素位置由它的下标决定。对数组的操作包括数组的复制、数组的合并、插入以及搜索等。本实例将讲解如何实现这些功能。

技术要点

本实例根据Java提供的不同方法操作数组。技术要点如下:

• 数组复制:通过System.arraycopy()方法实现数组的复制。

• 数组插入与数组删除相似,当插入元素后,插入点后面的每一个元素向后移一个位置,而删除是向前移一个位置。需要注意的是在插入元素前,必须对数组进行排序。

实现步骤

(1)新建一个类名为TextOperatorArray.java。

(2)代码如下所示:

package com.zf.s4;                              //创建一个包
import java.util.Arrays;                        //引入类
import java.util.Scanner;
public class TextOperatorArray {                //对数组元素进行各种操作的类
    public static void copy(){                  //数组复制
          int array[]=new int[]{1,2,3,4};       //声明数组并初始化
          int temp1[]=new int[array.length];    //声明数组长度为array数组的长度
          int temp2[]=new int[array.length];
          System.arraycopy(array, 0,temp1,0,array.length); //将数组array复制给数组temp1
          System.out.println("复制后的数组结果:");
          for(int i=0;i<temp1.length;i++)       //循环显示数组元素
              System.out.print(temp1[i]+" ");
          System.out.println();
          temp2=array;                          //使用赋值将数组array复制给数组temp2
    }
    public static void insert(){                //数组插入
          int i,j;
          int n=5;
          int num[]=new int[n+1];
          for(i=0;i<num.length-1;i++){
              num[i]=(i+1)*6;
          }
          int length=num.length;                       //获得数组长度
          System.out.println("插入数字之前的数组为:");
          for(i=0;i<length;i++)                        //循环显示数组元素
              if(num[i]==0)
                    System.out.print("存数空间");
              else
                    System.out.print(num[i]+" ");
          System.out.println();
          System.out.println("输出一个要插入的数:");
          Scanner scan=new Scanner(System.in);         //键盘输入一个数
          int in=scan.nextInt();
          for(i=0;i<length-1;i++){                     //循环查找一个大于要插入数的位置
              if(num[i]>in)                            //找到大于要插入的数就跳出
                    break;
          }
          for(j=length-1;j>i;j--){                     //为要插入的数留出位置
              num[j]=num[j-1];
          }
          num[i]=in;                                   //将要插入的数保存到该位置
          for(i=0;i<length;i++)                        //循环显示数组元素
              System.out.print(num[i]+" ");
          System.out.println();
      }
      public static int[] combine(int[] a, int[] b) {  //数组合并并排好序
          int alen = a.length;                         //获得传入数组的长度
          int blen = b.length;
          int length = alen + blen;
          int i, j;
          System.out.println("合并之间的两个数组:");
          for(i=0;i<alen;i++)                          //循环显示a数组元素
              System.out.print(a[i]+" ");
          System.out.println();
          for(i=0;i<blen;i++)                          //循环显示b数组元素
              System.out.print(b[i]+" ");
          System.out.println();
          int[] c = new int[length];             //声明数组长度为传入两个数组长度之和
          for (i = 0, j = 0; i < alen && j < blen;){   //循环查看元素进行比较
              if (a[i] < b[j]) {                       //判断两个数组元素值的大小
                    c[i + j] = a[i];//
                    i++;
              } else {
                    c[i + j] = b[j];
                    j++;
              }
          }
          if (i == alen)
              //将b数组从下标为j开始将值赋给c数组,放在c数组的alen+j,blen-j之间
              System.arraycopy(b, j, c, alen + j, blen - j);
          if (j == blen)
              //将a数组从下标为i开始将值赋给c数组,放在c数组的blen+i,alen-i之间
              System.arraycopy(a, i, c, blen + i, alen - i);
          System.out.println("合并并排序之后的新数组:");
          for (int k = 0; k < a.length + b.length; k++)   //循环输出合并后的数组的元素
              System.out.print(c[k]+" ");
          System.out.println();
          return c;
    }
    public static void main(String []args){               //Java程序的主入口处
          System.out.println("1.数组复制:");
          copy();                                         //调用数组复制方法
          int a[] = { 1, 2, 3, 12 };                      //声明数组并初始化
          int b[] = { 5, 6, 7, 8 };
          System.out.println("2.数组合并:");
          int c[] = combine(a, b);                        //调用数组合并方法
          System.out.println("3.数组插入:");
          insert();                                       //调用数组插入方法
    }
}

(3)运行结果如下所示:

1.数组复制:
复制后的数组结果:
1  2  3  4
2.数组合并:
合并之间的两个数组:
1  2  3  12
5  6  7  8
合并并排序之后的新数组:
1  2  3  5  6  7  8  12
3.数组插入:
插入数字之前的数组为:
6  12  18  24  30 存数空间
输出一个要插入的数:
20
6  12  18  20  24  30

源程序解读

(1)在copy()方法中,运用System.arraycopy()方法对数组进行复制。方法中声明两个数组,其中array数组在声明时初始化。temp1数组的长度为array数组的长度以便进行复制。进行复制时arraycopy(array,0,temp1,1,array.length)方法表示将array数组从第一个元素开始复制到temp1数组下标从0到array.length的位置。

(2)在insert()方法中,运用循环对数组初始化并排好序。接受通过键盘输入的待插入的数值。循环先查找第一个大于要插入数的位置,然后再运用循环为要插入的数留出位置,将待插入的数放到该位置。

(3)在combine()方法中,声明一个新数组,长度为传入数组的长度之和。循环查看传入的两个数组元素,将两个数组的元素依次进行大小比较,比较之后的元素放入新数组。通过arraycopy()方法将未放入新数组的元素复制进去,完成数组的合并与新数组的排序。

实例14 数组排序

排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录序列调整为“有序”的记录序列。常用的排序方法有冒泡排序、快速排序、选择排序、插入排序、希尔(Shell)排序、堆排序。本实例对常见排序方法进行讲解。

技术要点

本实例讲述几种排序的运算方法。技术要点如下:

• 冒泡排序是依次比较相邻的两个数,将大数放在前面,小数放在后面。即首先比较第一个和第二个数,将大数放前,小数放后。如此继续,直至比较最后两个数,将大数放前,小数放后。然后下一行再进行重复操作。

• 选择排序是每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。选择排序是不稳定的排序方法。

• 插入排序(Insertion Sort)把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外,而第二部分就只包含这一个元素。在第一部分排序后,再把这个最后元素插入到此刻已是有序的第一部分里的正确位置中。

• 希尔排序(Shell Sort)是插入排序的一种。基本思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<⋯<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

实现步骤

(1)创建一个类名为TextSort.java。

(2)代码如下所示:

package com.zf.s4;                                //创建一个包
public class TextSort {                           //操作排序的类
    public static void bubbleSort(int[] x) {      //冒泡排序
          for (int i = 0; i < x.length; i++) {
              for (int j = i + 1; j < x.length; j++) {
                    if (x[i] > x[j]) {            //将下标为i的数与下标为j的数进行比较
                        int temp = x[i];          //元素交换
                        x[i] = x[j];
                        x[j] = temp;
                    }
              }
          }
          for (int i = 0; i < x.length; i++) {    //循环将重新排序的结果输出
              System.out.print(x[i] + " ");
          }
    }
    public static void selectSort(int[] x) {      //选择排序
          for (int i = 0; i < x.length; i++) {
              int lowerIndex = i;
              for (int j = i + 1; j < x.length; j++) { //循环找出最小的一个索引
                    if (x[j] < x[lowerIndex]) {
                        lowerIndex = j;
                    }
              }
            int temp = x[i];                     //交换
            x[i] = x[lowerIndex];
            x[lowerIndex] = temp;
          }
          for (int i = 0; i < x.length; i++) {   //循环将重新排序的结果输出
              System.out.print(x[i] + " ");
          }
      }
      public static void insertSort(int[] x) {   //插入排序
          for (int i = 1; i < x.length; i++) {   //i从1开始,因为第一个数已经是排好序的
              for (int j = i; j > 0; j--) {
                    if (x[j] < x[j - 1]) {
                        int temp = x[j];         //元素交换
                        x[j] = x[j - 1];
                        x[j - 1] = temp;
                    }
              }
          }
          for (int i = 0; i < x.length; i++) {   //循环将重新排序的结果输出
              System.out.print(x[i] + " ");
          }
      }
      public static void shellSort(int[] x){     //希尔排序
          for (int increment = x.length / 2; increment > 0; increment /= 2){
                                                 //循环进行分组
              for (int i = increment; i < x.length; i++) {   //循环每个组内排序
                    int temp = x[i];
                    int j = 0;
                    for (j = i; j >= increment; j -= increment) {
                        if (temp < x[j - increment]) {       //元素进行判断、交换
                              x[j] = x[j - increment];
                        } else {
                              break;
                        }
                    }
                    x[j] = temp;
              }
          }
          for (int i = 0; i < x.length; i++) {    //循环将重新排序的结果输出
              System.out.print(x[i] + " ");
          }
      }
      public static void main(String[] args) {    //Java程序的主入口处
          int[] arr = { 1, 5, 6, 12, 4, 9, 3, 23, 39, 403, 596, 87 };
          System.out.println("----冒泡排序的结果:");
          bubbleSort(arr);                        //调用冒泡排序方法
          System.out.println();
          System.out.println("----选择排序的结果:");
          selectSort(arr);                        //调用选择排序方法
          System.out.println();
          System.out.println("----插入排序的结果:");
          insertSort(arr);                        //调用插入排序方法
          System.out.println();
          System.out.println("----希尔(Shell)排序的结果:");
          shellSort(arr);                         //调用希尔(Shell)排序方法
      }
}

(3)运行结果如下所示:

----冒泡排序的结果:
1 3 4 5 6 9 12 23 39 87 403 596
----选择排序的结果:
1 3 4 5 6 9 12 23 39 87 403 596
----插入排序的结果:
1 3 4 5 6 9 12 23 39 87 403 596
----希尔(Shell)排序的结果:
1 3 4 5 6 9 12 23 39 87 403 596

源程序解读

(1)在bubbleSort()方法中,运用双重循环对数组进行冒泡排序。其中i、j控制数组的元素。将下标为i的元素与下标为j的元素进行比较,将较小的元素与较大的元素依次用中间变量进行转换。得到的结果是较小的元素在前,较大的元素在后。然后将排好序的数组元素打印到控制台。

(2)在selectSort()方法中,运用选择排序法对数组进行排序。方法中第一层循环从起始元素开始选到最后一个元素,主要是在每次进入第二层循环之前,将外层循环的下标赋值给临时变量lowerIndex,接下来在第二层循环中,如果发现有比下标为lowerIndex更小的元素,则将值赋给lowerIndex,最后,在二层循环退出后,如果临时变量改变,则说明有比当前外层循环位置更小的元素,需要将这两个元素交换。

(3)在insertSort()方法中,运用插入排序对数组进行排序。从第一个元素开始,该元素可以认为已经被排序。循环取出下一个元素,在已经排序的元素序列中从后向前扫描,如果该元素(已排序)大于新元素,则将该元素移到下一位置,重复进行操作,直到找到已排序的元素小于或者等于新元素的位置,再将新元素插入到该位置中。

(4)在shellSort()方法中,先将数组进行分组,对分得的每个小组进行组内排序。在每个小组内对元素进行比较,将每个小组组内的元素由小到大进行排序。再次循环分组,直到元素排序完毕。

实例15 数组搜索

一个数组是具有同一数据类型的对象的集合。对数组元素进行逐个查找显然是费时费力的工作。本实例将讲解如何快速地搜索出数组中元素的指定位置。

技术要点

本实例根据二分搜索法对数组元素进行搜索。技术要点如下:

• 二分搜索法充分利用了元素间的次序关系,基本思想:将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止。如果x<a[n/2],则只要在数组a的左半部继续搜索x(这里假设数组元素呈升序排列)。如果x>a[n/2],则只要在数组a的右半部继续搜索x。

• 二分搜索法的局限性:必须是在有序的元素中进行的,不能在无序的元素中使用。

实现步骤

(1)创建一个类名为TextArraySearch.java。

(2)代码如下所示:

package com.zf.s4;                                      //创建一个包
import java.util.Arrays;
public class TextArraySearch {                   //运用递归和二分搜索法搜索数组元素的类
    //运用递归和二分搜索法查找特定整数在整型数组中的位置
    public static int binarySearch1(int[] array, int index, int beginIndex,
              int endIndex) {
          int midIndex = (beginIndex + endIndex) / 2;
          if (index < array[beginIndex] || index > array[endIndex]
                    || beginIndex > endIndex)           //判断要搜索的数字是否合理
              return -1;
          if (index < array[midIndex]) {                //搜索数字位于数组前半部分
              return binarySearch1(array, index, beginIndex, midIndex - 1);//运用递归
          } else if (index > array[midIndex]) {         //搜索数字位于数组后半部分
              return binarySearch1(array, index, midIndex+1, endIndex); //运用递归
          } else {
              return midIndex;                          //搜索数字位于数组中间
          }
    }
    //运用非递归和二分搜索法查找特定整数在整型数组中的位置
    public static int binarySearch2(int[] array, int index) {
          int beginIndex = 0;                           //起始位置,指的是元素下标
          int endIndex = array.length - 1;              //结束位置
          int midIndex = -1;
          if (index < array[beginIndex] || index > array[endIndex]
                    || beginIndex > endIndex)           //判断要搜索的数字是否合理
              return -1;
          //循环判断,根据起始位置与结束位置是否相等
          while (beginIndex <= endIndex) {
              midIndex = (beginIndex + endIndex)/2;     //获得数组中间位置
              if (index < array[midIndex]) {            //搜索数字位于数组前半部分
                    endIndex = midIndex - 1;            //重新定位结束位置
              } else if (index > array[midIndex]) {     //搜索数字位于数组后半部分
                    beginIndex = midIndex + 1;          //重新定位起始位置
              } else {
                    return midIndex;                     //搜索数字位于数组中间
                }
          }
          return -1;
      }
      public static void main(String []args){           //Java程序的主入口处
          int []array=new int[]{12,3,2,18,24,15,20};   //声明数组并初始化
          int number=18;                                  //声明变量
          int num=1;
          //二分搜索法搜索元素之前必须对数组进行排序
          Arrays.sort(array);
          System.out.println("元素"+number+"所在的位置为:"+binarySearch1(array,
number,0,array.length-1));
          System.out.println("元素"+number+"所在的位置为:"+binarySearch2(array,number));
          System.out.println("元素"+num+"所在的位置为:"+binarySearch2(array,num));
      }
}

(3)运行结果如下所示:

元素18所在的位置为:4
元素18所在的位置为:4
元素1所在的位置为:-1

源程序解读

(1)在binarySearch1()方法中,获得传递的起始位置与结束位置的中间位置作为二分点。判断搜索的数字的位置是在二分点的前面还是后面。位于前面则搜索的数字小于位于二分点的数字,位于后面则搜索的数字大于二分点的数字。运用递归方式再调用binarySearch1()方法进行二分搜索。

(2)在binarySearch2()方法中,设置起始位置与结束位置再获得二分点。根据起始位置与结束位置进行while()循环,判断搜索的数字在数组二分点的数字前面还是后面。位于前面则将结束位置重新设置。位于后面则将起始位置重新设置。

实例16 去掉数组重复数字

在上一实例中讲解了常用的排序方法,接下来要去掉一个已经排好序的数组的重复数字,执行速度也是要考虑的问题。

技术要点

本实例根据数组下标删除指定的数组元素。技术要点如下。

提供两种思路解决去掉重复数字:第一种是增加一个数组,但是长度无法确定,记录没有重复的值;第二种是增加一个数组,用于记录原数组中存在的数,再增加一个数组可以确定数组的长度,用于存放原数组的值。用来比较哪种方法最适用。

实现步骤

(1)创建一个类名为TextDelRepeat.java。

(2)代码如下所示:

package com.zf.s4;                                      //创建一个包
public class TextDelRepeat {                            //操作去掉数组中重复数字的类
    public static int[] changeMethodOne(int src[]) {    //方法1 去掉重复数字
          int length = src.length;                      //获得传入数组的长度
          int[] taget = new int[length];         //声明一个数组,长度为传入数组的长度
int index = 0; taget[0] = src[0]; //设置数组的初始值 for (int i = 1; i < length; i++) { //循环遍历传入数组 if (taget[index] != src[i]) { //遍历数组与初始值进行比较 index++; //等价于index=index+1 taget[index] = src[i]; //元素赋值 } } return taget; //返回结果数组 } public static int[] changeMethodTwo(int src[]) { //方法2 去掉重复数字 int length = src.length; //获得传入数组的长度 int[] tagetIndex = new int[length]; //声明一个数组,长度为传入数组的长度 int tagetLength = length; for (int i = 0; i < length; i++) { tagetIndex[i] = 0; //初始化tagetIndex } for (int j = 1; j < length; j++) { //记录重复的值 if (src[j] == src[j - 1]) { tagetIndex[j] = 1; tagetLength--; } } //声明数组,长度为传入数组长度-重复数字的个数 int[] target = new int[tagetLength]; int index = 0; for (int k = 0; k < length; k++) { //循环将数组赋值 if (tagetIndex[k] == 0) { //数组元素等于1是存放重复数字 target[index++] = src[k]; } } return target; } public static void main(String[] args) { int[] a = { 1, 1, 1, 2, 3, 4, 5, 6, 9, 9, 12, 53 }; //声明数组并初始化 int[] b = changeMethodOne(a); //调用第一种方法去掉重复数字 System.out.println("第一种方法去掉数组中重复数字结果:"); for (int i = 0; i < b.length; i++) { //将返回的数组输出 System.out.print(b[i] + " "); } System.out.println(); System.out.println("第二种方法去掉数组中重复数字结果:"); int c[] = changeMethodTwo(a); //调用第二种方法去掉重复数字 for (int i = 0; i < c.length; i++) { //将返回的数组输出 System.out.print(c[i] + " "); } } }

(3)运行结果如下所示:

第一种方法去掉数组重复数字结果:
1 2 3 4 5 6 9 12 53 0 0 0
第二种方法去掉数组重复数字结果:
1 2 3 4 5 6 9 12 53

源程序解读

(1)在changeMethodOne()方法中,声明一个与传入数组长度相等的数组,根据循环判断是否有重复的数字,并将不重复的数字放入声明的数组中,如果传入数组中存在重复的数字,那么这个数组的长度应会小于传入数组的长度,这样就造成了数组长度的浪费。

(2)在changeMethodTwo()方法中,也声明一个与传入数组长度相等的数组tagetIndex,值初始化全为0。循环进行判断重复数字的个数,如果存在重复数字则数组tagetIndex元素赋值为1。然后再声明一个数组target,长度为(tagetIndex.length-重复数字个数)。当tagetIndex数组中元素为0的,将数组src元素下标等于tagetIndex元素中不为0的下标的元素值赋值给target。

实例17 求质数(素数)

在所有比1大的整数中,除了1和它本身以外,不再有别的因数,这种整数叫做质数或素数。还可以说成质数只有1和它本身两个约数。本实例将讲解输出在指定范围内所有的质数。

技术要点

本实例主要采用筛选法快速求出指定范围内的质数。技术要点如下:

具体做法是:先把N个自然数按次序排列起来。1不是质数,也不是合数,要划去。第二个数2是质数留下来,而把2后面的所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后面所有能被5整除的数都划去。这样一直做下去,就会把不超过N的全部合数都筛掉,留下的就是不超过N的全部质数。

实现步骤

(1)创建一个类名为TextPrimeNumber.java。

(2)代码如下所示:

package com.zf.s4;                                  //创建一个包
import java.util.Arrays;                            //导入类
public class TextPrimeNumber {                      //操作求指定范围内的质数的类
    private static boolean[] filterNumber(int num){ //筛选法求质数
          if(num<=0){                               //判断指定的范围
              System.out.println("范围必须大于0");
              return null;
          }
          boolean[]isPrime=new boolean[num+1];      //声明布尔类型数组,长度为范围+1
                                  //数组标注是否为质数,下标值为质数,那么对应数组元素值为true
                                                    //例如2是质数,isPrime[2]=true
          isPrime[1]=false;                         //1不是质数
          Arrays.fill(isPrime, 2,num+1,true);       //将布尔数组元素的值都赋为true
          int n=(int)Math.sqrt(num);                //Math.sqrt方法用于求开方
          for(int i=1;i<n;i++){
              if(isPrime[i]){                       //如果是质数,那么i的倍数不是质数
                    for(int j=2*i;j<=num;j+=i){
                        isPrime[j]=false;
                    }
              }
          }
          return isPrime;
    }
    public static void showAppointArea(int number){ //显示指定范围内的质数
          boolean [] primes=FilterNumber(number);   //调用方法赋值给布尔类型的数组
          int num=0;
          if(primes!=null){
              for(int i=1;i<primes.length;i++){     //循环数组操作数组的元素
                  if(primes[i]){                 //如果数组元素值为true,则下标值为质数
                        System.out.print(i+" ");    //输出质数
                        if(++num%10==0)             //每输出10个质数换行
                              System.out.println();
                    }
              }
              System.out.println();
          }
          System.out.println("一共有"+num+"个");
    }
    public static void main(String[] args) {        //Java程序的主入口处
          int number = 200;                         //声明范围
          System.out.println("范围在"+number+"内的质数有:");
          showAppointArea(number);                  //调用方法显示质数
    }
}

(3)运行结果如下所示:

范围在200内的质数有:
2 3 5 7 11 13 17 19 23 29
31 37 41 43 47 53 59 61 67 71
73 79 83 89 97 101 103 107 109 113
127 131 137 139 149 151 157 163 167 173
179 181 191 193 197 199
一共有46个

源程序解读

(1)filterNumber()方法使用筛选法求传入参数值范围内的所有的质数。声明一个布尔类型的数组,数组元素的值为true时,表示该元素的下标为质数。如果number是一个质数,那么number的位数都不是质数,利用Array.fill()方法初始化布尔类型数组,然后利用循环将数组下标为number的倍数的元素值设置为false。这样就能判断哪部分元素是质数了。

(2)showAppointArea()方法调用FilterNumber()方法,得到布尔类型数组,将值为true的元素的下标在控制台输出。

实例18 矩阵的加减和转置

在数学上,矩阵是由方程组的系数及常数所构成的方阵。用在解线性方程组上既方便又直观。生活中通过矩阵多因素探索解决问题。本实例实现了矩阵的基本运算,包括矩阵的构造、矩阵的加法、矩阵的减法和转置矩阵等。

技术要点

技术要点如下:

• 对数组进行初始化有两种方法:在声明变量时直接初始化;运用循环对其进行初始化。

• Java支持多维数组,可以用二维数组表示矩阵。

• 对矩阵进行操作前,需要进行合法性验证,判断它们是否能进行运算。

实现步骤

(1)新建一个类名为TextMatrix.java。

(2)代码如下所示:

package com.zf.s4;                                      //创建一个包
import java.text.DecimalFormat;                         //引入类
public class TextMatrix {                               //操作矩阵的类,使用二维数组
    private double[][]data;                             //矩阵数据
    public TextMatrix(){}                               //默认构造函数
    public TextMatrix(double[][]data){                  //初始化矩阵
          if(CanTransToMatrix(data))                    //判断数组是否能转换成矩阵
              this.data=this.cloneArray(data);
    }
    private static boolean CanTransToMatrix(double[][]data){//判断二维数组能够转换成矩阵
          if(data==null)                                //判断二维数组是否为空
              return false;
          for(int i=0;i<=data.length-2;i++){     //循环依次比较如果长度不等则返回false
              if(data[i].length!=data[i+1].length)      //数组长度比较
                    return false;
          }
          return true;
    }
    public String showArray(double [][]data){         //格式化数组
          DecimalFormat format=new DecimalFormat("0.00");    //数据格式化保留两位小数
          StringBuffer buffer=new StringBuffer("");   //声明StringBuffer可以修改数据
          for(int i=0;i<data.length;i++){
              for(int j=0;j<data.length;j++){           //遍历二维数组按格式显示
                  //将数组元素转换为指定格式
                  buffer.append(format.format(data[i][j])).append(" ");
              }
              buffer.append("\n");//换行
          }
          return buffer.toString();
    }
    public void showData(){                             //调用方法显示二维数组
          System.out.println(showArray(this.data));
    }
    private double[][]cloneArray(double [][]data){      //克隆一个二维数组
          if(data==null)
              return null;
          return (double [][])data.clone();
    }
    public double [][]getMatrixData(){                  //获得矩阵
          return cloneArray(this.data);
    }
    public TextMatrix add(TextMatrix t){                //矩阵加法运算
          if(t==null) return null;
          TextMatrix text=null;
          double [][]tmData=t.getMatrixData();          //获得一个矩阵
          if((this.data.length!=tmData.length) ||
                (this.data[0].length!=tmData[0].length)){ //判断矩阵行数列数是否相等
              System.out.println("两个矩阵大小不一");
              return text;
          }else{
              double [][]result=new double[this.data.length][this.data[0].length];
              for(int i=0;i<this.data.length;i++){                 //依次循环行数
                  for(int j=0;j<this.data[0].length;j++){          //依次循环列数
                        result[i][j]=this.data[i][j]+tmData[i][j]; //两个矩阵相加
                  }
              }
              text=new TextMatrix(result);                  //将新生成的矩阵传入对象中
              return text;                                  //返回对象
          }
    }
    public TextMatrix subtration(TextMatrix t){             //矩阵减法运算
          if(t==null) return null;
          TextMatrix text=null;
          double [][]tmData=t.getMatrixData();              //获得一个矩阵
          if((this.data.length!=tmData.length) ||
                  (this.data[0].length!=tmData[0].length)){//判断矩阵行数列数是否相等
              System.out.println("两个矩阵大小不一");
              return text;
          }else{
              double [][]result=new double[this.data.length][this.data[0].length];
              for(int i=0;i<this.data.length;i++){                 //依次循环行数
                  for(int j=0;j<this.data[0].length;j++){          //依次循环列数
                        result[i][j]=this.data[i][j]-tmData[i][j]; //两个矩阵相减
          }
              }
              text=new TextMatrix(result);                  //将新生成的矩阵传入对象中
              return text;                                  //返回对象
          }
      }
      public TextMatrix transposeMatrix() {        //矩阵转置,格式为a[i][j]=b[j][i]
          int Row = this.data[0].length;
          int Column = this.data.length;
          double[][] change = new double[Row][Column];      //声明一个二维数组,长度指定
          for (int i = 0; i < Row; i++) {
              for (int j = 0; j < Column; j++) {
                    change[i][j] = this.data[j][i];         //循环进行转置
              }
          }
          return new TextMatrix(change);
      }
      public static void main(String []args){               //Java程序的主入口处
          //初始化的方式构造一个二维数组
          double[][]data1=new double[][]{{1.0,2.0,3.0},{4.0,5.0,6.0},{7.0,8.0,9.0}};
          double[][]data2=new double[3][3];                 //声明一个二维数组,没有初始化
          for(int i=0;i<3;i++){                             //for循环依次初始化二维数组
              for(int j=0;j<3;j++){
                    data2[i][j]=2*i+j;                      //进行赋值
              }
          }
          TextMatrix matrix1=new TextMatrix(data1);
          TextMatrix matrix2=new TextMatrix(data2);
          System.out.println("两组二维数组展示:");
          matrix1.showData();                               //二维数组展示
          matrix2.showData();
          System.out.println("矩阵加法运算结果:");
          matrix1.add(matrix2).showData();                  //显示矩阵加法运算结果
          System.out.println("矩阵减法运算结果:");
          matrix1.subtration(matrix2).showData();           //显示矩阵减法运算结果
          System.out.println("矩阵matrix1转置结果:");
          matrix1.transposeMatrix().showData();             //矩阵转置的结果
      }
}

(3)运行结果如下所示:

两组二维数组展示:
1.00 2.00 3.00
4.00 5.00 6.00
7.00 8.00 9.00
0.00 1.00 2.00
2.00 3.00 4.00
4.00 5.00 6.00
矩阵加法运算结果:
1.00 3.00 5.00
6.00 8.00 10.00
11.00 13.00 15.00
矩阵减法运算结果:
1.00 1.00 1.00
2.00 2.00 2.00
3.00 3.00 3.00
矩阵matrix1转置结果:
1.00 4.00 7.00
2.00 5.00 8.00
3.00 6.00 9.00

源程序解读

(1)本实例根据不同的方法对二维数组进行初始化,并采用二维数组存放矩阵的数据。并对要操作的两个数组进行行和列是否一致的判断。

(2)add()方法实现了矩阵的加法运算,根据矩阵加法的条件,判断参与加法的两个矩阵是否可加,并将结果数组变换为矩阵对象返回。

(3)sub()方法实现了矩阵减法运算,当前对象是被减数,输入参数对象是减数。

(4)clone()方法用于克隆一个矩阵。

实例19 数组实现顺序栈与队列

栈和队列是两种特殊的线性表,它们的逻辑结构和线性表相同,只是其运算规则较线性表有更多的限制。本实例介绍如何使用顺序栈、顺序队列和优先队列以及使用的规则和要领。

技术要点

数组实现顺序栈和队列的技术要点如下:

• 栈是一种数据结构,限制仅在表的一端进行插入和删除运算的线性表。其数据项的插入和删除(获取)都只能在称为栈顶的一端完成。因为最后插入的数据项就是最先要删除的数据项。当数据项中没有元素时称为空栈。栈为后进先出(Last In First Out)的线性表,简称LIFO表。

• 顺序栈:栈的顺序存储结构,它是运算受限的顺序表。顺序栈的元素用向量存放。栈底位置是固定不变的,可设置在向量两端的任意一个端点。栈顶位置是随着进栈和出栈操作而变化的,用一个整型量top(栈顶指针)来指示。

• 当程序中同时使用两个栈时,可以将两个栈的栈底设在向量空间的两端,让两个栈各自向中间延伸。当一个栈里的元素较多,超过向量空间的一半时,只要另一个栈的元素不多,那么前者就可以占用后者的部分存储空间。只有当整个向量空间被两个栈占满时,才会发生上溢。因此,两个栈共享一个长度为m的向量空间和两个栈分别占用两个长度」m/2」和 m/2」为的向量空间比较,前者发生上溢的概率比后者要小得多。」

• 队列是只允许在一端进行插入,而在另一端进行删除的运算受限的线性表。允许删除的一端称为队头,允许插入的一端称为队尾,当队列中没有元素时称为空队列。队列可称为先进先出(First In First Out)的线性表,简称FIFO表。

• 顺序队列:队列的顺序存储结构,实际上是运算受限的顺序表。和顺序表一样,顺序队列用一个向量空间来存放当前队列中的元素。由于队列的队头和队尾的位置是变化的,设置两个指针front和rear分别指示队头元素和队尾元素在向量空间中的位置,它们的初值在队列初始化时均应置为0。

实现步骤

(1)新建一个类名为TextStackAndQueue.java。

(2)代码如下所示:

package com.zf.s4;                                   //创建一个包
class Stack {                                        //实现顺序栈的类
    long stackArray[];                               //栈数组
    int size;                                        //栈的大小
    int top;                                         //栈的顶部
    public Stack(int size) {                         //构造方法初始化大小为size的栈
          this.size = size;
          this.stackArray = new long[size];
          this.top = -1;
    }
    public long pop() {                              //出栈操作
          return stackArray[top--];
    }
    public void push(long value) {                   //入栈操作
          stackArray[++top] = value;
    }
    public boolean isEmpty() {                       //判断栈是否为空
          return top == -1;
    }
    public boolean isFull() {                        //判断栈是否已满
          return top == size - 1;
    }
    public long peek() {                             //取栈顶元素
          return stackArray[top];
    }
}
class Queue {                                        // 实现顺序队列的类
    private long queueArray[];                       //队列数组
    private int front;                               //队列的前端下标
    private int rear;                                //队列的尾端下标
    private int size;                                //队列的大小
    private int count;                               //队列中元素的个数
    public Queue(int size) {                         //构造方法初始化大小为size的队列
          this.queueArray = new long[size];
          this.size = size;
          this.front = 0;
          this.rear = -1;
          this.count = 0;
    }
    public void insert(long value) {                 //插入操作
          if (rear == size - 1)                      //队列已满
              rear = -1;
          queueArray[++rear] = value;
          count++;
      }
      public long remove() {                         //删除操作
          long temp = queueArray[front++];
          if (front == size)
              front = 0;
          count--;
          return temp;
      }
      public long peakFront() {                      //返回队列第一个元素
          return queueArray[front];
      }
      public boolean isEmpty() {                     //判断是否为空
          return count == 0;
      }
      public boolean isFull() {                      //判断是否已满
          return count == size;
      }
      public int Count() {                           //返回队列中元素的个数
          return count;
      }
      public void print() {                          //输出队列元素
          for (int i = front; i < front + count; i++) {
              System.out.print(queueArray[i] + "\t");
          }
          System.out.println();
      }
}
class PriorityQueue {                                 //实现优先队列的类
      private int count;                              //队列中元素的个数
      private long priorityArray[];                   //队列数组
      private int size;                               //队列的大小
      public PriorityQueue(int size) {                //构造方法初始化大小为size的队列
          this.size = size;
          this.priorityArray = new long[size];
          this.count = 0;
      }
      public void insert(long value) {                //插入操作
          int i;
          if (count == 0)
              priorityArray[count++] = value;
          else {
          for (i = count - 1; i >= 0; i--) {          //循环找到比插入值大的位置
              if (value < priorityArray[i]) {
                    priorityArray[i + 1] = priorityArray[i];    //依次移动位置
              } else
                    break;
          }
          priorityArray[i + 1] = value;               //插入值放到指定位置
          count++;
          }
      }
      public long remove() {                          //删除操作
          return priorityArray[--count];
      }
      public boolean isEmpty() {                      //判断是否为空
          return count == 0;
      }
      public boolean isFull() {                       //判断是否已满
          return count == size;
      }
      public void print() {                           //输出队列元素
          for (int i = 0; i < count; i++)
              System.out.print(priorityArray[i] + "\t");
          System.out.println();
      }
}
public class TextStackAndQueue {                     //操作顺序栈与队列的类
      public static void main(String[] args) {       //Java程序主入口处
          System.out.println("1.数组实现顺序栈");
          Stack stack = new Stack(6);                //实例化顺序栈,栈的大小为6
          while (!stack.isFull()) {                  //只要栈不满便循环
              long r = (long) (Math.random() * 20);
              stack.push(r);                         //入栈
              System.out.print(r + "\t");
          }
          System.out.println();
          while (!stack.isEmpty()) {                 //只要栈不空便循环
              long value = stack.pop();              //获得栈顶元素
              System.out.print(value + "\t");
          }
          System.out.println();
          System.out.println("-------------------------------------");
          System.out.println("2.数组实现顺序队列");
          Queue queue = new Queue(6);                //实例化顺序队列,队列的大小为6
          while (!queue.isFull()) {                  //只要队列不满便循环
              long value = (long) (Math.random() * 20);
              queue.insert(value);                   //元素插入队列
          }
          queue.print();                             //输出队列元素
          while (!queue.isEmpty()) {                 //只要栈不空便循环
              queue.remove();                        //元素移除
              queue.print();                         //输出队列元素
          }
          queue.print();                             //输出队列元素
          System.out.println(queue.isEmpty());       //队列是否为空?
          System.out.println("-------------------------------------");
          System.out.println("3.数组实现优先队列");
          PriorityQueue priority = new PriorityQueue(6); //实例化顺序队列,队列的大小为6
          while (!priority.isFull()) {                   //只要队列不满便循环
              long value = (long) (Math.random() * 20);
              priority.insert(value);                 //元素插入队列
          }
          priority.print();                           //输出队列元素
    }
}

(3)运行结果如下所示:

1.数组实现顺序栈
10   17    17    6     0     9
9    0     6     17    17    10
-------------------------------------
2.数组实现顺序队列
16   8     18    8     8     9
8    18    8     8     9
18   8     8     9
8    8     9
8    9
9
true
-------------------------------------
3.数组实现优先队列
0    2     6     7     13    18

源程序解读

(1)Stack类实现顺序栈,包括入栈、出栈、置栈空、判断栈是否为空以及判断栈是否已满和取栈内的元素。入栈的push()方法需要将栈顶top加1,需要注意的是,top =size-1表示栈满,当栈满时再做入栈运算产生空间溢出的现象,简称“上溢”。出栈的pop()方法需要将栈顶top减1,top<0表示空栈。当栈空时,做出栈运算产生溢出现象,简称“下溢”。当取栈内元素时,由于栈是先进后出的,则取到的元素是最后放入的元素。

(2)Queue类实现顺序队列,包括入队、出队、置空队列、判断队列是否为空以及判断队列是否已满和取队列中的元素。入队的insert()方法将新元素插入到rear所指的位置,然后rear加1。需要注意的是,rear=size-1表示队列已满,当队列满时,做进栈运算产生空间溢出的现象,简称“真上溢”。当队列中实际的元素个数远远小于向量空间的规模时,也可以由于尾指针已超越向量空间的上界而不能做入队操作,该现象称为“假上溢”。出队的remove()方法删去front所指的元素,然后将front加1并返回被删的元素。当count为空时,做出队运算产生溢出,称为“下溢”。“下溢”常用作程序控制转移的条件。当取队列中的元素时,由于队列是先进先出的,则取到的元素是最先放入的元素。

(3)PriorityQueue类实现优化队列,对队列中的元素进行从小到大的排序。入队的insert()方法循环查找一个大于要插入元素的位置,当找到大于要插入的元素时就跳出,然后为要插入的元素留出位置,将要插入的元素保存到该位置。再根据队列元素是否为空和是否已满条件输出队列中已排序的元素,这样就实现了队列的优化操作。

实例20 Arrays数组的应用

Java中提供Arrays类协助我们对数组的一些基本操作。像排序、搜索与比较等是很常见的。本实例将详细讲解Arrays类操作数组的一些方法和用途。

技术要点

本实例通过操作Arrays类的静态方法来操作数组。技术要点如下:

• 赋值:当配置一个数组之后,会依数据类型来给定默认值。可以使用Arrays.fill()方法将所有的元素设定为指定的值。

• 排序:sort()方法帮助对指定的数组排序,所使用的是快速排序法。

• 查找元素:binarySearch()对已排序的数组进行二分搜索,如果找到指定的值就返回这个值所在的索引,否则就返回负值。

• 比较:equals()比较两个数组中的元素值是否全相等,如果是则返回true,否则返回false。

• 深层比较:deepEquals()对数组作深层比较,简单地说,可以对二维乃至三维以上的数组进行比较,判断是否相等。

• 深层输出:将数组值作深层输出,简单地说,可以对二维乃至三维以上的数组输出其字符串值。

实现步骤

(1)新建一个类名为TextArray.java。

(2)代码如下所示:

package com.zf.s4;                                      //创建一个包
import java.util.Arrays;                                //引入类
import java.util.Scanner;
public class TextArraysMethod {                         //操作Arrays方法的类
    public static void arraysSortAndSearch() {          //使用Arrays对数组排序与搜索
          int[] arr = { 93, 5, 3, 55, 57, 7, 2, 73, 41, 91 }; //声明数组并初始化
          System.out.print("排序前: ");
          for (int i = 0; i < arr.length; i++)
                                                        //循环显示数组元素
              System.out.print(arr[i] + " ");
          System.out.println();
          Arrays.sort(arr);                             //进行排序
          System.out.print("排序后: ");
          for (int i = 0; i < arr.length; i++)
                                                                  //循环显示数组元素
              System.out.print(arr[i] + " ");
          System.out.println("\n请输入搜索值:");
          Scanner scan = new Scanner(System.in);        //接受键盘输出的值
          int number = scan.nextInt();                  //接受一个整数
          int find = -1;
          if((find = Arrays.binarySearch(arr, number))> -1){   //判断是否找到搜索数字
              System.out.println("找到值的索引在第" + find + "位置");
          } else
              System.out.println("找不到指定值");
    }
    public static void arraysCompareAndFill() {          //使用Arrays对数组填充与比较
          int[] arr1 = new int[10];                      //声明数组
          int[] arr2 = new int[10];
          int[] arr3 = new int[10];
          Arrays.fill(arr1, 5);                          //将数组arr1的元素填充为5
          Arrays.fill(arr2, 5);                          //将数组arr2的元素填充为5
          Arrays.fill(arr3, 10);                         //将数组arr3的元素填充为10
          System.out.print("数组arr1中的元素为:");
          for (int i = 0; i < arr1.length; i++)
              System.out.print(arr1[i] + " ");
          System.out.println("\narr1 = arr2 ? " +        //判断数组arr1与arr2是否相等
              Arrays.equals(arr1, arr2));
          System.out.println("arr1 = arr3 ? " +          //判断数组arr1与arr3是否相等
              Arrays.equals(arr1, arr3));
      }
      public static void deepCompareAndDeepToString() {  //使用深层比较和深层输出
          int[][] arr1 = {{1, 2, 3},{4, 5, 6},{7, 8, 9}};    //声明三维数组
          int[][] arr2 = {{1, 2, 3},{4, 5, 6},{7, 8, 9}};
          int[][] arr3 = {{0, 1, 3},{4, 6, 4},{7, 8, 9}};
          System.out.println("数组arr1 内容等于 数组arr2 ? " +
          Arrays.deepEquals(arr1, arr2));                //深层比较数组arr1和数组arr2
          System.out.println("数组arr1 内容等于 数组arr3 ? " +
          Arrays.deepEquals(arr1, arr3));                //深层比较数组arr1和数组arr3
          System.out.println("数组arr1 深层输出(deepToString())\n\t" +
          Arrays.deepToString(arr1));                    //深层输出数组arr1
      }
      public static void main(String[] args) {           //Java程序的主入口处
          System.out.println("1.使用Arrays类的填充和比较方法:");
          arraysCompareAndFill();                        //调用填充与比较的方法
          System.out.println("2.使用Arrays类的深层比较和深层输出方法:");
          deepCompareAndDeepToString();
          System.out.println("3.使用Arrays类的排序与搜索方法:");
          arraysSortAndSearch();                         //调用排序与搜索的方法
      }
}

(3)运行结果如下所示:

1.使用Arrays类的填充和比较方法:
数组arr1中的元素为:5 5 5 5 5 5 5 5 5 5
arr1 = arr2 ? true
arr1 = arr3 ? false
2.使用Arrays类的深层比较和深层输出方法:
数组arr1 内容等于 数组arr2 ? true
数组arr1 内容等于 数组arr3 ? false
数组arr1 深层输出(deepToString())
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3.使用Arrays类的排序与搜索方法:
排序前: 93 5 3 55 57 7 2 73 41 91
排序后: 2 3 5 7 41 55 57 73 91 93
请输入搜索值:
55
找到值的索引在第5位置

源程序解读

(1)arraysSortAndSearch()方法对数组进行排序和搜索。sort()方法可以对整个数组进行排序,也可以根据数组起始位置与结束位置之间的元素进行排序。语法:Arrays.sort(数组,起始位置,结束位置)。应该注意的是:结束位置的元素不会进行排序。binarySearch()方法对数组进行搜索,使用的是二分法。即如果数组中间元素的值比查找的元素大,则只从数组的前半部分元素中查找,否则只从数组的后半部分元素中查找,如此递归下去。因此,在查找元素前必须对数组元素进行升序排序。返回的是查找元素的下标值。如果在数组中找不到查找元素,则返回负数。

(2)arraysCompareAndFill()方法对数组进行填充和比较。fill()方法可以对整个数组赋以初值,也可以对指定位置进行赋值。数组arr1与数组arr2元素值相同,但实际上arr1与arr2是引用自不同的两个组对象。equals()方法用来比较元素值是否相同。不可以用==来比较两个数组的元素值是否相等。

(3)deepCompareAndDeepToString()方法是对多维数组元素的值进行深层比较和输出。方法适用于任意深度的嵌套数组。如果两个数组引用均为null,或者它们引用了包含相同元素数量的数组,并且两个数组中的所有相应元素对都是深层相等的,则认为这两个数组引用是深层相等的。数组arr1与数组arr2中的相应元素对都是深层相等的,所以进行深层比较之后,返回true。如果满足以下任意条件之一,则两个null元素el和e2可以是深层相等:

e1和e2都是对象引用类型的数组,并且Arrays.deepEquals(e1,e2)将返回true。

e1和e2都是相同基本类型的数组,并且Arrays.equals(e1,e2)的适当重载将返回true。

e1.equals(e2)将返回true。

如果指定数组中的任意一个数组,直接或间接通过一个或多个数组级别,包含数组本身作为其元素,则此方法的行为是不确定的。