Java 中的数据结构和算法,第 2 部分:一维数组

开始使用一维数组和数组变量,然后尝试在 Java 程序中搜索和排序数组的五种算法

一个阵列是一个基本的数据结构的类别,和用于更复杂的数据结构的构造块。在数据结构和算法系列的第二篇教程中,您将学习如何在 Java 编程中理解和使用数组。我将从数组的概念以及数组在 Java 语言中的表示方式开始。然后,我将向您介绍一维数组以及在 Java 程序中使用它们的三种方法。最后,我们将探讨用于搜索和排序一维数组的五种算法:线性搜索、二分搜索、冒泡排序、选择排序和插入排序。

请注意,本教程基于数据结构和算法,第 1 部分,其中介绍了数据结构的理论方面以及与之相关的算法。该教程包括对算法的深入讨论,以及如何使用空间和时间复杂度因素来评估和选择最有效的 Java 程序算法。我们将在本教程中获得更多实践,因为我假设您已经阅读了第 1 部分。

什么是数组?

一个阵列是其中每个元素与至少一个索引相关联元素的序列。一个元素是一组存储的单个数据项的存储位置。一个指数是一个非负整数,而在这种情况下,用于唯一地标识的元素。这种关系类似于箱号如何唯一标识给定街道上的房屋。

与任何元素关联的索引数是数组的维度。在本文中,我们将讨论一维数组。本系列的下一篇文章将介绍多维数组。

Java 支持数组。每个元素占用相同的字节数,确切的数字取决于元素的数据项的类型。此外,所有元素共享相同的类型。

Java 数组不可调整大小

Java 数组具有固定大小。创建数组后,您无法更改数组的大小。相反,如果您需要更改数组的大小,您将创建另一个所需大小的数组,并将所有所需元素从原始数组复制到新数组。

一维数组

最简单的一种数组只有一维。阿一维阵列的每个元素具有一个索引相关联。一维数组用于存储数据项列表。在 Java 中创建一维数组的技术有以下三种:

  • 仅使用初始化程序
  • 仅使用关键字 new
  • 将关键字new与初始化程序一起使用

仅使用初始值设定项创建一维数组

以下是仅使用初始化程序创建一维数组的语法:

'{' [expr (',' expr)*] '}'

此语法声明一维数组是一个可选的、以逗号分隔的表达式列表,它们出现在左括号和右括号字符之间。此外,所有表达式都必须评估为兼容的类型。例如,在doubles的二元素一维数组中,两个元素可能都是 类型double,或者一个元素可能是 adouble而另一个元素是 afloat或整数类型(例如int)。

例子:

使用关键字 new 创建一维数组

关键字new为数组分配内存并返回其引用。这是这种方法的语法:

'new' type '[' int_expr ']'

此语法指出,一维数组是int_expr共享相同的(正)元素的区域type。此外,所有元素都归零,并被解释为0、0L、0.0F、0.0、false、null、'\u0000'

例子:

new char[4]

使用“new”关键字和初始值设定项创建一维数组

下面是使用new带有初始值设定项的关键字创建一维数组的语法。如您所见,它融合了前两种方法的语法:

'new' type '[' ']' '{' [expr (',' expr)*] '}'

在这种情况下,因为可以从逗号分隔的表达式列表中确定元素的数量,所以没有必要(或允许)int_expr在方括号之间提供。

例子:

new char[] {
    'J', 'a', 'v', 'a' }

需要注意的是,仅使用初始值设定项创建数组的语法与使用初始值设定项和关键字的语法没有区别。仅初始化程序语法是语法糖的一个示例,这意味着使语言更甜美或更易于使用的语法。

数组变量

就其本身而言,新创建的一维数组是无用的。它的引用必须直接或通过方法调用分配给兼容类型的数组变量。以下两行语法显示了如何声明此变量:

type var_name '[' ']'
type '[' ']' var_name

每个语法声明一个数组变量,用于存储对一维数组的引用。虽然你可以使用语法,将方括号后type的首选。

例子:

char[] name1 = {
    'J', 'a', 'v', 'a' };
char[] name2 = new char[4];
char[] name3 = new char[] {
    'J', 'a', 'v', 'a' };
output(new char[] {
    2, 3 }); // output({ 2, 3 }); results in a compiler error
static void output(char[] name)
{
   
   // ...
}

在示例中name1,name2、name3、 和name是数组变量。一对方括号表示每个方括号都存储对一维数组的引用。

关键字char表示每个元素必须存储一个char类型的值。但是,char如果 Java 可以将其转换为char. 例如,char[] chars = { 'A', 10 };是合法的,因为它10是一个足够小的正数int(意味着它适合char065535的范围)要转换为char。相比之下,char[] chars = { 'A', 80000 };就违法了。

数组变量与一个.length属性相关联,该属性将关联的一维数组的长度作为正数返回int;例如,name1.length返回 4

给定一个数组变量,您可以通过指定符合以下语法的表达式来访问一维数组中的任何元素:

array_var '[' index ']'

这里,index是一个正数int,范围从 0(Java 数组从零开始)到比从.length属性返回的值小 1 。

例子:

char ch = names[0]; // Get value.
names[1] = 'A';     // Set value.

如果指定负索引或大于或等于数组变量.length属性返回值的索引,Java 将创建并抛出一个java.lang.ArrayIndexOutOfBoundsException对象。

搜索和排序算法

搜索特定数据项的一维数组是一项非常常见的任务,并且有多种算法可以执行此操作。最流行的搜索算法之一称为线性搜索。另一种选择是二分搜索,它通常性能更高,但要求也更高:为了使用二分搜索,必须首先对数组的数据项进行排序或排序。虽然性能不高,但冒泡排序、选择排序和插入排序都是对一维数组进行排序的简单算法。对于较短的数组,每个都足够好。

下一节将介绍这些用于搜索和排序一维数组的算法。

空间复杂度

本节中讨论的每个算法——线性搜索、二分搜索、冒泡排序、选择排序和插入排序——都展示了 O(1)(常数)空间复杂度的变量存储。本系列的第 1 部分将算法的空间复杂度定义为算法完成其任务所需的额外内存量。

线性搜索算法

线性搜索在n 个数据项的一维数组中搜索特定项。它的功能是比较从最低索引到最高索引的数据项,直到找到指定的数据项,或者直到没有更多的数据项可供比较。

以下伪代码表示用于一维整数数组的线性搜索:


DECLARE INTEGER i, srch = ...
DECLARE INTEGER x[] = [ ... ]
FOR i = 0 TO LENGTH(x) - 1
   IF x[i] EQ srch THEN
      PRINT "Found ", srch
      END
   END IF
NEXT i
PRINT "Not found", srch
END

考虑一个由五个整数 [ 1, 4, 3, 2, 6 ] 组成的一维无序数组,其中整数 1 位于索引 0,整数 6 位于索引 4。伪代码执行以下任务以在其中找到整数 3这个数组:

  1. 将索引 0 (1) 处的整数与 3 进行比较。
  2. 由于没有匹配项,请将索引 1 (4) 处的整数与 3 进行比较。
  3. 由于仍然没有匹配项,请将索引 2 (3) 处的整数与 3 进行比较。
  4. 因为有匹配项,所以打印Found 3并退出。

线性搜索的时间复杂度为 O( n ),发音为“Big Oh of n”。对于n 个数据项,该算法最多需要n 次比较。平均而言,它执行n / 2 次比较。线性搜索提供线性性能。

效率

线性搜索算法的一个缺点是效率低下。对于包含 4,000,000 个数据项的数组,它将执行平均 2,000,000 次比较以找到指定的项。

探索线性搜索

为了让您试验线性搜索,我在清单 1 中创建了Java 应用程序。

清单 1. 使用线性搜索算法的 Java 示例


{
   
   public static void main(String[] args)
   {
   
      // Validate command line arguments count.

      if (args.length != 2)
      {
   
         System.err.println("usage: java LinearSearch integers integer");
         return;
      }

      // Read integers from first command-line argument. Return if integers 
      // could not be read.

      int[] ints = readIntegers(args[0]);
      if (ints == null)
         return;

      // Read search integer; NumberFormatException is thrown if the integer
      // isn't valid.

      int srchint = Integer.parseInt(args[1]);

      // Perform the search and output the result.

      System.out.println(srchint + (search(ints, srchint) ? " found"
                                                          : " not found"));
   }

   private static int[] readIntegers(String s)
   {
   
      String[] tokens = s.split(",");
      int[] integers = new int[tokens.length];
      for (int i = 0; i < tokens.length; i++)
         integers[i] = Integer.parseInt(tokens[i]);
      return integers;
   }

   private static boolean search(int[] x, int srchint)
   {
   
      for (int i = 0; i < x.length; i++)
         if (srchint == x[i])
            return true;

      return false;
   }
}

该LinearSearch应用程序读取一个逗号分隔从其第一命令行参数的整数列表。它在数组中搜索由第二个命令行参数标识的整

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值