链表结构的概念
链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
链表结构的特点
- 插入删除效率高:链表在任意位置插入元素和删除元素效率较高,时间复杂度接近O(1)。这是因为链表不需要移动其他元素,只需要修改指针的指向即可。
- 灵活度高:链表不需要预先分配固定大小的空间,可以随着元素的增加自动扩容,因此不会出现内存不足的情况。这种动态分配内存的方式使得链表具有很高的灵活性。
- 空间分散:在内存中,链表元素的空间可以在任意地方,空间是分散的,不需要连续。这种分散存储的方式使得链表可以充分利用内存碎片,提高内存的利用率。
- 查找效率低:查找数据时效率低,时间复杂度为O(N)。因为链表的空间是分散的,所以不具有随机访问性,如要需要访问某个位置的数据,需要从第一个数据开始找起,依次往后遍历,直到找到待查询的位置。
- 空间利用率高:链表的空间不需要提前指定大小,是动态申请的,根据需求动态的申请和删除内存空间,因此空间的利用率较高。但是链表需要额外的指针来存储节点之间的连接关系,这会占用更多的存储空间。
链表的分类
链表有多种类型,包括单向链表、双向链表、循环链表等。单向链表中的每个节点只包含一个指向下一个节点的指针;双向链表中的每个节点包含两个指针,一个指向前一个节点,一个指向下一个节点;循环链表中的最后一个节点指向第一个节点,形成一个闭环。
总的来说,链表是一种非常灵活的数据结构,适用于需要频繁进行插入和删除操作的应用场景。但是,由于链表的空间是分散的,不具有随机访问性,因此在查找数据时效率较低。
链表的操作
-
准备数据:
在使用链表之前,您需要准备要存储的数据。这些数据可以是任意类型,但通常需要满足链表中数据元素的类型。 -
初始化链表:
创建一个空的链表,并为其分配初始资源(如果有需要的话,例如头节点)。 -
获取链表长度:
遍历链表并计数节点数量,返回链表的长度。 -
插入节点:
在链表的指定位置插入一个新节点。如果位置超出链表范围,可能需要特殊处理(例如抛出异常或在链表末尾插入)。 -
追加节点:
在链表的末尾添加一个新节点。这通常是插入节点的特殊情况,位置为链表长度。 -
删除节点:
根据节点的值或位置删除链表中的一个节点。如果节点不存在,可能需要特殊处理。 -
查找节点:
根据节点的值或位置查找链表中的一个节点,并返回节点的位置或节点本身。 -
显示所有节点:
遍历链表并打印出所有节点的值。
下面是这些操作的Java代码实现:
public class ListNode<T> { | |
T value; | |
ListNode<T> next; | |
public ListNode(T value) { | |
this.value = value; | |
} | |
} | |
public class LinkedList<T> { | |
private ListNode<T> head; | |
private int size; | |
// 初始化链表 | |
public LinkedList() { | |
this.head = null; | |
this.size = 0; | |
} | |
// 获取链表长度 | |
public int length() { | |
return size; | |
} | |
// 插入节点 | |
public void insert(int index, T value) { | |
if (index < 0 || index > size) { | |
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); | |
} | |
ListNode<T> newNode = new ListNode<>(value); | |
if (index == 0) { | |
newNode.next = head; | |
head = newNode; | |
} else { | |
ListNode<T> current = head; | |
for (int i = 0; i < index - 1; i++) { | |
current = current.next; | |
} | |
newNode.next = current.next; | |
current.next = newNode; | |
} | |
size++; | |
} | |
// 追加节点 | |
public void append(T value) { | |
insert(size, value); | |
} | |
// 删除节点(按值删除) | |
public boolean delete(T value) { | |
if (head == null) { | |
return false; | |
} | |
if (head.value.equals(value)) { | |
head = head.next; | |
size--; | |
return true; | |
} | |
ListNode<T> current = head; | |
while (current.next != null && !current.next.value.equals(value)) { | |
current = current.next; | |
} | |
if (current.next != null) { | |
current.next = current.next.next; | |
size--; | |
return true; | |
} | |
return false; | |
} | |
// 查找节点(按值查找) | |
public ListNode<T> find(T value) { | |
ListNode<T> current = head; | |
while (current != null) { | |
if (current.value.equals(value)) { | |
return current; | |
} | |
current = current.next; | |
} | |
return null; | |
} | |
// 显示所有节点 | |
public void display() { | |
ListNode<T> current = head; | |
while (current != null) { | |
System.out.print(current.value + " "); | |
current = current.next; | |
} | |
System.out.println(); | |
} | |
// ... 其他可能的方法 | |
} |
注意:上面的代码示例中,链表节点的值是通过equals
方法进行比较的,所以链表中的元素类型T
需要正确实现