单项循环链表
一、定义
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单向循环链表。(示意图如下)
单向循环列表的实现的也是 list 的方法,在这里主要说一下插入元素和删除元素;插入元素的时候会遇到从表头插入、表尾插入和指定角标处插入,这些操作基本上和单链表的元素插入类似,但是需要注意的是从表头和表尾插入的时候,要考虑头指针和尾指针的移动,还有尾结点要指向头结点形成新的循环链表。
二、代码实现
先给出一个插入元素的示意图,删除元素则逆推即可,在下面代码中插入、删除则会详细叙述。
在下面的代码中实现了 List 接口的所有方法,并且在代码中给出了详细的注释。
//单向循环链表
public class LinkedSingleLoop<E> implements List<E> {
private Node head; //头指针
private Node rear; //尾指针
private int size; //长度
public LinkedSingleLoop(){ //构造函数 当前的头和尾都指向空
head=null;
rear=null;
size=0;
}
//获取长度
@Override
public int getSize() {
return size;
}
//判空
@Override
public boolean isEmpty() {
return size==0;
}
//添加结点
@Override
public void add(int index, E e) {
if(index<0||index>size){
throw new IllegalArgumentException("角标越界");
}
Node n=new Node(); //创建一个新结点
n.data=e;
if(isEmpty()){ //表为空时
head=n; //头指向新结点
rear=n; //尾也指向新结点
rear.next=head; //把头的地址给尾结点的指针域
}else if(index==size){ //插入的位置是表尾时
n.next=rear.next; //将尾指针的指针域给新结点的指针域
rear.next=n; //将新结点的地址给当前尾指针指向的结点的指针域
rear=n; //将尾指针移到新结点
}else if(index==0){ //插入的位置是表头时
rear.next=n; //先把新结点的地址给尾结点的指针域
n.next=head; //将当前头指针指向的结点的地址给新结点的指针域
head=n; //将头指针移到新结点
}else{ //指定位置插入
Node p=head; //创建一个p指针从头开始找index位置
for(int i=0;i<index-1;i++){
p=p.next;
}
n.next=p.next; //然后将p当前指的结点的指针域赋给新结点的指针域
p.next=n; //再将新结点的地址给p当前指的结点的指针域
}
size++;
}
//头插
@Override
public void addFirst(E e) {
add(0,e);
}
//尾插
@Override
public void addLast(E e) {
add(size,e);
}
//获取角标index处的元素
@Override
public E get(int index) {
if(isEmpty()){
throw new IllegalArgumentException("空表");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
if(index==0){
return head.data;
}else if(index==size-1){
return rear.data;
}else{
Node p=head; //创建一个p指针从头开始找index位置
for(int i=0;i<index;i++){
p=p.next;
}
return p.data;
}
}
//获取表头元素
@Override
public E getFirst() {
return get(0);
}
//获取表尾元素
@Override
public E getLast() {
return get(size-1);
}
//修改角标index处的元素
@Override
public void set(int index, E e) {
if(isEmpty()){
throw new IllegalArgumentException("空表");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
Node p=head;
for(int i=0;i<index;i++){
p=p.next;
}
p.data=e;
}
//是否包含
@Override
public boolean contains(E e) {
return find(e)!=-1;
}
//查找元素
@Override
public int find(E e) {
Node p=head; //创建一个指针p从头找元素e
for(int i=0;i<size;i++){
if(p.data.equals(e)){
return i;
}
p=p.next;
}
return -1;
}
//删除元素
@Override
public E remove(int index) {
if(isEmpty()){
throw new IllegalArgumentException("空表");
}
if(index<0||index>=size){
throw new IllegalArgumentException("角标越界");
}
E ret=null; //定义一个变量ret存储所要删除的元素
if(size==1){ //如果表中只剩一个元素时
ret=head.data; //存一下要删除的元素
head=null;
rear=null;
}else if(index==size-1){ //删除尾结点时
Node p=head; //创建一个p指针从头开始找到尾结点的前一个结点
while(p.next!=rear){
p=p.next;
}
ret=rear.data; //存一下要删除的元素
p.next=rear.next; //将尾结点的指针域给前一个结点的指针域
rear=p; //尾指针前移
}else if(index==0){ //删除头结点时
ret=head.data;
rear.next=head.next;
head=head.next;
}else{ //从指定角标处删除时
Node p=head;
for(int i=0;i<index-1;i++){
p=p.next;
}
Node del=p.next;
ret=del.data;
p.next=del.next;
}
size--;
return ret;
}
//头删
@Override
public E removeFirst() {
return remove(0);
}
//尾删
@Override
public E removeLast() {
return remove(size-1);
}
//删除指定元素
@Override
public void removeElement(E e) {
int index=find(e);
if(index!=-1){
remove(index);
}else{
throw new IllegalArgumentException("元素不存在");
}
}
//清空表
@Override
public void clear() {
head=null;
rear=null;
size=0;
}
//迭代器
@Override
public Iterator<E> iterator() {
return new LinkedSingleLoopIterator();
}
public class LinkedSingleLoopIterator implements Iterator<E>{
Node p;
public LinkedSingleLoopIterator(){
p=new Node();
p.next=head;
}
@Override
public boolean hasNext() {
return p!=rear;
}
@Override
public E next() {
p=p.next;
return p.data;
}
}
private class Node{
E data; //数据域
Node next; //指针域
Node(){
this(null,null);
}
Node(E data, Node next){
this.data=data;
this.next=next;
}
@Override
public String toString() {
return data.toString();
}
}
}