详解双向循环链表的实现及概念
Posted 勇敢牛牛不怕困难@帅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解双向循环链表的实现及概念相关的知识,希望对你有一定的参考价值。
解剖双向循环链表!!!
双向循环链表概念
双向链表也叫双链表,是链表的一种,它的每个数据结点都有两个指针,分别指向后继和直接前区。所以,从双向链表中的任意一个结点开始,都可以很方便的访问到它的前驱结点和后继结点。如下图:
可以看出双向循环链表的继承体系,依然实现了List接口!
实现流程图
当此时只有一个结点元素
此时创建样式如下:
一.元素的添加,链表长度大于等于1时
1.在双向循环链表的表头添加元素
先断掉头结点的前继然后在指向新节点的前继
最后将head的前继指向新节点,新节点的后继指向head,再把head重新指向新节点,最后把tail结点的后继指向head结点
2.表尾添加一个新元素
表尾添加一个元素是先断掉表尾元素的后继重新指向新节点的后继
接着将tail的后继重新指向给新节点,新节点的前继指向tail结点,最后tail指向新节点,head的前继指向tail结点
3.中间添加元素
当前一个新节点,add添加到中间插入时
首先我们要找到当前插入结点位置的前一个结点,找到之后也就是图中的结点P,在找到后继结点q,此时把p的后继结点指向新节点,新节点的前继指向p,q的前继指向新节点,新节点的后继指向q。此时便,添加完成!
二.元素的删除
1.删除此时的头结点
删除头结点首先是将头结点的前继指向后一个node结点的前继续,此时将head的前继设为null,把头结点的后继置为null,再把head重新指向node结点,最后把尾节点的后继指向新head结点
最后删除头结点完成
2.删除尾节点
删除尾接点时,首先将尾节点的后继指向上一个结点的后继,并将尾结点的前继置为null,后继为null,最后把tail指向node结点,再把头结点的前继指向tail结点
3.删除中间元素
首先找到删除结点的前继和后继结点
将p的后继指向r结点,r的前继指向p结点
最后将q的前继和后继都置为null,中间删除元素便完成了!
实现代码
第一部分List接口
package com.my.接口;
import java.util.Comparator;
public interface
/*
* List是线性结构的接口
* 里面定义了该线性结构的一些通用操作 并支持泛型
* 继承自Iterable接口(可迭代接口) 主要用于遍历数据结构
* 其次还有让我们的类可以被foreach循环使用
* 不是所有的数据结构都可以像数组一样通过角标来访问元素
*/
List<E> extends Iterable<E> {
/**
* 在线性结构的末尾添加一个元素element
* */
public void add(E element);
/**
* 在线性结构指定角标index处添加一个元素element
* */
public void add(int index,E element);
/**
* 在线性结构中删除指定元素element
* */
public void remove(E element);
/**
* 在线性结构中删除指定角标index处的元素,并返回
* */
public E remove(int index);
/**
* 在线性结构中获取指定角标处index的元素
* */
public E get(int index);
/**
* 在线性结构中修改指定角标处index的元素为新元素element
* */
public E set(int index,E element);
/**
* 获取线性结构中有效元素的个数
* */
public int size();
/**
* 获取指定元素element在线性结构中的角标
* */
public int indexOf(E element);
/**
* 查看线性表中是否包含指定元素element
* */
public boolean contains(E element);
/**
* 查看线性结构是否为空
* */
public boolean isEmpty();
/**
* 清空线性结构
* */
public void clear();
/**
* 对线性结构按照比较器comparator的定义来进行排序
* */
public void sort(Comparator<E> comparator);
/**
* 获取线性结构中从指定fromIndex角标开始到toIndex角标结尾的所有元素
* (0 <= fromIndex < toIndex < size)
* [fromIndex,toIndex)
* */
public List<E> sublist(int fromIndex,int toIndex);
}
第二部分LinkedList双向循环链表
package com.my.线性结构;
import java.util.Comparator;
import java.util.Iterator;
import com.my.接口.List;
public class LinkedList<E> implements List<E> {
private class Node{
Node pre;
Node next;
E data;
public Node(E data) {
this.data =data;
next = null;
pre = null;
}
@Override
public String toString() {
// TODO 自动生成的方法存根
return data.toString();
}
}
private Node head;
private Node tail;
private int size;
public LinkedList() {
head =null;
tail = null;
size =0;
}
@Override
public Iterator<E> iterator() {
// TODO 自动生成的方法存根
return null;
}
@Override
public void add(E element) {
// TODO 自动生成的方法存根
add(size,element);
}
@Override
public void add(int index, E element) {
// TODO 自动生成的方法存根
if(index<0||index>size) {
throw new IndexOutOfBoundsException("Index is bound!");
}
Node node = new Node(element);
if(size==0) {//此时表中无元素
node.pre = node;
node .next=node;
head = node;
tail = node;
}else if(index==0) {//表头添加元素
node.pre = head.pre;
node.next = head;
head.pre = node;
head = node;
tail.next = head;
}else if(index == size) {//表尾添加
node.next = tail.next;
tail.next = node;
node.pre=tail;
tail =node;
head.pre =tail;
}else {//其他情况 也就是在中间添加元素
Node p =head;
for(int i=0;i<index-1;i++) {
p = p.next;
}
Node q = p.next;
p.next=node;
node.pre=p;
q.pre=node;
node.next=p;
}
size++;
}
@Override
public void remove(E element) {
// TODO 自动生成的方法存根
remove(size);
}
@Override
public E remove(int index) {
// TODO 自动生成的方法存根
if(index<0||index>=size) {
throw new IndexOutOfBoundsException("Index is bound!");
}
E ret =null;
if(size==1) {//只有一个元素
ret = head.data;
head =null;
tail =null;
size =0;
}
else if(index==0) {
ret = head.data;
Node node = head.next;
node.pre = head.pre;
head.next=null;
head.pre =null;
head =node;
tail.next = head;
}else if(index==size-1) {
Node node = tail.pre;
ret = tail.data;
node.next = tail.next;
tail.pre = null;
tail.next = null;
tail =node;
head.pre = tail;
}else {
Node p,q,r,node =head;
for(int i=0;i<index-1;i++) {
head = head.next;
}
p = node;
q=p.next;
ret = q.data;
r=q.next;
p.next=r;
r.pre=p;
q.next=null;
q.pre=null;
}
size--;
return ret;
}
@Override
public String toString() {
// TODO 自动生成的方法存根
StringBuilder sb =new StringBuilder();
sb.append('{');
Node node =head;
while(node.next!=head) {
sb.append(node.data);
node =node.next;
sb.append(',');
}
sb.append(node.data);
sb.append('}');
return sb.toString();
}
@Override
public E get(int index) {
// TODO 自动生成的方法存根
if(index<0||index>=size) {
throw new IndexOutOfBoundsException("Index is bound!");
}
E ret = null ;
if(index<size/2) {
Node p = head;
for(int i=0;i<index;i++) {
p =p.next;
}
ret = p.data;
}else {
Node q = tail;
for(int i=size-1;i>index;i--) {
q = q.pre;
}
ret = q.data;
}
return ret;
}
@Override
public E set(int index, E element) {//根据指定下标修改元素
// TODO 自动生成的方法存根
if(index<0||index>=size) {
throw new IndexOutOfBoundsException("Index is bound!");
}
E ret = null ;
if(index<size/2) {
Node p = head;
for(int i=0;i<index;i++) {
p =p.next;
}
ret = p.data;
p.data = element;
}else {
Node q = tail;
for(int i=size-1;i>index;i--) {
q = q.pre;
}
ret = q.data;
q.data = element;
}
return ret;
}
@Override
public int size() {//获取有效长度
// TODO 自动生成的方法存根
return size;
}
@Override
public int indexOf(E element) {//查找元素的下标
// TODO 自动生成的方法存根
if(isEmpty()) {
try {
throw new IllegalAccessException("NULL!");
} catch (IllegalAccessException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
Node node =head;
for(int i=0;i<size;i++) {
if(node.data.equals(element)) {
return i;
}
node = node.next;
}
return -1;
}
@Override
public boolean contains(E element) {
// TODO 自动生成的方法存根
return indexOf(element)!=-1;
}
@Override
public boolean isEmpty() {
// TODO 自动生成的方法存根
return size==0;
}
@Override
public void clear() {
// TODO 自动生成的方法存根
head =null;
tail =null;
size =0;
}
@Override
public void sort(Comparator<E> comparator) {
// TODO 自动生成的方法存根
if(comparator==null) {
throw new IndexOutOfBoundsException("Is NULL!");
}
if(size<2) {
return;
}
Node i = head.next;
Node j = null;
Node k = null;
E e = null;
while(i!=head) {
e = i.data;
j =i;
k = j.pre;
while(k!=tail&&comparator.compare(k.data, e)>0) {
j.data = k.data;
j = j.pre;
k = j.pre;
}
j.data = e;
i = i.next;
}
}
@Override
public List<E> sublist(int fromIndex, int toIndex) {
// TODO 自动生成的方法存根
if (fromIndex < 0 || toIndex >= size || fromIndex >= toIndex) {
throw new IllegalArgumentException("sublist index outof range");
}
Node nodeA = head;
for(int i=0;i<fromIndex;i++) {
nodeA = nodeA.next;
}
Node nodeB = head;
for(int i=0;i<toIndex;i++) {
nodeB = nodeB.next;
}
LinkedList<E> newList = new LinkedList<>();
while(nodeA!=nodeB) {
newList.add(nodeA.data);
nodeA = nodeA.next;
}
return newList;
}
}
测试代码
package com.my.线性结构;
public class TestS {
public static void main(String[] args) {
// TODO 自动生成的方法存根
LinkedList list =new LinkedList<>();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(3));
list.add(new Integer(4));
list.add(new Integer(5));
list.add(new Integer(6));
list.set(5, 10);
LinkedList list1 =new LinkedList<>();
list1 = (LinkedList) list.sublist(0, 3);
System.out.println(list.remove(0));
System.out.println(list.get(4));
System.out.println(list.indexOf(new Integer(3)));
System.out.println数据结构开发:循环链表与双向链表