2、链表
1、链表
2、接口设计
链表的大部分接口与 动态数组 是一致的。因此可以将这些方法设计成一个接口List。
public interface List<E> { //元素未找到 public static final int ELEMENT_NOT_FOUNT = -1; /** * 清除所有元素 */ void clear(); /** * 元素的数量 * @return */ int size(); /** * 是否为空 * @return */ boolean isEmpty(); /** * 是否包含某个元素 * @param element * @return */ boolean contains(E element); /** * 添加元素到尾部 * @param element */ void add(E element); /** * 获取index位置的元素 * @param index * @return */ E get(int index); /** * 设置index位置的元素 * @param index * @param element * @return 原来的元素ֵ */ E set(int index, E element); /** * 在index位置插入一个元素 * @param index * @param element */ void add(int index, E element); /** * 删除index位置的元素 * @param index * @return */ E remove(int index); /** * 查看元素的索引 * @param element * @return */ int indexOf(E element); }
在动态数组和链表的实现类中,存在一些重复代码,可以设计一个抽象类AbstractList,由该抽象类实现接口List,在由动态数组和链表的实现类继承即可。
public abstract class AbstractList<E> implements List<E> { //元素数量 protected int size = 0; /** * 返回元素的数量 * @return */ public int size() { return this.size; } /** * 是否为空 * @return */ public boolean isEmpty() { return size == 0; } /** * 是否包含某个元素 * @param element * @return */ public boolean contains(E element) { return indexOf(element) != ELEMENT_NOT_FOUNT; } /** * 添加元素到尾部 * @param element */ public void add(E element) { this.add(size, element); } //设置成protected,可由子类调用 protected void outOfBounds(int index) { throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + size); } protected void rangeCheck(int index) { if (index < 0 || index >= size) { outOfBounds(index); } } protected void rangeCheckForAdd(int index) { if (index < 0 || index > size) { outOfBounds(index); } } }
3、链表代码实现
注意:在编写链表过程中,要注意边界测试,比如 index 为 0 、size – 0 、size 时
package com.xpp; public class LinkedList<E> extends AbstractList<E> { private Node<E> first; @Override public void clear() { size = 0; first = null; } @Override public E get(int index) { return node(index).element; } @Override public E set(int index, E element) { Node<E> node = node(index); E old = node.element; node.element = element; return old; } /** * 在index位置添加元素 * @param index * @param element */ @Override public void add(int index, E element) { rangeCheckForAdd(index); if (index == 0) {//注意 0 位置 first = new Node<>(element, first); } else { Node<E> prev = node(index - 1); prev.next = new Node<>(element, prev.next); } size++; } /** * 获取index位置对应的节点对象 * @param index * @return */ private Node<E> node(int index) { rangeCheck(index); Node<E> node = first; for (int i = 0; i < index; i++) { node = node.next; } return node; } @Override public E remove(int index) { rangeCheck(index); Node<E> node = first; if (index == 0) { first = first.next; } else { Node<E> prev = node(index - 1); node = prev.next; prev.next = prev.next.next; } size--; return node.element; } @Override public int indexOf(E element) { if (element == null) { Node<E> node = first; for (int i = 0; i < size; i++) { if (node.element == null) { return i; } node = node.next; } } else { Node<E> node = first; for (int i = 0; i < size; i++) { if (element.equals(node.element)) { return i; } node = node.next; } } return ELEMENT_NOT_FOUNT; } private static class Node<E> { E element; Node<E> next; public Node(E element, Node<E> next) { this.element = element; this.next = next; } } @Override public String toString() { StringBuilder str = new StringBuilder(); str.append("Size: ").append(size).append(", elements=["); Node<E> node = first; for (int i = 0; i < size; i++) { if (i != 0) { str.append(", "); } str.append(node.element); node = node.next; } str.append("]"); return str.toString(); } }
本文作者:颜欢兮
本文链接:https://www.cnblogs.com/xpp3/p/18095747
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步