循环链表(单链表)

2022/4/22 23:15:47

本文主要是介绍循环链表(单链表),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

  在单链表中,尾节点的next指向null,如果尾节点的next指向头节点,链表不就循环起来了?在循环链表中,没有一个节点的next指向null。尽管每一个节点都指向下一个节点,但循环链表还是有头部和尾部之分。外部怎么访问循环链表?需要一个外部的引用指向链表,那指向链表的头节点还是尾节点?指向链表的尾节点。因为如果指向头节点的话,链表尾部的插入需要遍历整个链表,指向尾节点不存在这个问题。如果在头部插入,循环列表尾节点的next就是头节点,也没有问题,循环列表有如下几种情况

  当循环链表中只有一个节点时,节点自己指向自己。实现循环链表,需要一个外部变量指向链表的尾节点。

class CircleLinkedList<T> {
    private class Node {
        T data;
        Node next;

        Node(T data) {
            this.data = data;
        }
    }

    private Node last;
}

  向链表中插入元素有三种情况,插入到链表的头部,插入到链表的尾部,插入到链表两个节点之间。当然,无论是哪种情况,都要检查链表是否为空。如果链表为空,让last指向新创建的节点,并自己指向自己。

private void addToEmpty(T data) {
    var newNode = new Node(data);
    last = newNode;
    newNode.next =last; // 链表自己指向自己
}

  如果链表不为空,比如有如下链表

   1,向链表头部插入元素,比如向链表的头部插入6,那就先创建一个新节点newNode, 然后让newNode.next 指向last.next,因为last.next就是头节点,最后让last.next指向最新的头节点newNode.

public void addFront(T data) {
    if (last == null) {
        addToEmpty(data);
    } else {
        var newNode = new Node(data);
        newNode.next = last.next;
        last.next = newNode;
    }
}

  2,向链表尾部插入节点,让last的next指向新的节点,last再指向新节点,当然,不要忘记它是循环链表,新节点的next还要指向头节点

public void addLast(T data) {
    if (last == null) {
        addToEmpty(data);
    } else {
        var newNode = new Node(data);
        newEntry.next = last.next; // 新节点的next指向头节点
        last.next = newEntry;
        last = newEntry;
    }
}

   3,向两个节点之间添加元素,就是向某一个元素后面添加元素,首先遍历链表,找到这个元素。如果这个元素正好是尾节点,那么还要移动last的位置

// 向某个item后面 添加值,
public void addAfter(T item, T data) {
    if(last == null) {
        throw new RuntimeException("链表为空");
    } else {
        var found = false;
        var temp = last.next; // 头节点

        do {
            if(temp.data.equals(item)){
                found = true;
            } else {
                temp = temp.next;
            }
        } while(temp != last.next && !found);

        if(found) {
            // temp就是将要向它向面添加元素的节点
            var newNode = new Node(data);
            // 先获取到旧的temp.next
            var oldNext = temp.next;
            temp.next = newNode;
            newNode.next = oldNext;

            //如果正好添加尾节点后面,还要移动last的指向
            if (temp == last) {
                last = newNode;
            }
        } else {
            throw new RuntimeException("没有找到元素");
        }
    }
}

  删除节点:如果链表为空,肯定是要报错的。如果链表中只有一个节点,那么如果删除的节点正好是这个节点,那么就删除,last=null,如果不是,那也只能报错了。如果有多个节点,但正好删除的是最后一个节点,那就要循环链表,找到最后一个节点的前一个节点,然后修改last指向,

   如果是删除中间一个元素,遍历找到前一个节点,

 

public void deleteNode(T item) {
    // 链表为空,肯定不能删除
    if(last == null) {
        throw new RuntimeException("链表为空");
    } else if(last.next == last) { // 链表只有一个节点
        if (last.data.equals(item)){
            last = null;
        } else {
            throw new RuntimeException("没有找到元素");
        }
        // 链表有多个节点
    } else if (last.data.equals(item)) { // 删除的节点,正好是最后一个节点
        // 找到最后一个节点的前一个节点
        var temp = last;
        while(temp.next != last) {
            temp = temp.next;
        }

        temp.next = last.next;
        last = temp;
    } else {
        var temp = last;
        // 找到前面一个节点
        while(!temp.next.data.equals(item) && temp.next != last) {
            temp = temp.next;
        }

        if(temp.next.data.equals(item)) {
            temp.next= temp.next.next;
        } else {
            throw new RuntimeException("没有找到元素");
        }
    }
}

  遍历

public void traverse() {
    if (last == null) {
        throw new RuntimeExceiption('空链表');
    }

    var p = last.next;

    do {
        System.out.print(p.data + " ");
        p = p.next;
    }
    while (p != last.next);
}

  测试

public static void main(String[] args) {
    var circleList = new CircleSingleLinkedList<Integer>();

    circleList.addFront(6);
    circleList.addEnd(8);
    circleList.addFront(2);

    circleList.addAfter(2, 10);

    circleList.traverse();

    System.out.println();

    circleList.deleteNode(8);
    circleList.traverse();
}

   

 



这篇关于循环链表(单链表)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程