链表
Java数据结构链表是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址。链表可分为单向链表和双向链表。单向链表的每个节点包含两个值:当前节点的值和一个指向下一个节点的链接。双向链表的每个节点有三个值:数值、向后的节点链接、向前的节点链接。
单链表
Java中单链表是一种基础的数据结构,它由一系列的节点组成,每个节点包含一个数据域和一个指向下一个节点的指针域。单链表的第一个节点称为头节点,最后一个节点的指针域为null。
常见操作
- 头插法:在链表的头部插入一个新的节点,让新节点的指针域指向原来的头节点,然后更新头节点为新节点。
- 尾插法:在链表的尾部插入一个新的节点,需要先找到链表的最后一个节点,然后让最后一个节点的指针域指向新节点,新节点的指针域为null。
- 任意位置插入:在链表的指定位置插入一个新的节点,需要先找到该位置的前一个节点,然后让前一个节点的指针域指向新节点,新节点的指针域指向原来的后一个节点。
- 查找是否包含关键字:遍历链表,比较每个节点的数据域和关键字是否相等,如果找到相等的返回true,否则返回false。
- 得到单链表的长度:遍历链表,用一个计数器记录遍历过的节点个数,最后返回计数器的值。
- 打印单链表:遍历链表,输出每个节点的数据域。
- 删除第一次出现关键字为key的节点:遍历链表,找到第一个数据域为key的节点和它的前一个节点,然后让前一个节点的指针域指向后一个节点,释放当前节点。
- 删除所有值为key的节点:遍历链表,找到所有数据域为key的节点和它们的前一个节点,然后让前一个节点的指针域指向后一个节点,释放当前节点。
优缺点
- 优点:
- 单链表是一种动态的数据结构,可以根据需要增加或减少节点,不需要预先分配固定的空间,节省了内存。
- 单链表的插入和删除操作比较简单,只需要修改指针域即可,不需要移动其他元素,提高了效率。
- 单链表可以用来实现其他的数据结构,如栈、队列、多项式等。
- 缺点:
- 单链表的存储空间开销较大,每个节点除了数据域外还需要一个指针域,占用额外的空间。
- 单链表的访问效率较低,不能随机访问任意位置的元素,只能从头节点开始顺序遍历,时间复杂度为O(n)。
- 单链表的反向遍历比较困难,需要借助栈或递归等方式实现。
单链表的增删改查
// 定义一个节点类
class Node {
// 数据域
int data;
// 指针域
Node next;
// 构造方法
public Node(int data) {
this.data = data;
}
}
// 定义一个单链表类
class MyLinkedList {
// 头节点
Node head;
// 增加节点(尾插法)
public void add(int data) {
// 创建一个新节点
Node node = new Node(data);
// 如果链表为空,直接让头节点指向新节点
if (head == null) {
head = node;
} else {
// 否则,找到链表的最后一个节点,让它的指针域指向新节点,新节点的指针域为null
Node cur = head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
}
}
// 删除节点(根据数据域)
public void delete(int data) {
// 如果链表为空,直接返回
if (head == null) {
return;
}
// 如果头节点就是要删除的节点,直接让头节点指向下一个节点,并释放原来的头节点
if (head.data == data) {
head = head.next;
return;
}
// 否则,找到要删除的节点的前一个节点,让它的指针域指向后一个节点,并释放要删除的节点
Node prev = head;
Node cur = head.next;
while (cur != null) {
if (cur.data == data) {
prev.next = cur.next;
break;
}
prev = cur;
cur = cur.next;
}
}
// 修改节点(根据数据域)
public void update(int oldData, int newData) {
// 如果链表为空,直接返回
if (head == null) {
return;
}
// 遍历链表,找到要修改的节点,更新它的数据域
Node cur = head;
while (cur != null) {
if (cur.data == oldData) {
cur.data = newData;
break;
}
cur = cur.next;
}
}
// 查询节点(根据数据域)
public boolean search(int data) {
// 如果链表为空,直接返回false
if (head == null) {
return false;
}
// 遍历链表,比较每个节点的数据域和查询的数据是否相等,如果找到相等的返回true,否则返回false
Node cur = head;
while (cur != null) {
if (cur.data == data) {
return true;
}
cur = cur.next;
}
return false;
}
// 打印单链表
public void display() {
Node cur = head;
while (cur != null) {
System.out.print(cur.data + " ");
cur = cur.next;
}
System.out.println();
}
}