手写双链表,实现链表的增删改查

链表一共有四种,单向链表,单向循环链表,双向链表,双向循环列表。单向链表在上篇文章中有过介绍,而单向循环链表和单向链表结构几乎相同,只是循环链表并不像是链,而是一个环,首尾相连。双向链表和双向循环链表的区别也是链和环的区别。双向链表顾名思义,有两个方向。可以从头到尾进行检索,也可以从尾到头反向检索。Java中的LinkedList就是一个双向链表。下面我们将手写一个LinkedList,实现双向链表的增删改查。

一、准备工作

我们创建一个LinkedList类,上篇文章说过,链表是由一个个的节点组成的。所以在LinkedList类中创建一个Node节点类。

注意:上篇文章说过,单链表的节点由两部分组成,而双向链表由三部分组成。pre指针域,数据域,next指针域。pre指针域中存储了上一个节点的内存地址,而next指针域中存储了下一个节点的内存地址。所以Node节点类中三个变量分别表示上述的三个含义。而链中需要保存链的首节点和尾节点。

public class LinkedList<E>{
	Node<E>first;//头结点
	Node<E>last;//尾节点
	int size = 0;//大小
	public LinkedList() {
		
	}
    private static class Node<E>{
		E item;
		Node<E>pre;//前一个节点
		Node<E>next;//后一个节点
		public Node(Node<E>pre,E item,Node<E>next) {
			this.pre = pre;
			this.item = item;
			this.next = next;
		}
	}
}

二、数据的查询

1.index<(size>>1):判断index是在链的前半部分还是后半部分

2.node=node.next:这个主要是移动node的指针位置,当符合条件的时候,就会返回当前node节点对象,node.item就是存储的数据。

/**
	 * 获取指定位置的节点
	 * @param index
	 * @return
	 */
	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.pre;
			}
			return node;
		}
	}

三、数据的增加

数据增加的核心方法是add双参方法和linklast,具体看一下注释即可。其实核心的操作就是断开连接,然后再将新数据重新连接。写的时候注意一些细节和考虑特殊情况就可以了。

/**
	 * 如果没有填写index,默认从链的尾部添加
	 * @param e
	 */
	public void add(E e) {
		add(size,e);
	}
	/**
	 * 在指定index的位置添加节点
	 * @param index
	 * @param e
	 */
	public void add(int index ,E e) {
		if(index<0||index>size) {
			return;
		}
		if(index==size) {
			linkLast(e);
		}else {
			Node<E>target=node(index);
			Node<E>preNode = target.pre;
			Node<E>newNode = new Node<E>(preNode,e,target);
			if(preNode==null) {
				first = newNode;
			}else {
				preNode.next = newNode;
			}
			target.pre = newNode;
			size++;
		}
	}

	/**
	 * 将数据添加到链的尾部
	 * @param e
	 */
	private void linkLast(E e) {
		Node<E>newNode = new Node<E>(last,e,null);
		Node<E>lastNode = last;
		last = newNode;
		if(lastNode==null) {
			first = newNode;
		}else {
			lastNode.next = newNode;
		}
		size++;
	}

四、数据的删除

数据的删除虽然和增加的方法不一样,但是原理其实是一样的,主要就是断开连接,然后再重新连接到新的节点。

/**
	 * 移除指定位置的节点
	 * @param index
	 */
	public void remove(int index) {
		Node<E>target = node(index);
		unlinkNode(target);
	}
	
	/**
	 * 断开连接
	 * @param target
	 */
	private void unlinkNode(Node<E>target) {
		Node<E>preNode = target.pre;
		Node<E>nextNode = target.next;
		if(preNode==null) {
			first = nextNode;
		}else {
			preNode.next = nextNode;
		}
		
		if(nextNode==null) {
			last = preNode;
		}else {
			nextNode.pre = preNode;
		}
		size--;
	}

以上实现的就是双向链表的增删改查操作,相对来说还是比较简单。没有什么特殊的骚操作,明白原理后,注意一些细节的地方即可。

欢迎提问,欢迎纠错

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值