【数据结构】双向链表 - 指南

📅 2026-07-06 04:12:49 ✍️ admin 👁️ 6367 ❤️ 421
【数据结构】双向链表 - 指南

文章目录什么是LinkedListLinkedList的使用LinkedList的构造LinkedList的其他常用方法LinkedList的遍历ArrayList和LinkedList的区别

小贴士:建议学习这章之前先看一下上一章的单向链表哦

什么是LinkedListLinkedList的底层是双向链表结构(链表后面介绍),由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。

在集合框架中,LinkedList也实现了List接口,具体如下:【说明】

LinkedList实现了List接口LinkedList的底层使用了双向链表LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)LinkedList比较适合任意位置插入的场景LinkedList的使用LinkedList的构造 我们在顺序表那一章节中(详见顺序表)详细的探讨过构造函数的问题,当时我们知道构造函数时可以传递一个ArrayList类型的表的参数。不过由于只要是Collection的子类都可以传参,所以传递的参数不仅可以是ArrayList,还可以是任意的其他的类型。比如下面这个案例:

public static void main(String[] args) {

// 构造一个空的LinkedList

List<

Integer> list1 = new LinkedList<

>();

List<

String> list2 = new java.util.ArrayList<

>();

list2.add("JavaSE");

list2.add("JavaWeb");

list2.add("JavaEE");

// 使用ArrayList构造LinkedList

List<

String> list3 = new LinkedList<

>(list2);

}

LinkedList的其他常用方法 这些常用的方法我们很容易就可以模拟实现,并且这些方法在ArrayList那一章中我们就模拟实现过了,所以我们实现一些特殊的方法,具体如下: 还是先建立一个MyList接口,然后再用链表类实现它:

package demo;

public interface MyList {

//头插法

public void addFirst(int data);

//尾插法

public void addLast(int data);

//任意位置插入,第一个数据节点为0号下标

public void addIndex(int index,int data);

//查找是否包含关键字key是否在单链表当中

public boolean contains(int key);

//删除第一次出现关键字为key的节点

public void remove(int key);

//删除所有值为key的节点

public void removeAllKey(int key);

//得到单链表的长度

public int size();

public void clear() ;

public void display() ;

}

双向链表类:

package demo;

// 2、无头双向链表实现

public class MyLinkedList

implements MyList{

static class ListNode

{

public ListNode next;

public ListNode prev;

int val;

public ListNode(int val) {

this.val = val;

}

}

ListNode head;

ListNode last;

//头插法

public void addFirst(int data){

ListNode node = new ListNode(data);

if(head == null){

head = last = node;

return;

}

head.prev = node;

node.next = head;

head = node;

}

//尾插法

public void addLast(int data){

ListNode node = new ListNode(data);

if(last == null){

last = head = node;

return;

}

node.prev = last;

last.next = node;

last = node;

}

//任意位置插入,第一个数据节点为0号下标

public void addIndex(int index,int data){

ListNode cur = head;

ListNode node = new ListNode(data);

if(index == 0){

node.next = head;

head.prev = node;

head = node;

return;

}

if(index == size()){

node.prev = last;

last.next = node;

last = node;

return;

}

while(index != 0){

cur = cur.next;

index--;

}

node.next = cur;

node.prev = cur.prev;

cur.prev.next = node;

cur.prev = node;

}

//查找是否包含关键字key是否在单链表当中

public boolean contains(int key){

ListNode cur = head;

while(cur != null){

if(cur.val == key){

return true;

}

cur = cur.next;

}

return false;

}

//删除第一次出现关键字为key的节点

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;

}

}

//删除所有值为key的节点

public void removeAllKey(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;

}

}

}

cur = cur.next;

}

}

//得到单链表的长度

public int size(){

ListNode cur = head;

int count = 0;

while(cur != null){

count++;

cur = cur.next;

}

return count;

}

public void display(){

ListNode cur = head;

while(cur != null){

System.out.print(cur.val + " ");

cur = cur.next;

}

System.out.println();

}

public void clear(){

last = null;

head = null;

}

}

还是建议大家可以跟着自己尝试模拟实现一下

LinkedList的遍历

public static void main(String[] args) {

LinkedList<

Integer> list = new LinkedList<

>();

list.addLast(1);

list.addLast(1);

list.addLast(1);

list.addLast(2);

list.add(2,3);

list.add(0,9);

list.addLast(6);

System.out.println("====for循环====");

for (int i = 0; i < list.size(); i++) {

System.out.print(list.get(i) + " ");

}

System.out.println();

System.out.println("====for each循环====");

for(Integer x : list){

System.out.print(x + " ");

}

System.out.println();

System.out.println("====iterator====");

Iterator<

Integer> it = list.iterator();

while(it.hasNext()){

System.out.print(it.next() + " ");

}

System.out.println();

System.out.println("====listIterator反向输出====");

ListIterator<

Integer> it2 = list.listIterator(list.size());

while(it2.hasPrevious()){

System.out.print(it2.previous() + " ");

}

System.out.println();

}

遍历这一部分跟顺序表大差不差,其中迭代器输出的方法还是着重理解一下。

ArrayList和LinkedList的区别