阅读 88

小码哥数据结构与算法(四): 循环链表

本篇是恋上数据结构与算法(第一季)的学习笔记, 使用JAVA语言

一、单向循环链表

  • 单向循环量链表, 就是尾节点的next, 指向头节点

1、插入方法

  • 单向循环链表插入数据时, 有一点与单项链表不同, 那就是需要取出最后一个节点的next指向头结点

public void add(int index, E element) {
    rangeCheckForAdd(index);
    if (index == 0) {
    	// 创建新节点, 并指向原链表的first节点
    	Node<E> node = new Node<>(element, first);
    	// 取出最后一个节点
    	Node<E> last = size == 0 ? first : node(size - 1);
    	// 最后一个节点的next指向新节点
    	last.next = node;
    	// first指针指向新节点
    	first = node;
    }else {
    	Node<E> prev = node(index - 1);
    	prev.next = new Node<>(element, prev.next);
    }
    size++;
}
复制代码

2、删除节点

  • 删除节点, 要保证尾节点指向头节点, 当只有一个节点时, first指向null
public E remove(int index) {
    Node<E> node = first;
    if (index == 0) {
    	if (size == 1) {
            first = null;
    	}else {
            Node<E> last = node(size - 1);
            first = first.next;
            last.next = first;
    	}
	}else {
        Node<E> prev = node(index - 1);
        node = prev.next;
        prev.next = node.next;
    }
    size--;
    return node.element;
}
复制代码

二、双向循环链表

  • 双向循环链表, 首节点的prev指向尾节点, 尾节点的next指向首节点

1、插入节点

  • 插入节点后, 需要保证首节点的prev指向尾节点, 尾节点的next指向首节点

public void add(int index, E element) {
    rangeCheckForAdd(index);
    // 如果 index == size, 说明添加的索引是最后位置
    if (index == size) {
    	// 创建新节点, prev指向原链表的尾节点, next指向首节点
    	Node<E> node = new Node<>(last, element, first);
    	// 当原链表没有任何节点
    	if (size == 0) {
            first = node;
            last = node;
            node.prev = node;
            node.next = node;
        }else {
            // 原链表尾节点next指向node
            last.next = node;
            // 原链表头结点prev指向node
            first.prev = node;
            // last指向新的尾节点
            last = node;
        }
    }else {
        // 添加新节点后的下一个节点
        Node<E> next = node(index);
        // 添加新节点后的上一个节点
        Node<E> prev = next.prev;
        // 创建新节点, 新节点的上一个节点时prev, 新节点的下一个节点是next
        Node<E> node = new Node<>(prev, element, next);
        // next的上一个节点是新节点
        next.prev = node;
        // prev的下一个节点是新节点
        prev.next = node;
        // 当next == first时, 说明新添加节点的索引是0
        if (next == first) { 
        	first = node;
        }
    }
    size++;
}
复制代码

2、删除节点

  • 删除节点, 就是在环上去掉某一个节点, 然后根据删除的节点是首节点或者尾节点来处理firstlast
public E remove(int index) {
    // 需要删除的节点
    Node<E> node = node(index);	
    if (size == 1) {
        first = null;
        last = null;
    }else {
        // 删除节点的前一个节点
        Node<E> prev = node.prev;
        // 删除节点的后一个节点
        Node<E> next = node.next;
        next.prev = prev;
        prev.next = next;
        // 如果node == first, 说明删除的是第一个节点
        if (node == first) {
            first = next;
        }
        // 如果next == last, 说明删除的是最后一个节点
        if (next == last) {
            last = prev;
        }	
    }
    size--;
    return node.element;
}
复制代码