链表的实现

本文介绍了如何实现一个自定义的双向链表MyLinkedList,包括内部节点类的设计、添加、删除元素的方法,以及迭代器的实现。通过示例展示了链表的基本操作。

Java的List接口有两个比较常用的实现类,分别是ArrayList和LinkedList。关于它们的区别主要是ArrayList使用动态数组存储数据,而LinkedList使用相互链接的节点存储数据。关于它们的性能比较,具体要看进行的是什么操作,此处不赘述。

相关知识:

1、链式结构是一种数据结构,它使用对象引用变量来创建对象之间的链接。

2、链表由一些对象构成,其中每个对象指向了链表的下一个对象。

3、链表会按需动态增长,因此在本质上,它没有容量限制。

4、访问链表的元素的唯一方式是,从第一个元素开始,顺着该链表往下进行。

5、改变引用顺序是维护链表的关键。

6、处理链表的首节点需要进行一些特殊处理。

7、存储在集合中的对象不应该含有基本数据结构的任何实现细节。

8、可以使用栈来模拟递归处理,以跟踪恰当的数据。

下面我们实现一个自己的MyLinkedList

一、首先定义一个内部类,使用private修饰限定其只能在类内部使用,使用static修饰表示其是类成员无需依赖具体实例。

节点类有三个成员变量(LinkedList可以使用单向,在这里使用双向是为了以后扩展)

element:当前节点的元素

previous:指向当前节点的上一个节点

next:指向当前节点的下一个节点

// 链表的节点
	private static class Node<E> {
		// 节点元素
		private E element;
		// 节点上一个节点
		private Node<E> previous;
		// 节点下一个节点
		private Node<E> next;
		// 含参构造函数
		public Node(E element, Node<E> previous, Node<E> next) {
			this.element = element;
			this.previous = previous;
			this.next = next;
		}
	}

二、接着定义三个成员变量。

first:记录第一个元素,遍历(迭代)、删除元素时使用

last:记录最后一个元素,添加元素时使用

size:记录元素数量

// 第一个元素
	private Node<E> first;
	
	// 最后一个元素
	private Node<E> last;
	
	// 元素数量
	private int size;

三、对外提供的API。

1、获取元素数量

/**
	 * 获取链表集合元素数量
	 * @return 数量
	 */
	public int size() {
		return size;
	}

2、判断链表是否为空

/**
	 * 判断是否为空:即元素个数是否为0
	 * @return 元素个数为0返回true,否则返回false
	 */
	public boolean isEmpty() {
		return size == 0;
	}

3、添加一个元素

先创建一个节点,然后判断last是否为空,是的话说明链表为空,该节点也是首节点,否的话把该节点设为last的下一节点,把该节点的上一节点设为last。接着将该元素设为last。最后将size加一。

/**
	 * 添加一个元素
	 * @param e
	 */
	public void add(E e) {
		// 1、根据元素值创建一个节点node
		Node<E> node = new Node<>(e, null, null);
		// 2、定义一个变量l保存原来last节点
		Node<E> l = last;
		// 3、如果last为空,说明没有元素,将当前节点设为第一个元素
		// 否则,将last的下一个元素指向node,并将node的上一个元素指向last
		if (Objects.isNull(l)) {
			first = node;
		} else {
			l.next = node;
			node.previous = l;
		}
		// 4、设置node为最后一个节点
		last = node;
		// 5、数量+1
		size++;
	}

4、删除一个元素

将所有符合的元素都删掉,涉及到所删节点的前后节点重新链接。

/**
	 * 删除元素
	 * @param e
	 * @return 删除的个数
	 */
	public int remove(E e) {
		// 1、从第一个节点first开始,遍历所有节点
		Node<E> current;
		int count = 0;
		for (current = first; Objects.nonNull(current); current = current.next) {
			// 将符合的元素都删掉,并且调整前面节点的下一个元素和后面节点的上一个元素
			if (Objects.equals(e, current.element)) {
				Node<E> p = current.previous;
				Node<E> n = current.next;
				if (Objects.nonNull(p)) p.next = n;
				if (Objects.nonNull(n)) n.previous = p;
				size--;
				count++;
			}
		}
		
		return count;
	}

5、迭代所有元素

需要创建一个内部类迭代器并提供接口给外部创建该类实例。迭代器提供两个方法:判断是否还有元素和获取下一个元素。

创建迭代器时,需要把当前对象作为参数,并将current设置为链表的第一个节点。next方法需要将current指向下一节点。

/**
	 * 获取一个迭代器
	 * @return 迭代器
	 */
	public Iterator<E> iterator() {
        return new Iterator<>(this);
    }
	
	
	/**
	 * 迭代器
	 * @author z_hh  
	 * @date 2018年8月9日
	 */
	public static class Iterator<E> {
		private MyLinkedList<E> linkedList;
		private Node<E> current;
		private boolean hasNext = false;
		
		// 私有构造函数,传入当前链表集合对象
		private Iterator(MyLinkedList<E> linkedList) {
			this.linkedList = linkedList;
			current = this.linkedList.first;
		}

		/**
		 * 是否还有元素
		 * @return 还有下一个元素返回true,否则返回false
		 */
		public boolean hasNext() {
			hasNext = Objects.nonNull(current);
			return hasNext;
		}
		
		/**
		 * 获取下一个元素,并把指针下移一位
		 * @return
		 */
		public E next() {
			if (!hasNext) {
				throw new UnsupportedOperationException("当前没有元素可以迭代");
			}
			Node<E> c = current;
			current = c.next;
			return c.element;
		}
	}

6、测试

/**
 * 自定义链表测试
 * @author z_hh
 * @time 2018年8月11日
 */
public class LinkedTest {

	public static void main(String[] args) {
		
		MyLinkedList<String> linkedList = new MyLinkedList<>();
		
		linkedList.add("里");
		linkedList.add("奥");
		linkedList.add("梅");
		linkedList.add(null);
		linkedList.add("西");
		linkedList.add("煌");
		linkedList.add(null);
		linkedList.add("华");
		
		System.out.println("元素数量:" + linkedList.size());
		
		System.out.println("元素为:");
		Iterator<String> iterator = linkedList.iterator();
		while (iterator.hasNext()) {
			System.out.print(iterator.next() + " ");
		}
		System.out.println();
		
		System.out.println("删除元素:煌,共删除" + linkedList.remove("煌") + "个");;
		System.out.println("删除元素:null,共删除" + linkedList.remove(null) + "个");;
		
		System.out.println("元素数量:" + linkedList.size());
		
		System.out.println("元素为:");
		Iterator<String> iterator2 = linkedList.iterator();
		while (iterator2.hasNext()) {
			System.out.print(iterator2.next() + " ");
		}
		
	}

}

结果为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值