数据结构:双向链表(Java)

简介

双向链表(Double-Linked List)是一种重要的线性数据结构,它在单链表的基础上引入了“前驱指针”,使得每个节点不仅能指向其后续节点,还能回溯到其前一个节点。这一特性赋予了双向链表更灵活的遍历方式和更高效的插入、删除操作。

概念与结构

概念

双向链表,又称双链表,是一种链式存储的数据结构。它由一系列节点组成,每个节点包含两部分:数据域和指针域。数据域用于存储具体的数据元素,而指针域则分为两个,分别称为“后继指针”(next)和“前驱指针”(prev),分别指向当前节点的下一个节点和前一个节点。这种设计使得从双向链表中的任何一个节点出发,都能够方便地访问其前后相邻节点。

结构

在Java中,我们可以定义一个表示双向链表节点的类(如DoubleListNode或Node),其中包含数据成员和对应的指针:

class HerNode {
	public int date;
	public HeroNode next;// 指向下一个节点,默认为null
	public HeroNode pre;// 指向前一个节点,默认为null
}

双向链表的常见操作

class DoubleLinkedList {
    private HeroNode2 head = new HeroNode2(0, "", "");

    // 获取到第一个节点
    public HeroNode2 getHead() {
        return head;
    }
}

插入操作

双向链表支持在头部、尾部或指定位置插入新节点。以下是在头部插入节点的示例:

/**
按照date的大小进行排序
*/
public void add(HeroNode) {
	HeroNode temp =	head;
	boolean flag = false;
	while (temp.next != null) {
		if (temp.next.date > heroNode.date) {
				//先处理后面的指针
                heroNode.next = temp.next;
                temp.next.pre = heroNode;
		//特别注意:
        /*
        * 双向链表按循序添加的时候,要先处理新节点的后面的指针,再处理前面的指针
        * 原因:
        * 1.如果先把新节点和链前表半截连接起来,链表前半截指针指向后链表半截的指针就找不到了
        * 2.先把新节点和链表后半截连起来,这样由于新节点是可以直接找到的,
        *   所以这样可以将新节点和链表后半截连接起来
        * */
        		break;
        } else if(temp.next.date == heroNode.date) {
                flag = true;
                break;
        }
        temp = temp.next;
	}
	if (flag) {
            System.out.println("已存在,添加失败");
    } else {//再处理前面的指针或者添加到最后
            temp.next = heroNode;
            heroNode.pre = temp;
    }
}

删除操作

同样,双向链表支持删除头部、尾部或特定位置的节点。以下为删除头节点的示例:

public void del(int date) {
	if (head.next == null) {
        System.out.println("链表为空");
        return;
    }
    HeroNode2 temp = head.next;
    boolean flag = false;
   	while (temp != null) {
		if (temp.date == date) {
			flag = true;
			break;
		}
		temp = temp.next;
	}
	if (flag) {
            temp.date = date;
    } else {
            System.out.println("没找到" + update.date + "的节点,不能修改");
    }
}

查找操作

双向链表可以按值查找节点,但通常不如数组或哈希表高效。以下是一个简单的线性查找示例:

public HeroNode find(int target) {
    HeroNode current = head;
    while (current != null) {
        if (current.data == target) {
            return current;
        }
        current = current.next;
    }
    return null; // 如果未找到目标节点,返回null
}

遍历操作

双向链表可以正向、反向或双方向遍历。以下为正向遍历打印所有节点值的示例:

public void displayForward() {
    HeroNode current = head;
    while (current != null) {
        System.out.print(current.data + " ");
        current = current.next;
    }
    System.out.println();
}

特殊优势

高效插入与删除

由于双向链表节点具有前驱和后继指针,插入或删除节点时只需更改相邻节点的指针即可,无需像单链表那样可能需要遍历找到前一个节点。特别是在链表中间插入或删除时,双向链表的优势更为明显。

双向遍历

除了常规的从头至尾遍历,双向链表还支持从尾至头遍历,这对于某些应用场景(如LRU缓存淘汰策略、回溯搜索等)非常有用。例如,反向遍历代码如下:

public void displayBackward() {
    HeroNode current = tail;
    while (current != null) {
        System.out.print(current.data + " ");
        current = current.prev;
    }
    System.out.println();
}

总结

双向链表作为一种链式数据结构,结合了单链表的优点(动态分配内存、支持灵活插入删除)并克服了其在某些操作上的局限性(如逆序遍历困难)。通过在节点中增加前驱指针,双向链表实现了高效插入、删除和双向遍历功能。在Java中,通过定义节点类和封装类,并实现相应的增删查遍历方法,可以轻松构建和管理双向链表。尽管在空间复杂度上略高于单链表(每个节点多一个指针),但在需要频繁进行双向操作的场景下,双向链表往往能提供更好的性能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值