双向循环链表实现
Posted guardwhy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双向循环链表实现相关的知识,希望对你有一定的参考价值。
1.1 基本介绍
双向循环链表就是在双线链表的基础上首尾相连(第一个节点的prev指向最后一个节点,最后一个节点的next指向第一个节点)。
1.2 添加操作
1、思路分析
头部插入
当整个链表都为空时,添加操作。
头结点和尾节点都指向自己。
当链表不为空时,添加操作
先把当前头节点的上一跳地址给新元素的上一跳
然后让新节点的后驱指针指向head
结点,再让head
的前驱指针指向新元素。
更新head
结点,让head
结点指向新结点,更新tail
结点,让tail
的下一跳重新指向head
。
尾部插入
将当前tail
的下一跳给新节点的下一跳
让tail
的下一跳指向新结点,新结点的上一跳指向tail
。
tail
重新指向新结点。
直接让head
的上一跳重新指向tail
。
中间插入
1、离头部比较近
定义两个指针p
,q
,找到要插入节点前驱,让p
的上一跳指向新节点,让新节点的下一跳指向p
。
让q
的上一跳指向新节点,让新节点的下一跳指向q
。
2、离尾部比较近
让q
的下一跳指向新节点,让新节点的上一跳指向q
。
让p
的上一跳指向新节点,让新节点的下一跳指向p
。
2、代码示例
链表类: LinkedList
package cn.linkedlist.demo05;
import java.util.Iterator;
public class LinkedList<E> implements List<E>
// 创建Node节点
private class Node
// 数据域
E data;
// 指向直接前驱的指针
Node prev;
// 指向直接后继的指针
Node next;
// 构造函数
public Node()
this(null, null, null);
public Node(E data)
this(data, null, null);
public Node(E data, Node prev, Node next)
this.data = data;
this.prev = prev;
this.next = next;
@Override
public String toString()
StringBuilder sb = new StringBuilder();
if (prev != null)
sb.append(prev.data);
else
sb.append("null");
sb.append("->").append(data).append("->");
if (next != null)
sb.append(next.data);
else
sb.append("null");
return sb.toString();
// 链表元素的数量
private int size;
// 声明头结点
private Node head;
// 声明尾节点
private Node tail;
// 初始化头结点
public LinkedList()
head = null;
tail = null;
size = 0;
public LinkedList(E[] arr)
for (E e : arr)
add(e);
//默认向表尾添加元素
@Override
public void add(E element)
add(size, element);
//在链表当中指定索引index处添加一个元素
@Override
public void add(int index, E element)
if (index < 0|| index > size)
throw new ArrayIndexOutOfBoundsException("add index out of bounds");
// 创建新的结点对象
Node node = new Node(element);
// 链表为空
if(isEmpty())
head = node;
tail = node;
tail.next = head;
head.prev = tail;
else if(index == 0) // 在链表头部添加元素
// 头结点的上一跳指向新节点的上一跳
node.prev = head.prev;
node.next = head;
head.prev = node;
head = node;
tail.next = head;
else if(index == size) // 在链表尾部添加元素
node.next = tail.next;
tail.next = node;
node.prev = tail;
tail = node;
head.prev = tail;
else
// 在链表中添加元素
Node p,q; // 定义两个指针变量
if(index <= size / 2)
p = head;
for(int i =0; i < index -1 ; i++)
p = p.next;
q = p.next;
p.next = node;
node.prev = p;
q.prev = node;
node.next = q;
else
p = tail;
for(int i=size -1; i > index; i--)
p = p.prev;
q = p.prev;
q.next = node;
node.prev = q;
p.prev = node;
node.next = p;
size++;
@Override
public int size()
return size;
//查找元素在链表中第一次出现的索引
@Override
public int indexOf(E element)
if(isEmpty())
return -1;
Node p = head;
int index = 0;
while (!p.data.equals(element))
p = p.next;
index++;
if(p == head)
return -1;
return index;
//在链表中判断是否包含元素element
@Override
public boolean contains(E element)
return indexOf(element) != -1;
@Override
public boolean isEmpty()
return size== 0 && head == null && tail == null;
@Override
public void clear()
head = null;
tail = null;
size = 0;
@Override
public String toString()
StringBuilder res = new StringBuilder();
res.append("size=").append(size).append(", [");
Node node = head;
for (int i = 0; i < size; i++)
if (i != 0)
res.append(", ");
res.append(node);
node = node.next;
res.append("]");
return res.toString();
@Override
public Iterator<E> iterator()
return new DoubleCircleLinkedListIterator();
class DoubleCircleLinkedListIterator implements Iterator<E>
private Node cur = head;
private boolean flag = true;
@Override
public boolean hasNext()
if(isEmpty())
return false;
return flag;
@Override
public E next()
E ret = cur.data;
cur = cur.next;
if(cur == head)
flag = false;
return ret;
测试类:LinkedListDemo
package cn.linkedlist.demo05;
public class LinkedListDemo
public static void main(String[] args)
LinkedList<Integer> list = new LinkedList<>();
System.out.println("===链表头部插入===");
// System.out.println(list);
list.add(0, 1);
list.add(0, 2);
list.add(0, 3);
System.out.println(list);
System.out.println("===链表尾部插入===");
list.add(list.size(), 4);
list.add(list.size(), 5);
list.add(list.size(), 6);
System.out.println(list);
3、执行结果
1.3 删除操作
1、思路分析
删除头结点
node
节点为head.next
,最终node
是新的头结点。
head
的下一跳置空。
head
的上一跳,给node
的上一跳。
head
的上一跳置空!!head
重新指向node
。
最后让尾指针下一跳重新指向head
即可。
删除尾节点
node
为tail.pre
前驱,最终node
是新的尾结点。
让tail
的上一跳置空。
tail
的下一跳给node
的下一跳,tail
的下一跳置空。
tail
重新指向node
。
head
的上一跳重新指向tail
。
删除中间节点
1、离头部比较近
定义三个指针,p
是要删除节点的前驱,q
是要删除节点,r
是要删除节点的后继,p指针移动到要删除节点的前驱。
让p
的下一跳直接指向r
,让r
的上一跳重新指向p
。
让q
的上一跳和q
的下一跳直接置空。
删除成功。
2、离尾部比较近
定义三个节点指针,p
是要删除节点的前驱,q
是要删除节点,R
是要删除节点的后继。
让R
的上一跳指向p
,让p
的下一跳指向R
,让q
的两边同时置空!!!
最后删除成功!!!
2、代码示例
链表类: LinkedList
//删除链表中指定的元素element
@Override
public void remove(E element)
int index = index0f(element);
if(index != -1)
remove(index);
//删除链表中指定角标处index的元素
@Override
public E remove(int index)
if (index < 0|| index > size)
throw new ArrayIndexOutOfBoundsException("remove index out of bounds");
// 定义ret变量
E ret = null;
Node node;
// 当链表只剩一个元素
if(size ==1)
ret = head.data;
head = null;
tail = null;
// 删除表头
else if(index == 0)
ret = head.data;
node = head.next;
head.next = null;
node.prev = head.prev;
head.prev = null;
head = node;
tail.next = head;
// 删除表尾
else if(index == size -1)
ret = tail.data;
node = tail.prev;
tail.prev = null;
node.next = tail.next;
tail.next = null;
tail = node;
head.prev = tail;
else
// 删除链表中间的某一个元素
Node p, q, r;
if(index <= size / 2)
p = head;
for(int i=0; i < index-1; i++)
p = p.next;
q = p.next;
ret = q.data;
r = q.next;
p.next = r;
r.prev = p;
q.next = null;
q.prev = null;
else
p = tail;
for(int i = size -1; i > index + 1; i--)
p = p.prev;
q = p.prev;
ret = q.data;
r = q.prev;
r.next = p;
p.prev = r;
q.next = null;
q.prev = null;
size --;
return ret;
测试类:LinkedListDemo
package cn.linkedlist.demo05;
public class LinkedListDemo
public static void main(String[] args)
LinkedList<Integer> list = new LinkedList<>();
System.out.println("===链表头部插入===");
//System.out.println(list);
list.add(0, 1);
list.add(0, 2);
list.add(0, 3);
System.out.println(list);
System.out.println("===链表尾部插入===");
list.add(list.size(), 4);
list.add(list.size(), 5);
list.add(list.size(), 6);
System.out.println(list);
System.out.println("==删除元素==");
System.out.println(list.remove(3));
System.out.println(list);
3、执行结果
1.4 修改和获取操作
1、代码示例
链表类: LinkedList
//获取链表中指定索引处的元素
@Override
public E get(int index)
if (index < 0|| index > size)
throw new ArrayIndexOutOfBoundsException(双向循环链表