Java中的内置数据结构介绍

331 阅读5分钟

Java中的内置数据结构介绍

在这篇文章中,我们将了解Java中使用的各种内置数据结构。在本文结束时,你将了解到内置数据结构如何比Java中用户定义的数据结构更有效。

你还将学习如何使用内置数据结构。

简介

根据维基百科,数据结构是一种数据组织、管理和存储格式,能够有效地访问和修改。

更确切地说,数据结构是一个数据值的集合,它们之间的关系,以及可以应用于数据的功能或操作。

内置与用户定义的数据结构

像Stack或Queue这样的数据结构可以用其他基本数据结构自行创建。例如,堆栈可以用数组或链接列表来创建。这些被称为用户定义的数据结构。

内置数据结构不需要从头开始创建数据结构。但是,我们可以利用预先建立的方法来抽象出数据结构的工作。

使用内置数据结构,提高了开发者的工作效率,因为为用户定义的数据结构编写操作是很耗时的,而且不能保证效率。另外,内置数据结构的编写通常具有最有效的时间和空间复杂度。

时间和空间复杂度是衡量代码的标准,确保在运行代码片段时有效地使用时间和内存。通过减少这些复杂度,可以提高数据结构的效率。

数据结构

现在,让我们来看看几个内置的数据结构,我们将看到如何使用它们。

阵列列表

java.util 包中,ArrayList 是一个内置的数据结构,与Array 非常相似。

ArrayArrayList 之间的区别是大小。在Array 中,长度是固定的,所以分配给存储值的内存是固定的。而在ArrayList ,列表是可调整大小的,这使得开发者可以选择一个动态大小。在这里,内存是动态创建的。

创建ArrayList的语法。

import java.util.ArrayList; // Import the ArrayList class

ArrayList<String> list1 = new ArrayList<String>(); // Create an ArrayList object

在我们继续使用内置方法之前,让我们建立一个用户定义的函数来显示ArrayList 中的所有元素。

void printArrayList(ArrayList<String> list) {
  for (int i = 0; i < list.size(); i ++) {
    System.out.print(list.get(i) + " ");
  }
  System.out.println();
}

添加元素

当使用Array ,我们必须手动将值或变量分配给特定的索引。但是,在ArrayList 中,通过使用add() 方法,向列表中添加元素变得更加简单。

例子。

list1.add("Hello"); // Add "Hello" to the ArrayList
printArrayList(); // OUTPUT: list1 = ["Hello"]
list1.add("World"); // Add "World" to the ArrayList
printArrayList();  // OUTPUT: list1 = ["Hello", "World"]

输出。

Hello
Hello World

更新元素

Array 中更新元素类似于加法,即找到数组的索引并替换成所需的值。

ArrayList 中,我们使用set(index, value) 方法在一个特定的index 替换元素value

例子。

list1.set(1, "Welcome"); // Replaces "World" with "Welcome" in list1
printArrayList();  // OUTPUT: list1 = ["Hello", "Welcome"]

输出。

Hello Welcome

移除元素

Array ,由于分配的内存是固定的,所以不可能删除元素。

ArrayList ,删除元素可以通过remove(int index) 方法来完成。在指定indexArrayList ,将元素从内存中移除,其余的元素被移动以填补空间。因此,它的内存效率更高。

例子。

list1.remove(0); // Removes "Hello" from list1
printArrayList(); // OUTPUT: list1 = ["Welcome"]
list1.remove(1); // Remove element from Empty list
printArrayList(); // Exception

输出。

Welcome
java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 0

链接列表

链接列表是使用指针连接的线性数据结构,并持有数据。指针被用来存储和管理动态分配的内存块的地址。内存分配是不连续的,这使得它比使用数组更好。

在Java中创建链表时,我们必须创建一个类来定义链表的每个节点的结构。下面是一个演示在用户定义的链表中创建指针的示例类。

class Node { // Node class containing a single pointer and data
  Node next; // 'next' is used as pointer
  int data; // 'data' is used for storing values in the node
  // Constructor for initializing the variables
  Node() { 
    next = null;
    data = 0;
  }
}

java.util 包中,我们通过使用LinkedList 数据结构,简化了手动创建内存处理的任务。它包含预定义的方法来建立一个链表数据结构。

创建LinkedList 数据结构的语法。

import java.util.LinkedList; // Import package

LinkedList<String> list2 = new LinkedList<String>(); // Create new object

在我们继续使用内置方法之前,让我们建立一个用户定义的函数来显示LinkedList 的所有元素。

void printLinkedList(LinkedList<String> list) {
  for (int i = 0; i < list.size(); i ++) {
    System.out.print(list.get(i) + " ");
  }
  System.out.println();
}

添加元素

在用户定义的链表数据结构中,当添加新数据时,我们必须手动移动指针并分配数据。而在LinkedList 数据结构中,我们使用add(Object)add(int index, Object) 方法来添加新元素。

例子。

list2.add("Hello"); // Add "Hello" to the LinkedList list2
printLinkedList(); // OUTPUT: ["Hello"]
list2.add("World"); // Add "World" to the LinkedList list2
printLinkedList(); // OUTPUT: ["Hello", "World"]
list2.add(1, "Computer"); // Add "Computer" to the LinkedList list2 at index 1
printLinkedList(); // OUTPUT: ["Hello", "Computer", "World"]

输出。

Hello
Hello World
Hello Computer World

更新元素

为了更新用户定义的链表中的元素,我们必须从 "HEAD "指针开始遍历整个链表以更新特定的数据。

LinkedList 数据结构用 方法抽象了整个过程。set(index, data)

例子。

list2.set(0, "Welcome"); // Update the string at index 0 to "Welcome"
printLinkedList(); // OUTPUT: ["Welcome", "Computer", "World"]

输出。

Welcome Computer World

删除元素

同样,在用户定义的链表中删除一个元素时也会很麻烦,前一个元素的指针被指向下一个元素的地址。在处理巨大的数据时,与指针打交道并不简单。

在用户定义的链表中删除一个元素的情况发生在下面的步骤中。

  • 初始化一个指针nodenode = head
  • 遍历链表,直到到达你想删除的元素(node.next.val != value)。
  • 在到达该节点时,我们将node 指向node.next.next ,这意味着,我们将前一个节点指向下一个节点。node = node.next.next.

通过使用内置数据结构,我们可以避免使用remove(Object) 方法来删除链表中的元素。

例子。

list2.remove(1); // Removes "Computer" from list2
printLinkedList(); // OUTPUT: ["Welcome", "World"]
list2.remove(0); // Remove "Welcome" from list2
list2.remove(0); // Remove "World" from list2
printLinkedList(); // Empty list
list2.remove(0); // Remove elements from Empty list

输出。

Welcome World

java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0

HashMap

Map是一种数据结构,可以帮助我们对Key和Value对进行映射。同样,在Java中,我们利用HashMap ,它通过一个索引对Key进行散列。通过散列,我们将能够通过指定索引来访问值。

创建一个HashMap 的语法。

import java.util.HashMap; // Importing package

HashMap<Integer, String> map1 = new HashMap<Integer, String>(); // Creating a HashMap object

添加元素

HashMap 是一个重要的数据结构,当映射键和值时,有助于以非常小的平均时间复杂度O(1)访问元素。为了映射一个键与一个值,我们可以利用 方法。put(key, value)

使用HashMap ,增加或访问或删除一个元素的平均时间复杂度是O(1)。

例子。

map1.put(0, "A"); // Map (0, "A") and hash the key
map1.put(1, "B"); // Map (1, "B") and hash the key
System.out.println(map1); // OUTPUT: map1 = {0="A", 1="B"}

输出。

{0=A, 1=B}

更新元素

同样,在更新元素时,我们可以再次使用添加新元素时使用的相同方法。

例子。

map1.put(0, "B"); // Map (0, "B") and hash the key
map1.put(1, "C"); // Map (1, "C") and hash the key
System.out.println(map1); // OUTPUT: map1 = {0="B", 1="C"}

输出。

{0=B, 1=C}

删除元素

当从HashMap 删除映射时,我们将利用remove(index) 方法来删除所述索引的值。

例子。

map1.remove(0); // Remove mapping (0, "B") from map1
System.out.println(map1); // OUTPUT: map1 = {1="C"}

输出。

{1=C}

堆栈

Stack 是一种线性数据结构,与ArrayList 非常相似。但是,它是基于后进先出(LIFO)的原则。用更简单的话来说,后进先出可以解释为哪一个元素最后被添加,就必须先被删除。

由于它是一个基于后进先出原则的线性数据结构,通过指定索引来访问最后一个元素是不可能的。通过利用Stack 数据结构,可以避免在特定索引处访问数值的一系列步骤。

构建一个Stack 数据结构的语法。

import java.util.Stack; // Import Stack package

Stack<Integer> stack = new Stack<Integer>(); // Creating object for Stack

添加元素

添加元素也被称为 "PUSH"。由于堆栈只基于一个指针工作,所以只能进行2个操作。要把一个值推入一个Stack ,我们利用push(value) 方法。

例子。

stack.push(10); // Push value 10 into Stack
stack.push(11); // Push value 11 into Stack
// OUTPUT: stack = [10, 11]

移除元素

类似地,要从Stack ,我们将使用pop() 方法来删除一个元素。在这里,我们不需要指定索引,因为在默认情况下,根据原则,它将删除最后添加的元素。

例子。

stack.pop(); // Removes 11 from Stack
// OUTPUT: stack = [10]
stack.pop() // Remove 10 from Stack
// OUTPUT: EmptyStackException

如果你的Stack 是空的,即(stack.size() == 0) ,那么弹出的元素是不可能的。如果你仍然继续使用pop() 方法,那么它将引发一个名为EmptyStackException 的异常。

队列

另外,Queue 是一个线性数据结构,根据先进先出(FIFO)原则工作。首先被添加到队列中的元素,应该首先从队列中删除。

创建Queue 数据结构的语法。

import java.util.Queue; // Import Queue package

Queue<Integer> queue = new Queue<Integer>(); // Create new object

添加元素

向队列中添加元素可以通过使用add(value) 方法来完成。

例子。

queue.add(1); // 1 added to queue
queue.add(2); // 2 added to queue
// OUTPUT: queue = [1, 2]

删除元素

Queue ,移除元素被称为 "轮询"。轮询可以在队列的一端进行,称为 "后 "端。类似地,添加可以在队列的另一端进行,称为 "前 "端。

例子。

queue.poll(); // Removes 1 from the queue
// OUTPUT: queue = [2]

结论

最后,我们已经了解了Java中的各种内置数据结构。我们还学习了如何使用它们。

总结一下。

  • 我们了解了各种内置数据结构。

  • 我们将它们与用户定义的数据结构进行了比较。

  • 我们学会了如何使用每个内置数据结构。