详解双向循环链表的实现及概念

解剖双向循环链表!!!

在这里插入图片描述

双向循环链表概念

双向链表也叫双链表,是链表的一种,它的每个数据结点都有两个指针,分别指向后继和直接前区。所以,从双向链表中的任意一个结点开始,都可以很方便的访问到它的前驱结点和后继结点。如下图:
在这里插入图片描述
可以看出双向循环链表的继承体系,依然实现了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(list);
	}

}

结果:
在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛牛最爱喝兽奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值