Java手写LinkedList 应用数据结构之双向链表

作为Java程序员,扎实的数据结构算法能力是必须的

LinkedList理解的最好方式是,自己手动实现它

        ArrayList和LinkedList是顺序存储结构和链式存储结构的表在java语言中的实现.

  ArrayList提供了一种可增长数组的实现,使用ArrayList,因为内部使用数组实现,所以,它的优点是,对于get和set操作调用花费常数时间.缺点是插入元素和删除元素会付出昂贵的代价.因为这个操作会导致后面的元素都要发生变动,除非操作发生在集合的末端.

  鉴于这个缺点,如果需要对表结构的前端频繁进行插入,删除操作,那么数组就不是一个好的实现,为此就需要使用另一种结构,链表,而LinkedList就是基于一种双链表的实现,使用它的优点就是,对于元素的插入,删除操作开销比较小,无论是在表的前端还是后端.但是缺点也显而易见,对于get操作,它需要从表的一端一个一个的进行查找,因此对get的调用花费的代价也是很昂贵的.

  理解这集合最好的方式就是自己去实现它,下面我们通过代码来实现自己的LinkedList.

注意点:在学习数据结构的双向链表,会学习头结点和尾结点,加上头结点和尾结点,操作其他结点可以保持同一个动作,但是在JDK实现双向链表代码中,没有加头结点和尾结点,下面看LinkedList实现的简易版

public class LinkedList<E> implements Iterable<E> {
	
	private int size;
	
	private Node first;
	private Node last;
	
	//静态内部类
	private static class Node<E>{
		private E data;
		private Node prev;
		private Node next;
		
		public Node(E data, Node prev, Node next) {
			super();
			this.data = data;
			this.prev = prev;
			this.next = next;
		}
	}
	
	//不添加头结点和尾结点
	public void add(int index,E e){
		testIndex(index);
		
		//根据index位置,选择不同的方式添加结点
		if(index == size){
			lastNode(e);
		}else
			//使用node()方法,查找到当前index位置的node结点
			beforeNode(node(index),e);
	}
	
	//根据索引,插入结点,参数node为插入前,需要插入位置的node
	private void beforeNode(Node<E> node, E e) {
		final Node<E> pnode = node.prev;
		final Node<E> nnode = node;
		final Node<E> newNode  = new Node<E>(e, pnode,nnode );
		//为插入的两边结点分别添加前后指针域
		pnode.next = newNode;
		nnode.prev = newNode;
		
		size++;
	}

	//默认直接在链表尾部添加结点
	public void add(E e){
		this.add(size,e);
	}
	
	//根据索引值,在链表中查找到当前位置结点
	private Node<E> node(int index) {
		if(index<size>>1){
			Node<E> node = first;
			for(int i = 0;i<index;i++)
			{
				node  = node.next;
			}
			return node;
		}else{
			Node<E> node = last;
			for(int i= size-1;i>index;i--){
				node = node.prev;
			}
			return node;
		}
	}

	//在jdk源码中,只有根据索引值来取值
	public E get(int index){
		Node<E> node = (Node) node(index);
		return node.data;
	}
	
	//在双向链表的最后添加元素,由于没有头结点和尾结点
	private void lastNode( E e) {
		final Node<E> l = last;
		final Node<E> newNode = new Node<E>(e,l,null);
		last = newNode;
		if(l == null){
			first = newNode;
		}else{
			l.next = last;
		}
		size++;
	}

	private void testIndex(int index)  {
		//抛出运行时异常,是非检查异常,所以不要trycatch,index >= 0 && index <= size;
		if(!(index>=0&&index<=size)){
			throw new ArrayOutOfBoundsException("位置信息初始化错误,大于size");
		}
	}
	
	public int size(){
		return size;
	}
	
	public boolean isEmpty(){
		return size == 0;
	}

	@Override
	public Iterator<E> iterator() {
		return new ListIterator();
	}
	
	//使用内部类,编写遍历集合逻辑
	public class ListIterator implements Iterator<E>{
		private Node<E> node = first;
		@Override
		public boolean hasNext() {
//			node = node.next;
			return node != null;
		}

		@Override
		public E next() {
			E val = node.data;
			node = node.next;
			return val;
		}
	}
	
}

下面是测试自己手写LinkedList代码

public class TestLinkedList {
	
	public static void main(String[] args) {
		LinkedList<Integer> list = new LinkedList<>();
//		System.out.println(list.size());
		list.add(111);
		list.add(1554);
		list.add(333);
		list.add(88888);
		list.add(262511);
		System.out.println(list.size());
		Integer ai = list.get(2);
		System.out.println(ai);
		
		list.add(1, 66669);
//		System.out.println(list.size());
		System.out.println(list.get(1));
		
		Iterator<Integer> it = list.iterator();
		while(it.hasNext()){
			System.out.print(it.next()+"  ");
		}
	}
}

测试结果

个人理解:理解源码和数据结构的最好方式,单步调试初步理解,自己重新手写

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章