JAVA开发讲义(二)-Java程序设计之数据之谜四

本文深入探讨Java程序设计中的数组和大数值处理,包括BigInteger和BigDecimal的使用,数组的创建、访问、初始化及遍历,以及多维数组和不规则数组的概念。通过实例代码,帮助读者理解和掌握相关知识。
摘要由CSDN通过智能技术生成

JAVA开发讲义(二)-Java程序设计之数据之谜四

程序之美

在这里插入图片描述

今天,又一不小心,听到同事说:“看,空指针”、“数组越界了,所以异常了!”,数组,一个不起眼的名词,在程序开发中,起着关乎全局的作用,可以毫不夸张的说,我们写的代码,其中有40%左右,都和 数组相关,数据结构中,数组也占着非常重要的权重和位置,不管是排序算法也好,背包算法也好,你随眼扫一下代码块,都和数组脱离不了关系,所以也可以这样说,数组处理能力是考验一个程序员是否优秀的一个重要的指标,也是程序员们的基本功,在程序员改Bug的过程中,有60%的Bug可能都是数组使用不当引起的,我们在初学代码时,数组也是我们认为难以理解和接受的。
既然“数组如此重要,我们这一篇就来着重介绍数组,同时也会介绍大数值相关的知识,并且配有相应的实例代码,帮助小伙伴们理解与消化,我相信,经过这一篇的讲解,不管时在校的,还是就业的,或者是正在不断面试的朋友们,你们都能有所收获,有所提升。
在这里插入图片描述

大数值

如果基本的数据结构不能满足你的需求,java.math包中提供了两个很有用的类:BigInteger和BigDecimal。这两个类可以处理任意长度数字序列的值,BigInteger类可以处理任意精度的整型运算,BigDecimal类可以处理任意精度的浮点数运算。将任意整型数值转换为大数值如下:

BigInteger a = BigInteger.valueOf(100);

大数值的加减乘除,都需要使用自身所带的方法来完成,不能使用算术运算符。如下:

BigInteger a = BigInteger.valueOf(100);
BigInteger b = BigInteger.valueOf(300);
BigInteger c = a.add(b);// c = a + b;
BigInteger d = c.multiply(b.add(BigInteger.valueOf(2)));//d = c * (b +2)

下面我们看下彩票概率程序的改进,使其可以采用大数值进行运算。

import java.math.*;
import java.util.*;
 
/**
 * This program uses big numbers to compute the odds of winning the grand prize in a lottery.
 * @version 1.20 2004-02-10
 * @author Cay Horstmann
 */
public class BigIntegerTest
{
   public static void main(String[] args)
   {
      Scanner in = new Scanner(System.in);
 
      System.out.print("How many numbers do you need to draw? ");
      int k = in.nextInt();
 
      System.out.print("What is the highest number you can draw? ");
      int n = in.nextInt();
 
      /*
       * compute binomial coefficient n*(n-1)*(n-2)*...*(n-k+1)/(1*2*3*...*k)
       */
 
      BigInteger lotteryOdds = BigInteger.valueOf(1);
 
      for (int i = 1; i <= k; i++)
         lotteryOdds = lotteryOdds.multiply(BigInteger.valueOf(n - i + 1)).divide(
            BigInteger.valueOf(i));
 
      System.out.println("Your odds are 1 in " + lotteryOdds + ". Good luck!");
   }
}

按照算数运算符核心算法为:

lotteryOdds = lotteryOdds *(n - i + 1) / i;

使用大数据就是:

lotteryOdds = lotteryOdds.multiply(BigInteger.valueOf(n - i + 1)).divide(
            BigInteger.valueOf(i));

下面我们罗列下大数据常用的几个函数:
BigInteger类:

1、BigInteger add(BigInteger other);
2、BigInteger subtract(BigInteger other);
3、BigInteger multiply(BigInteger other);
4、BigInteger divide(BigInteger other);

以上为加减乘除运算

5、BigInteger mod(BigInteger other);

该函数返回本大数与另一个大数other的余数。

6、int compareTo(BigInteger other);

如果本大数与另一个大数other相等,返回0,如果本大数小于另一个大数other,返回负数,否则返回正数。

7、static BigInteger valueOf(long x);

返回值等于x的大整数,通俗一点说就是long类型转换为大数。

BigDecimal类:

1、BigDecimal add(BigDecimal other);
2、BigDecimal subtract(BigDecimal other);
3、BigDecimal multiply(BigDecimal other);
4、BigDecimal divide(BigDecimal other RoundingMode mode);

为大数的加减乘除等,这里说下RoundingMode舍入方式,即为四舍五入方式。

5、int compareTo(BigDecimal other);

如果本大数与另一个大数other相等,返回0,如果本大数小于另一个大数other,返回负数,否则返回正数。

6、static BigDecimal valueOf(long x);

返回值等于x的大实数,通俗一点说就是long类型转换为大数。

7、static BigDecimal valueOf(long x, int scale);

返回值为x/(10的scale次方)的大实数。
在这里插入图片描述

数组

画重点了,数组,数组,数组,数组是一种数据结构,用来存储同一类型值的集合。通过数组的下标来进行数组访问。如下我们定义一个数组:

int[] a;
a = new int[100];//开辟100个整型空间,这样就创建了一个可以存储100个整型的数组。

由上面可知,我们可以通过new int[n]创建一个长度为n的数组。
如何访问数组呢
a[0] 访问第0个空间
a[1] 访问第1个空间
a[2] 访问第2个空间

如果我们加入for循环

for(int i = 0; i < 100; i ++){
System.out.println(a[i]);
}

我们就可以将数组a中的100个元素遍历输出;这时我们输出出来的就都是0,为什么呢?因为我们没有给他们进行赋值操作,他们都是默认值0,故而输出全是0;
那么怎么进行赋值呢?

a[0] = 0;
a[1] = 1;

如果我们加入for循环

for(int i = 0; i < 100; i ++){
a[i] = i;
}

我们就完成了对数组a的赋值操作,下面我们看下整体代码:

import java.math.BigInteger;
import java.util.Date;
import java.util.Scanner;

public class Test2 {
public static void main(String[] args) {

   int[] a = new int[100];
   for(int i = 0; i< 100; i++) {
	   a[i] = i;
   }
   
   for(int i = 0; i< 100; i++) {
	   System.out.println(a[i]);
   }
}
}

在这里插入图片描述

for each 循环
java有一种很强的循环能力,可以依次处理数组中的每个元素,不用过多的牵扯下标值。增强的for循环的语句格式为:

for(variable : collection) statement

实例代码为:

int[] a = new int[100];
for(int b: a){
System.out.println(b);
}

这样就可以打印数组中的每一个元素,每个元素占一行。
java语言的设计者认为应该使用诸如foreach、in这样的关键字,但由于其最初不是包含在java语言中的,而是后期添加进去的,需要废弃已经包含同名方法或变量的就代码。
传统的for循环可以达到同样的效果:

for(int i = 0; i< 100; i++) {
   System.out.println(a[i]);
}

相比而言,for each循环语句会遍历数组中的每一个元素值,而不使用下标,它显得更加简洁、更不容易出错。当然我们也可以使用数组函数完成此功能,如:Arrays类的toString方法,具体如下:

System.out.println(Arrays.toString(a));

一样可以实现输出打印的效果。
数组的初始化以及匿名数组
数组初始化

int[] primes = {1, 4, 5, 6, 7, 8, 9};//这种初始化不需要new

当然我们也可以初始化一个匿名数组。

new int[]{3, 5, 6, 8, 9};

另外还可以这样:

int[] primes;
primes = new int[]{3, 5, 6, 8, 9};

这里我们一样需要着重讲下空指针。如下:

int[] a;
for(int b: a){//a保空指针
System.out.println(b);
}

数组长度为0和空指针是不同的,我们可以new一个长度为0的元素,但是他是有指向,有地址的,而空指针则没有,这里要特别注意:

int[] f = new int[0];
int[] b;
System.out.println(b);//报空指针
System.out.println(f);

数组拷贝
数组拷贝即为一个数组的元素拷贝给另外一个元素。这里我们可以通过两种方式来实现这个操作。
一种为:

int[] a = new int[]{1, 3, 5, 7, 9};
int[] b = new int[5];
for(int i = 0; i < 5; i++){
b[i] = a[i];
}

在这里插入图片描述

另外一种我们要借助与Arrays类的CopyOf函数,具体如下:

b = Arrays.copyOf(a, a.length);

对于int型的数组,如果b开辟的空间比a大,那么多余的元素将被赋值为0;如果元素是boolean类型,则将被赋值为false,相反,如果b小于a的空间,那么只拷贝前面的元素。
JAVA数组和C++在堆栈上有着很大的区别,基本上分配在堆上的数组指针是一样的。如:

int[] a = new int[100];//java

不同于:

int a[100];//c++

却相同于:

int* a = new int[100];//c++

命令行参数
在我们写java程序时,我们可能会留意到JAVA的main函数带有一个String[] args参数,这就是main函数接收的命令行参数,也是一个字符串数组。如下:

public class Message{
public static void main(String[] args){
if(args.length == 0 || args[0].equals("-h"))
System.out.print("Hello");
else if(args[0].equals("-g")){
System.out.print("Goodbye,");

for(int i = 0; i < args.length; i ++){
System.out.print(" " + args[i]);
}
System.out.print("!";
}
}
}

可以通过如下形式运行:

gava Message -g cruel word

args[0]:"-g"
args[1]:“cruel”
args[2]:“word”

输出结果为:

Goodbye,-g cruel word!

在这里插入图片描述

数组排序

java中的在数组排序可以手动排序,比如使用排序算法:冒泡算法,选择算法,插入算法等进行排序,也可借助与Arrays类sort方法进行排序。个人推荐使用Arrays.sort方法,因为这个方法使用了优化的快速排序算法。
下面我们看下其排序结果。

   int[] a = new int[]{8, 6, 6, 7, 8, 3, 5, 0, 12, 5};
   Arrays.sort(a);
   for(int r : a){
   System.out.printf("%d ", r);
   }
}

结果为:0 3 5 5 6 6 7 8 8 12

下面我们讲下Arrays类中的相关函数。

1、static String toString(type[] a) 5.0

返回包含a中数据元素的字符串,这些数据元素被放在括号内,并用逗号分隔;
参数a可以是:int,long, short, char, byte, boolean, float或double的数组。

2、static type copyOf(type[] a, int length) 6

拷贝字符串,返回一个a数组的拷贝。

3、static type copyOfRange(type[] a, int start, int end) 6

返回与a类型相同的一个数组,其长度为length或者end-start,素组元素为a的值
参数a可以是:int,long, short, char, byte, boolean, float或double的数组
参数start:起始下标(包含这个值)
参数end:终止下标(不包含这个值)。如果end > a.length,那么结果为0或false。
参数length:拷贝数组的长度。如果length值大于a.length,结果为0或者false;否则,数组中只有前面的length个数据元素的拷贝值。

4、static void sort(type[] a)

采用优化快速排序算法对数组进行排序。
参数a可以是:int,long, short, char, byte, boolean, float或double的数组

5、static int binarySearch(type[] a, type v)
6、static int binarySearch(type[] a, int start, int end, type v) 6

采用二分搜索算法查找值v。如果查找成功,则返回相应的下标值;否则,返回一个负数值r。-r-1是为了保持a有序v应插入的位置。
参数a可以是:int,long, short, char, byte, boolean, float或double的数组
start: 起始下标(包含这个值)
end:终止下标(不包含这个值)
v:同a的数据元素类型相同的值。

7、static void fill(type[] a, type v)

将数组的所有数据元素值设置为v。
参数a可以是:int,long, short, char, byte, boolean, float或double的数组
v:与a的数据元素类型相同的值。

8、static boolean equals(type[] a, type[] b)

如果两个数组大小相同,并且下标相同的元素都对应相等,返回true。
参数a、b 类型为:int,long, short, char, byte, boolean, float或double的数组
在这里插入图片描述

多维数组
多维数组是相对于一维数组来说的,这也让我想到了我们初高中时学习的坐标系,一维成线,二维成面,三维成体,当然这个口诀也适用与多维数组,对于一维数组,我们可以理解成他就是一个顺序表,而二维数据,我们可以理解成他是一个面,巨型的面,三维数组我们可以理解为他是一个长方体,当三维相等是就是正方体了,当然理解可以这个样理解,在计算机里的存储和布局就不是这样的了,我们只是方便理解罢了。

一维数组:int[] a = new int[]{1,2,4,5};
二维数组:int[][] b = new int[][]{{1,2,4,5},{1,2,4,5},{1,2,4,5}};
三维数组:int[][][] c = new int[][][]{{{1,2,4,5},{1,2,4,5},{1,2,4,5}},{{1,2,4,5},{1,2,4,5},{1,2,4,5}},{{1,2,4,5},{1,2,4,5},{1,2,4,5}}}

当然也包含四维,五维数组等。感兴趣的朋友可以深入理解下。
一但数组被初始化,就可以利用两个或多个方括号访问每个元素。比如二维b[i][j],三维c[i][j][k]等。
多维数数组的遍历
二维数组:

for(double[] row: a)
for(double value:row)
do something with value

想要快速打印一个二维数组的数据元素。可以如下操作:

System.out.println(Arrays.deepToString(b))

完整实例:

public class CompoundInterest
{
  public static void main(String[]args)
  {
    final int STARTRATE=10;
    final int NRATES=6;
    final int NYEARS=10;
    double[]interestRate=new double[NRATES];
    for(int j=0;j<interestRate.length;j++)
      interestRate[j]=(STARTRATE+j)/100.00;
    double[][] balances=new double[NYEARS][NRATES];
    for(int j=0;j<balances[0].length;j++)
      balances[0][j]=10000;
    for(int i=1;i<balance.length;i++)
    {
      for(int j=0;j<balances[i].length;j++)
      {
        double oldBalance=balance[i-1][j];
        double interest=oldBalance*interestRate[j];
        balances[i][j]=oldBalance+interest;
      }
    }
    for(int j=0;j<interestRate.length;j++)
      System.out.printf("%9.0f%%",100*interestRate[j]);
    System.out.println();
    for(double[]row:balances)
    {
      for(double b:row)
        System.out.printf("%10.2f",b);
      System.out.println();
    }
  }
}

不规则数组
JAVA实际上没有多维数组,只有一维数组,多维数组被理解为"数组的数组",例如在前面的实例中,balances数组实际上是一个包含10个元素的数组,而每个元素又是一个由6个浮点数组成的数组,参见下图。
在这里插入图片描述

表达式balances[i]引用第i个子数组,也就是二维表的第i行。它本身也是一个数组,balances[i][j]引用这个数组的第j项。
由于可以单独的存取数组的某一行,所以可以让两行交换。

double[] temp = balances[i];
balances[i] = balances[i + 1];
balances[i + 1] = temp;

可以构造一个“不规则”数组,即数组的每一行有不同的长度。如下实例:

public class YanghuiThree {
    public static void main(String[] args){
        int[][] arr=new int[6][6];
        //生成竖线和对角线
        for(int i=0;i<6;i++){
            arr[i][i]=1;
            arr[i][0]=1;
        }
        //根据头上的元素和头上左边的元素生成该元素
        for(int i=2;i<6;i++){
            for(int j=1;j<=i-1;j++){
                arr[i][j]=arr[i-1][j]+arr[i-1][j-1];
            }
        }
        //打印输出结果
        for(int i=0;i<6;i++){
            for(int j=0;j<=i;j++){
                System.out.print(arr[i][j]+" ");
            }
            System.out.println();
        }
    }
}

其结果为:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1

杨辉三角地打印就是不规则数组使用的典型案例。上述我们是通过开辟int[6][6]规则数组完成的,那么如何通过不规则数组完成呢,见如下代码:

/**
 * This program demonstrates a triangular array.
 * @version 1.20 2004-02-10
 * @author Cay Horstmann
 */
public class LotteryArray
{
   public static void main(String[] args)
   {
      final int NMAX = 10;

      // allocate triangular array
      int[][] odds = new int[NMAX + 1][];
      for (int n = 0; n <= NMAX; n++)
         odds[n] = new int[n + 1];

      // fill triangular array
      for (int n = 0; n < odds.length; n++)
         for (int k = 0; k < odds[n].length; k++)
         {
            /*
             * compute binomial coefficient n*(n-1)*(n-2)*...*(n-k+1)/(1*2*3*...*k)
             */
            int lotteryOdds = 1;
            for (int i = 1; i <= k; i++)
               lotteryOdds = lotteryOdds * (n - i + 1) / i;

            odds[n][k] = lotteryOdds;
         }

      // print triangular array
      for (int[] row : odds)
      {
         for (int odd : row)
            System.out.printf("%4d", odd);
         System.out.println();
      }
   }
}

在这里插入图片描述

好了,到此为止,java基本程序设计结构我们就全部讲完了,从下篇开始我们就开始java的精髓“对象和类”了,不知小伙伴们是否有收获,如果有什么疑问可以给我留言,或者私信我,我都会在工作之余给以回复,但愿能够在大家前进的旅途中起到增砖添瓦的作用,很感谢朋友们能在百忙之中阅读这篇文章。能够帮到大家是我最大的幸福。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五一编程

程序之路有我与你同行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值