数据结构是计算机科学中用于组织和存储数据的方式,通常涉及在计算机上执行的各种操作。以下是一些常见的数据结构:
1.数组
由相同类型的元素组成的有序集合,通过索引访问
public class ArrayFeatures {
public static void main(String[] args) {
// 声明和初始化整数数组
int[] intArray = {1, 2, 3, 4, 5};
// 访问数组元素
int firstElement = intArray[0];
int lastElement = intArray[intArray.length - 1];
// 修改数组元素
intArray[2] = 30;
// 获取数组长度
int arrayLength = intArray.length;
// 遍历数组
System.out.println("Array elements:");
for (int num : intArray) {
System.out.println("Element: " + num);
}
// 声明和初始化二维数组
int[][] twoDArray = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
int element = twoDArray[1][2];
// 数组的拷贝
int[] copiedArray = Arrays.copyOf(intArray, intArray.length);
// 数组排序
Arrays.sort(intArray);
}
}
2.链表
链表(Linked List)是一种基本的数据结构,它由节点(Node)组成,每个节点包含数据和指向下一个节点的引用。Java中的链表可以通过LinkedList
类实现,以下是链表的一些主要特性:
-
动态大小: 链表的大小可以动态增长或缩小,不像数组在创建时需要指定大小。
-
节点结构: 每个节点包含数据和指向下一个节点的引用。
class Node {
int data;
Node next;
Node(int data) {
this.data = data;
this.next = null;
}
}
- 单链表和双链表: 单链表中每个节点只有一个指向下一个节点的引用,而双链表中每个节点有一个指向前一个节点和一个指向后一个节点的引用。
-
头结点: 链表的开头通常有一个特殊的节点称为头结点,它不包含实际的数据,仅用于标识链表的起始位置。
-
尾节点: 链表的末尾通常有一个特殊的节点称为尾节点,它的
next
指向null
,表示链表的结束。 -
插入和删除操作: 链表的插入和删除操作效率较高,只需调整节点的引用。
// 在链表末尾插入新节点
Node newNode = new Node(42);
lastNode.next = newNode;
// 删除指定节点
previousNode.next = currentNode.next;
-
遍历: 可以通过循环遍历整个链表,访问每个节点的数据。
Node current = head;
while (current != null) {
System.out.println(current.data);
current = current.next;
}
-
搜索: 可以按值或索引搜索链表中的节点。
// 搜索具有特定值的节点
Node current = head;
while (current != null) {
if (current.data == targetValue) {
// 找到了
break;
}
current = current.next;
}
-
反转: 可以反转整个链表,改变节点的引用方向。
Node prev = null;
Node current = head;
Node next = null;
while (current != null) {
next = current.next; // 保存下一个节点的引用
current.next = prev; // 反转当前节点的引用方向
prev = current; // 移动到下一个节点
current = next; // 移动到下一个节点
}
head = prev; // 新的头节点
-
循环检测: 可以检测链表中是否存在循环。
boolean hasCycle(Node head) {
Node slow = head;
Node fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true; // 链表中存在循环
}
}
return false; // 链表中不存在循环
}
3.栈
栈(Stack)是一种后进先出(Last In First Out,LIFO)的数据结构,它具有以下主要特性:
-
动态大小: 栈的大小可以动态增长或缩小。
-
基本操作: 栈支持两个基本操作:
push
(入栈)和pop
(出栈)。push(element)
: 将元素压入栈顶。pop()
: 弹出栈顶元素。
-
栈顶和栈底: 栈顶是最后压入栈的元素,栈底是最先压入栈的元素。
-
空栈: 栈可以为空,即不包含任何元素。
-
栈的实现: 可以使用数组或链表实现栈
--用数组实现:
public class Stack {
private int maxSize;
private int[] stackArray;
private int top;
public Stack(int size) {
maxSize = size;
stackArray = new int[maxSize];
top = -1;
}
public void push(int value) {
if (top < maxSize - 1) {
stackArray[++top] = value;
} else {
System.out.println("Stack overflow. Cannot push " + value);
}
}
public int pop() {
if (top >= 0) {
return stackArray[top--];
} else {
System.out.println("Stack underflow. Cannot pop.");
return -1; // Error code indicating underflow
}
}
public int peek() {
if (top >= 0) {
return stackArray[top];
} else {
System.out.println("Stack is empty. Cannot peek.");
return -1; // Error code indicating empty stack
}
}
public boolean isEmpty() {
return top == -1;
}
public boolean isFull() {
return top == maxSize - 1;
}
}
--链表实现
public class LinkedStack {
private Node top;
private class Node {
int data;
Node next;
Node(int data) {
this.data = data;
this.next = null;
}
}
public void push(int value) {
Node newNode = new Node(value);
newNode.next = top;
top = newNode;
}
public int pop() {
if (!isEmpty()) {
int value = top.data;
top = top.next;
return value;
} else {
System.out.println("Stack is empty. Cannot pop.");
return -1; // Error code indicating empty stack
}
}
public int peek() {
if (!isEmpty()) {
return top.data;
} else {
System.out.println("Stack is empty. Cannot peek.");
return -1; // Error code indicating empty stack
}
}
public boolean isEmpty() {
return top == null;
}
}
-
应用场景: 栈常用于需要后进先出操作的场景,如表达式求值、括号匹配、深度优先搜索(DFS)等。
-
调用栈: 在编程中,栈用于管理函数调用过程,保存函数的局部变量、返回地址等信息。
-
递归: 递归函数的调用过程也涉及栈的使用。
4.队列
队列(Queue)是一种先进先出(First In First Out,FIFO)的数据结构,具有以下主要特性:
-
动态大小: 队列的大小可以动态增长或缩小。
-
基本操作: 队列支持两个基本操作:
enqueue
(入队)和dequeue
(出队)。enqueue(element)
: 将元素加入队列尾部。dequeue()
: 从队列头部移除元素。
-
队头和队尾: 队头是最先进队的元素所在位置,队尾是最后进队的元素所在位置。
-
空队列: 队列可以为空,即不包含任何元素。
-
队列的实现: 可以使用数组或链表实现队列。
-
数组实现: 使用固定大小的数组,队列的大小有限。
-
public class Queue {
private int maxSize;
private int[] queueArray;
private int front;
private int rear;
public Queue(int size) {
maxSize = size + 1; // One extra space for the rear pointer to maintain the circular nature
queueArray = new int[maxSize];
front = 0;
rear = 0;
}
public void enqueue(int value) {
if (!isFull()) {
queueArray[rear] = value;
rear = (rear + 1) % maxSize;
} else {
System.out.println("Queue is full. Cannot enqueue " + value);
}
}
public int dequeue() {
if (!isEmpty()) {
int value = queueArray[front];
front = (front + 1) % maxSize;
return value;
} else {
System.out.println("Queue is empty. Cannot dequeue.");
return -1; // Error code indicating empty queue
}
}
public int peek() {
if (!isEmpty()) {
return queueArray[front];
} else {
System.out.println("Queue is empty. Cannot peek.");
return -1; // Error code indicating empty queue
}
}
public boolean isEmpty() {
return front == rear;
}
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
}
-
链表实现: 使用链表作为底层结构,队列的大小可以动态变化。
public class LinkedQueue {
private Node front;
private Node rear;
private class Node {
int data;
Node next;
Node(int data) {
this.data = data;
this.next = null;
}
}
public void enqueue(int value) {
Node newNode = new Node(value);
if (isEmpty()) {
front = newNode;
rear = newNode;
} else {
rear.next = newNode;
rear = newNode;
}
}
public int dequeue() {
if (!isEmpty()) {
int value = front.data;
front = front.next;
if (front == null) {
rear = null; // 队列为空,重置rear
}
return value;
} else {
System.out.println("Queue is empty. Cannot dequeue.");
return -1; // Error code indicating empty queue
}
}
public int peek() {
if (!isEmpty()) {
return front.data;
} else {
System.out.println("Queue is empty. Cannot peek.");
return -1; // Error code indicating empty queue
}
}
public boolean isEmpty() {
return front == null;
}
}
-
应用场景: 队列常用于需要先进先出操作的场景,如任务调度、广度优先搜索(BFS)等。
-
优先队列: 优先队列是一种特殊的队列,其中的元素按照优先级顺序出队。
-
循环队列: 队列可以采用循环方式实现,当队列满时,新元素可以放到队列头部,形成循环。
-
阻塞队列: 阻塞队列是在队列为空或满时会阻塞等待的队列,常用于多线程编程。
。。。。