8.双哨兵的双向链表(增加、删除、遍历)

图8-1 

双哨兵是定义两个哨兵,一个头和一个尾,双向链表是每个元素都有一个前仆节点和后继节点,如图8-1所示。

 图8-2

在首部插入元素一,让新节点前仆指向头节点,后继指向下一节点,头哨兵的后继指向新节点,后一节点的前仆指向新节点,如图8-2所示。

 图8-3

在尾部插入元素,需要找到尾哨兵指向的前一个节点,让新节点的前仆指向前一个节点,后继指向尾哨兵,上一个节点的后继指向新节点,尾哨兵的前仆指向新节点,如图8-3所示。

 图8-4

 根据索引插入,需要找到该索引的上一个节点后下一个节点,新节点的前仆指向上一个节点,后继指向下一个节点,上一个节点的后继指向新节点,下一个节点的前仆指向新节点,如图8-4所示。

 图8-5

删除头部元素,找到头哨兵,让头哨兵的后继指向待删除的下一个节点,下一个节点的前仆指向头哨兵,如图8-5所示。

  图8-6

删除尾部元素,通过尾哨兵找到待删除的节点,通过待删除的节点找到上一个节点,使上一个节点的后继指向尾哨兵,尾哨兵的前仆指向上一个节点,如图8-6所示。

   图8-7

根据索引删除,需要找到待删除的上一个节点和下一个节点,让上一个节点的后继指向下一个节点,下一个节点的前仆指向上一个节点,如图8-7所示。

代码实现如下:

//带哨兵的双向链表
public class DoubleLinkedListSentinel{

    //测试在最后插入
    @Test
    public void testLast(){
        addLast(1);
        addLast(2);
        addLast(3);
        addLast(4);
        loopLinked();                // 4 3 2 1
    }

    //测试在首部插入
    @Test
    public void testFirst(){
        addLast(1);
        addLast(2);
        addLast(3);
        addLast(4);
        loopLinked();            // 1 2 3 4
    }


    //测试根据索引插入
    @Test
    public void testInsert(){
        insert(0,0);
        addLast(1);
        insert(2,2);
        addLast(3);
        addLast(4);
        insert(5,5);
        loopLinked();     // 1 2 3 4
    }

    //测试删除
    @Test
    public void testRemoveFirst(){
        addLast(1);
        addLast(2);
        addLast(3);
        addLast(4);
        removeFirst();
        loopLinked();       //2 3 4
    }

    //测试删除
    @Test
    public void testRemoveLast(){
        addLast(1);
        addLast(2);
        addLast(3);
        addLast(4);
        removeLast();
        loopLinked();       //1 2 3
    }

    //测试根据索引删除
    @Test
    public void testRemove(){
        addLast(1);
        addLast(2);
        addLast(3);
        addLast(4);
        remove(3);
        loopLinked();
    }





    static class Node {
        Node prev;   //上一个指针
        int value;   //值
        Node next;   //下一个指针

        public Node(Node prev, int value, Node next) {
            this.prev = prev;
            this.value = value;
            this.next = next;
        }
    }

    private Node head;  //头哨兵
    private Node tail;  //尾哨兵

    //根据索引查找节点
    private Node findNode(int index){
        int i=-1;
        for (Node pointer=head;pointer!=tail;pointer=pointer.next,i++){
            if (i==index){
                return pointer;
            }
        }
        return null;
    }

    public DoubleLinkedListSentinel() {
        //初始化头尾哨兵
        head = new Node(null, 8848, null);
        tail = new Node(null, 8888, null);
        //初始头哨兵下一个指向尾哨兵
        head.next = tail;
        //初始尾哨兵上一个指向头哨兵
        tail.prev = head;
    }

    //头部插入
    public void addFirst(int value) {
        insert(0,value);
    }

    //头部删除
    public void removeFirst() {
        remove(0);
    }

    //尾部插入
    public void addLast(int value) {
        //找到尾节点的前仆
        Node last = tail.prev;
        //插入新节点
        Node add = new Node(last, value, tail);
        //新节点的前仆的后继指向新节点
        last.next=add;
        //尾节点的前仆指向新节点
        tail.prev=add;

    }

    //尾部删除
    public void removeLast() {
        //找到删除的节点
        Node remove = tail.prev;
        if (remove==head){
            throw new IllegalArgumentException("参数不合法:");
        }
        //找到删除的前一个节点
        Node prev = remove.prev;
        //待删除的前一个节点的后继指向尾指针
        prev.next=tail;
        //尾指针的前仆指向待删除的前一个节点
        tail.prev=prev;
    }

    //根据索引插入
    public void insert(int index,int value){
        //找到插入的上一个节点
        Node preNode = findNode(index - 1);
        if (preNode==null){
            throw new IllegalArgumentException("参数不合法:"+index);
        }
        //找到插入的下一个节点
        Node nextNode = preNode.next;
        //定义新节点
        Node newNode = new Node(preNode, value, nextNode);
        //上一个节点的下一个指向新节点
        preNode.next=newNode;
        //下一个节点的前一个指向新节点
        nextNode.prev=newNode;

    }

    //根据索引删除
    public void remove(int index){
        //找到待删除的少一个节点
        Node preNode = findNode(index - 1);
        if (preNode==null){
            throw new IllegalArgumentException("参数不合法:"+index);
        }
        //上一个节点的后继即是待删除元素
        Node remove = preNode.next;
        if (remove==tail){
            throw new IllegalArgumentException("参数不合法:"+index);

        }
        //找到待删除的下一个
        Node next = remove.next;
        //删除一个元素只需上一个后继指向待删除的下一个,待删除的后继的前仆指向待删除的前仆
        preNode.next=next;
        next.prev=preNode;

    }
    //遍历链表
    public void loopLinked(){
        Node pointer=head.next;
        while (pointer!=tail){
            System.out.println(pointer.value);
            pointer=pointer.next;
        }
    }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值