Java常用的数据类型
一、线性数据结构
1.栈
遵循“后进先出”(LIFO, Last In First Out)的原则
java.util.Stack 是 Java 标准库提供的一个类,它继承自 Vector 类,并提供了栈的基本操作,如 push, pop, peek 等。
import java.util.Stack;
public class StackExample {
public static void main(String[] args) {
// 创建一个 Stack 对象
Stack<String> stack = new Stack<>();
// 入栈操作
stack.push("one");
stack.push("two");
stack.push("three");
// 查看栈顶元素
System.out.println("Top element: " + stack.peek());
// 出栈操作
String topElement = stack.pop();
System.out.println("Popped element: " + topElement);
// 输出栈的内容
System.out.println("Stack contents: " + stack);
}
}
2.队列
Queue 是 Java 集合框架中的一个接口,它继承自 Collection 接口,因此实现了 Queue 的类可以使用所有 Collection 接口的方法。Queue 接口中定义了一些特定于队列的操作方法,比如 add, offer, remove, poll, element 和 peek 等。
add(e): 添加元素到队列尾部,如果队列已满,则抛出 IllegalStateException。
offer(e): 添加元素到队列尾部,如果队列已满则返回 false。
remove(): 移除并返回队列头部的元素,如果队列为空则抛出 NoSuchElementException。
poll(): 移除并返回队列头部的元素,如果队列为空则返回 null。
element(): 返回队列头部的元素,如果队列为空则抛出 NoSuchElementException。
peek(): 返回队列头部的元素,如果队列为空则返回 null。
Java 队列实现:
在Java中,队列(Queue)是一种先进先出(FIFO, First-In-First-Out)的数据结构。Java的java.util
包提供了多种队列的实现类,这些类根据它们的特性(如线程安全性、是否允许null元素、性能特性等)而有所不同。以下是一些常见的Queue实现类:
- LinkedList:
LinkedList
类实现了List
和Deque
接口,因此它也可以用作队列。由于其基于链表的结构,它在添加和删除元素时表现出良好的性能(在链表的两端)。- 使用
offer(E e)
添加元素到队列的末尾,poll()
移除并返回队列头部的元素,或者peek()
查看队列头部的元素但不移除它。
- PriorityQueue:
PriorityQueue
是一个基于优先级堆的无界优先级队列。元素根据其自然顺序进行排序,或者根据创建PriorityQueue时提供的Comparator
进行排序。- 注意,PriorityQueue不是严格意义上的FIFO队列,因为它基于元素的优先级进行排序。
- ArrayDeque:
ArrayDeque
是一个基于数组的双端队列,但它也可以高效地用作FIFO队列。- 相比
LinkedList
,ArrayDeque
在大多数实现中提供了更好的性能,尤其是在执行大量的插入和删除操作时。
- ConcurrentLinkedQueue:
ConcurrentLinkedQueue
是一个基于链接节点的无界线程安全队列。此队列按照FIFO(先进先出)排序元素。- 它适合在多线程环境中使用,因为它支持高并发级别的操作。
- LinkedBlockingQueue和ArrayBlockingQueue:
- 这两个类都是
BlockingQueue
接口的实现,它们支持两个附加操作:支持阻塞的插入和移除方法。 LinkedBlockingQueue
通常具有更高的吞吐量,但在大多数并发级别上,ArrayBlockingQueue
提供了更好的可预测性能。ArrayBlockingQueue
是一个由数组结构组成的有界阻塞队列。LinkedBlockingQueue
如果创建时没有指定容量,则默认为Integer.MAX_VALUE
。
- 这两个类都是
- SynchronousQueue:
SynchronousQueue
是一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,反之亦然。- 它对于传递性场景特别有用,其中一个线程需要将对象传递给另一个线程。
在选择队列实现时,您应该根据您的具体需求(如性能要求、是否需要线程安全、队列的大小是否有限制等)来决定使用哪个实现。
代码案例:
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
// 创建一个队列实例
Queue<String> queue = new LinkedList<>();
// 向队列中添加元素
queue.add("one");
queue.add("two");
queue.add("three");
// 输出队列头部的元素
System.out.println("Head of the queue: " + queue.element());
// 从队列中移除并输出头部的元素
String removedElement = queue.remove();
System.out.println("Removed element: " + removedElement);
// 输出队列的内容
System.out.println("Queue contents: " + queue);
}
}
3.数组(Array)
- 是一种线性表数据结构,它用一组连续的内存空间来存储一组具有相同类型的数据。
- 特点:内存地址连续,检索效率高(可以通过下标访问成员),但增删操作效率低(需要移动数据)
int[] arr =new int[]
4.链表(Linked List)
- 由一系列节点组成,每个节点包含数据和指向下一个节点的引用(在双向链表中还包含指向前一个节点的引用)。
- 分为单向链表、双向链表和循环链表等。
- 特点:内存地址不连续,插入和删除操作效率高,但随机访问效率低。
// 定义节点
class Node {
int data; // 节点存储的数据
Node next; // 指向下一个节点的指针
// 构造函数
public Node(int data) {
this.data = data;
this.next = null; // 新节点的下一个节点初始时为null
}
}
// 定义链表
class LinkedList {
Node head; // 链表的头节点
// 构造函数
public LinkedList() {
this.head = null; // 初始时链表为空
}
// 在链表末尾添加节点
public void add(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode; // 如果链表为空,则新节点即为头节点
} else {
Node current = head;
while (current.next != null) {
current = current.next; // 遍历到链表的最后一个节点
}
current.next = newNode; // 将新节点添加到链表末尾
}
}
// 打印链表
public void printList() {
Node current = head;
while (current != null) {
System.out.print(current.data + " -> ");
current = current.next;
}
System.out.println("null");
}
// 其他方法(如删除节点、查找节点等)可以根据需要添加
}
// 使用
public class Main {
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add(1);
list.add(2);
list.add(3);
list.printList(); // 输出: 1 -> 2 -> 3 -> null
}
}
二、非线性数据结构
数据元素之间存在一对多或多对多的关系,形成非线性结构。常见的非线性数据结构包括:
1.树(Tree)
- 由n(n≥0)个节点组成的具有层次关系的集合。
- 包括二叉树、完全二叉树、平衡二叉树(如AVL树)、B树、B+树等多种类型。
- 特点:具有层次结构,便于进行查找、插入和删除等操作。
// 二叉树的节点
class TreeNode {
int val; // 节点存储的数据
TreeNode left; // 左子节点
TreeNode right; // 右子节点
// 构造函数
public TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
// 二叉树的定义
class BinaryTree {
TreeNode root; // 二叉树的根节点
// 构造函数
public BinaryTree() {
this.root = null;
}
// 简化的插入方法(总是插入为左子节点,仅用于示例)
public void insert(int val) {
if (root == null) {
root = new TreeNode(val);
} else {
// 注意:这里只是简单地总是插入为根节点的左子节点,实际中可能需要根据情况决定插入位置
TreeNode current = root;
while (current.left != null) {
// 这里实际上没有处理右子树的情况,仅作为示例
current = current.left;
}
current.left = new TreeNode(val);
}
}
// 遍历方法(这里以中序遍历为例)
public void inorderTraversal(TreeNode node) {
if (node != null) {
inorderTraversal(node.left); // 遍历左子树
System.out.print(node.val + " "); // 访问节点
inorderTraversal(node.right); // 遍历右子树
}
}
// 提供一个公共的遍历入口
public void inorderTraversal() {
inorderTraversal(root);
}
// 其他方法(如前序遍历、后序遍历、搜索节点、删除节点等)可以根据需要添加
}
// 二叉树的使用
public class Main {
public static void main(String[] args) {
BinaryTree tree = new BinaryTree();
tree.insert(1);
tree.insert(2);
tree.insert(3);
// 注意:由于插入方法总是将新节点插入为左子节点,所以这里的树结构是倾斜的
tree.inorderTraversal(); // 输出将取决于树的结构,但在这个例子中,由于插入逻辑,输出可能不是直观的排序
// 假设树的结构是:
// 1
// /
// 2
// /
// 3
// 那么输出将是:3 2 1(因为我们是中序遍历,但树是倾斜的)
}
}
2.图(Graph)
- 由一系列顶点(Vertex)和边(Edge)组成的集合,用于描述对象之间的关系。
- 分为有向图和无向图两种。
- 特点:节点之间的关系是任意的,图中任意两个数据元素之间都有可能相关。
// 图的定义
public class GraphMatrix {
private int vertices; // 图的顶点数
private int[][] adjMatrix; // 邻接矩阵
// 构造函数
public GraphMatrix(int vertices) {
this.vertices = vertices;
adjMatrix = new int[vertices][vertices];
// 初始化邻接矩阵为0(表示无边)
for (int i = 0; i < vertices; i++) {
for (int j = 0; j < vertices; j++) {
adjMatrix[i][j] = 0;
}
}
}
// 添加边
public void addEdge(int v1, int v2, int weight) {
adjMatrix[v1][v2] = weight; // 无向图时,还需要设置adjMatrix[v2][v1] = weight
// 对于有向图,上面的代码就足够了
}
// 打印邻接矩阵
public void printGraph() {
for (int i = 0; i < vertices; i++) {
for (int j = 0; j < vertices; j++) {
System.out.print(adjMatrix[i][j] + " ");
}
System.out.println();
}
}
}
// 图的实现
import java.util.LinkedList;
import java.util.List;
public class GraphList {
private int vertices; // 图的顶点数
private List<List<Integer>> adjLists; // 邻接表
// 图的节点类,用于存储边(如果图是有权重的,则可以存储权重信息)
class AdjListNode {
int dest; // 相邻的顶点
// 如果需要,可以在这里添加权重等其他信息
AdjListNode next; // 指向下一个邻接节点的指针
// 构造函数
public AdjListNode(int dest) {
this.dest = dest;
this.next = null;
}
}
// 构造函数
public GraphList(int vertices) {
this.vertices = vertices;
adjLists = new LinkedList<>();
// 初始化邻接表
for (int i = 0; i < vertices; i++) {
adjLists.add(new LinkedList<>());
}
}
// 添加边
public void addEdge(int v1, int v2) {
// 注意:对于无向图,还需要调用addEdge(v2, v1)
adjLists.get(v1).add(new AdjListNode(v2));
}
// 打印邻接表(简化版,不打印权重)
public void printGraph() {
for (int i = 0; i < vertices; i++) {
System.out.print("顶点 " + i + " 的邻接表: ");
List<Integer> list = adjLists.get(i);
for (int node : list) {
System.out.print(node + " ");
}
System.out.println();
}
}
}
3.哈希表(Hash Table)
- 也叫散列表,是一种可以通过关键码值(Key-Value)直接访问的数据结构。
- 实现了快速查询、插入和删除操作。
- 在Java中,HashMap是哈希表的典型实现,它通过哈希函数将数据元素映射到数组的某个位置,并通过链表或红黑树解决哈希冲突问题。
Map map = new HashMap<Object,Object>();