链表的基本概念
链表是一种线性数据结构,由一系列节点组成,每个节点包含数据域和指针域。数据域存储数据,指针域存储下一个节点的地址。链表可以动态分配内存,不需要预先知道数据量的大小。
链表的类型
- 单链表:每个节点只有一个指针域,指向下一个节点。
- 双链表:每个节点有两个指针域,分别指向前一个节点和后一个节点。
- 循环链表:尾节点的指针域指向头节点,形成一个环。
链表的操作
插入节点
在链表中插入节点需要调整指针的指向。例如,在单链表中插入一个新节点:
- 新节点的指针指向原位置的下一个节点。
- 原位置的指针指向新节点。
删除节点
删除节点时,需要将前一个节点的指针指向被删除节点的下一个节点。例如,在单链表中删除一个节点:
- 找到待删除节点的前驱节点。
- 将前驱节点的指针指向待删除节点的后继节点。
遍历链表
从头节点开始,依次访问每个节点,直到指针域为 null
。
链表的优缺点
优点
- 动态内存分配,不需要预先知道数据量。
- 插入和删除操作高效,时间复杂度为 O(1)(已知位置时)。
缺点
- 访问元素需要从头遍历,时间复杂度为 O(n)。
- 需要额外的空间存储指针。
链表的代码实现(JAVA)
java
/**
* Created with IntelliJ IDEA.
* Description:
* User: zhany
* Date: 2025-10-13
* Time: 11:55
*/
public class MyLink implements IList{
static class ListNode {
int val;
ListNode prev;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
public ListNode head;
public ListNode last;
@Override
public void addFirst(int data) {
ListNode node = new ListNode(data);
if (head == null) {
head = last = node;
} else {
node.next = head;
head.prev = node;
head = node;
}
}
@Override
public void addLast(int data) {
ListNode node = new ListNode(data);
if (last == null) {
head = last = node;
} else {
last.next = node;
node.prev = last;
last = node;
}
}
@Override
public boolean addIndex(int index, int data) {
int len = size();
if(len < 0 || len > size()){
return false;
}
if (len == 0) {
addFirst(data);
}
if (len == size()){
addLast(data);
}
ListNode cur = findindex(index);
ListNode node =new ListNode(data);
node.next = cur;
cur.prev.next = node;
node.prev = cur.prev;
cur.prev = node;
return true;
}
private ListNode findindex(int index) {
ListNode cur = head;
while(index == 0){
cur =cur.next;
index--;
}
return cur;
}
@Override
public boolean contains(int key) {
ListNode cur = head;
while(cur != null && cur.next !=null){
if(cur.val == key){
return true;
}
cur = cur.next;
}
return false;
}
@Override
public void remove(int key) {
ListNode cur = head;
while(cur != null){
if (cur.val == key){
if (cur == head) {
head = head.next;
if (head != null) {
head.prev = null;
}
} else {
cur.prev.next = cur.next;
if (cur.next == null) {
last = last.prev;
} else {
cur.next.prev = cur.prev;
}
}
return;
}
cur = cur.next;
}
}
@Override
public void removeAllKey(int key) {
ListNode cur = head;
while(cur != null){
if (cur == head) {
head = head.next;
if (head.prev != null) {
head.prev = null;
}
} else{
cur.prev.next = cur.next;
if (cur.next == null) {
last = last.prev;
} else {
cur.next.prev = cur.prev;
}
}
cur =cur.next;
}
}
@Override
public int size() {
ListNode cur = head;
int len = 0;
while (cur != null && cur.next !=null){
cur = cur.next;
len++;
}
return len;
}
@Override
public void display() {
ListNode cur = head;
while(cur != null && cur.next != null){
System.out.println(cur.val+" ");
cur =cur.next;
}
System.out.println();
}
@Override
public void clear() {
ListNode cur = head;
while(cur != null){
ListNode curN =cur.next;
cur.prev =null;
cur.next = null;
cur = curN;
}
last = head = null;
}
}
链表的应用场景
- 动态内存管理:适用于需要频繁插入和删除的场景。
- 实现其他数据结构:如栈、队列、哈希表等。
- 文件系统:文件目录结构可以用链表表示。
链表是一种基础但强大的数据结构,理解其原理和实现方式对编程和算法学习至关重要。