JAVA数据结构:通过实现List接口的自定义TLinkedList

 首先定义接口 List<E> ,以下是对每个方法的详细解释:

  • int size(): 返回列表中元素的数量。
  • boolean isEmpty(): 判断列表是否为空,如果为空则返回true,否则返回false。
  • boolean contains(Object o): 判断列表是否包含指定的元素,如果包含则返回true,否则返回false。
  • Object[] toArray(): 将列表转换为一个数组。
  • boolean add(E e): 将指定的元素添加到列表的末尾,并返回true。
  • boolean remove(Object o): 从列表中移除指定的元素,如果成功移除则返回true,否则返回false。
  • boolean containsAll(List<E> c): 判断列表是否包含另一个集合中的所有元素,如果是则返回true,否则返回false。
  • boolean addAll(List<? extends E> c): 将另一个集合中的所有元素添加到列表的末尾,如果成功添加则返回true。
  • boolean addAll(int index, List<? extends E> c): 在指定位置插入另一个集合中的所有元素。
  • boolean removeAll(List<?> c): 移除列表中与另一个集合相同的所有元素。
  • void clear(): 移除列表中的所有元素,使其为空。
  • E get(int index): 返回指定位置的元素。
  • E set(int index, E element): 将指定位置的元素替换为新的元素,并返回原来的元素。
  • void add(int index, E element): 在指定位置插入一个元素。
  • E remove(int index): 移除并返回指定位置的元素。
  • int indexOf(Object o): 返回指定元素在列表中第一次出现的位置索引,如果不存在则返回-1。

这个接口定义了列表常用的操作,实现这个接口的类需要提供对应的方法实现,例如ArrayList或LinkedList。

public interface List<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Object[] toArray();
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(List<E> c);
    boolean addAll(List<? extends E> c);
    boolean addAll(int index, List<? extends E> c);
    boolean removeAll(List<?> c);
    void clear();
    E get(int index);
    E set(int index, E element);
    void add(int index, E element);
    E remove(int index);
    int indexOf(Object o);

}

接下来是一个使用链表实现的自定义泛型列表类 TLinkedList,实现了之前提到的 List 接口。以下是对代码的详细解释:

  • Node 类:

    • Node<E> 是一个节点类,包含一个数据域 value 和一个指向下一个节点的引用 next
    • 构造方法 Node(E o, Node<E> next) 用于初始化节点。
class Node<E> {
    E value;
    Node<E> next;

    public Node(E o, Node<E> next){
        this.value = o;
        this.next = next;
    }
}
  • TLinkedList 类:

    • 实现了 List 接口,使用泛型来表示列表的元素类型。
    • 成员变量包括 root(链表的头节点)、last(链表的尾节点)、size(链表中的元素个数)。
public class TLinkedList<E> implements List{
    Node<E> root;
    Node<E> last;
    int size;
}
  • 构造方法:

    • TLinkedList(E e): 接受一个元素作为参数,创建包含该元素的链表。
    • TLinkedList(): 无参数构造方法,用于创建空链表。
public TLinkedList(E e){
        if(e == null){
            throw new NullPointerException ("o:" + e);
        }
        root = new Node<>(e, null);
        size++;
    }

public TLinkedList(){ }//添加数据
  • 主要方法实现:

size(): 返回链表中的元素个数。

public int size() {
        return size;
    }

isEmpty(): 判断链表是否为空。

public boolean isEmpty() {
        return size==0;
    }

contains(Object o): 判断链表是否包含指定元素。

public boolean contains(Object o) {
        Node<E> tempNode = root;
        while(tempNode != null){
            if(tempNode.value == o){
                return true;
            }else{
                tempNode = tempNode.next;
            }
        }
        return false;
    }

toArray(): 将链表转换为数组。

public Object[] toArray() {
        Object[] array = new Object[size];
        Node<E> tempNode = root;
        int index = 0;

        while (tempNode != null) {
            array[index++] = tempNode.value;
            tempNode = tempNode.next;
        }

        return array;
    }

add(Object o): 向链表末尾添加元素。

public boolean add(Object o) {
        // 判断 root 是否为null
        if(root == null){
            root = new Node<>( (E)o, null);
            size++;
            return true;
        }
        // 循环查找 最后一个节点
        // 迭代的思路
        Node<E> tempNode = root;
        while(tempNode.next != null){
            // 替换
            tempNode = tempNode.next;
        }
        //System.out.println ("tempNode:" + tempNode);
        tempNode.next = new Node<>((E)o, null);
        size++;
        return true;
    }

remove(Object o): 从链表中移除指定元素。

public boolean remove(Object o) {
        Node<E> tempNode = root;

        // 处理从根节点移除的情况
        while (tempNode != null && tempNode.value==o) {
            tempNode = tempNode.next;
            root = tempNode;
            size--;
        }

        // 处理从链表其余部分移除的情况
        while (tempNode != null && tempNode.next != null) {
            if (tempNode.next.value==o) {
                tempNode.next = tempNode.next.next;
                size--;
            } else {
                tempNode = tempNode.next;
            }
        }

        return true;
    }

containsAll(List c): 判断链表是否包含另一个集合中的所有元素。

public boolean containsAll(List c) {
        for (int i = 0; i < c.size(); i++) {
            Object element = c.get(i);
            boolean found = false;
            Node<E> tempNode = root;
            while (tempNode != null) {
                if (tempNode.value.equals(element)) {
                    found = true;
                    break;
                } else {
                    tempNode = tempNode.next;
                }
            }
            if (!found) {
                return false; // 如果任何元素未找到,则返回false
            }
        }
        return true; // 所有元素都找到了
    }

addAll(List c): 将另一个集合中的所有元素添加到链表末尾。

public boolean addAll(List c) {
        for (int i=0 ; i < c.size() ; i++) {
            Object element = c.get(i);
            // 判断 root 是否为null
            if(root == null){
                root = new Node<>( (E)element, null);
                size++;
            }
            // 循环查找 最后一个节点
            // 迭代的思路
            Node<E> tempNode = root;
            while(tempNode.next != null){
                // 替换
                tempNode = tempNode.next;
            }
            //System.out.println ("tempNode:" + tempNode);
            tempNode.next = new Node<>((E)element, null);
            size++;
        }
        return false;
    }

addAll(int index, List c): 在指定位置插入另一个集合中的所有元素。

public boolean addAll(int index, List c) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }

        for (int i = 0; i < c.size(); i++) {
            Object element = c.get(i);

            if (index == 0) {
                // 在链表头部插入新节点
                root = new Node<>((E) element, root);
            } else {
                Node<E> tempNode = root;
                for (int j = 0; j < index - 1; j++) {
                    tempNode = tempNode.next;
                }

                tempNode.next = new Node<>((E) element, tempNode.next);
            }

            size++;
            index++;
        }

        return true;
    }

clear(): 移除链表中的所有元素。

public void clear() {
        Node<E> tempNode = root;
        while(tempNode != null){
            // 替换
            tempNode.value = null;
            tempNode = tempNode.next;
        }
        size = 0;
    }

get(int index): 获取指定位置的元素。

public Object get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }

        Node<E> tempNode = root;
        for (int i = 0; i < index; i++) {
            tempNode = tempNode.next;
        }

        return tempNode.value;
    }

set(int index, Object element): 替换指定位置的元素。

public Object set(int index, Object element) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }

        Node<E> tempNode = root;
        for (int j = 0; j < index; j++) {
            tempNode = tempNode.next;
        }

        tempNode.value = (E) element; // 直接更新指定索引处节点的值
        return true;
    }

add(int index, Object element): 在指定位置插入一个元素。

public void add(int index, Object element) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }

        if (index == 0) {
            // 插入到链表头部
            root = new Node<>((E) element, root);
        } else {
            Node<E> tempNode = root;
            for (int i = 0; i < index - 1; i++) {
                tempNode = tempNode.next;
            }

            tempNode.next = new Node<>((E) element, tempNode.next);//
        }

        size++;
    }

remove(int index): 移除指定位置的元素。

public Object remove(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
        Node<E> tempNode = root;
        for (int j = 0; j < index-1; j++) {
            tempNode = tempNode.next;
        }
        tempNode.next=tempNode.next.next;
        size--;
        return true;
    }

indexOf(Object o): 获取第一个匹配元素的索引。

public int indexOf(Object o) {
        int index=0;
        Node<E> tempNode = root;
        while(tempNode != null){
            if(tempNode.value == o){
                return index;
            }else{
                tempNode = tempNode.next;
                index=index+1;
            }
        }
        return -1;
    }

removeAll(List c): 移除链表中与另一个集合相同的所有元素。

public boolean removeAll(List c) {
        boolean modified = false;

        for (int i = 0; i < c.size(); i++) {
            Object element = c.get(i);
            Node<E> tempNode = root;
            Node<E> prevNode = null;

            while (tempNode != null) {
                if (tempNode.value.equals(element)) {
                    if (prevNode == null) {
                        // 移除头节点
                        root = tempNode.next;
                    } else {
                        prevNode.next = tempNode.next;
                    }

                    size--;
                    modified = true;
                    break;  // 一旦找到并移除元素,就退出循环
                }

                prevNode = tempNode;
                tempNode = tempNode.next;
            }
        }

        return modified;
    }
  • 主方法(main):

    • 演示对 TLinkedList 对象进行一系列操作的例子,对实现的方法进行测试包括添加、移除、查询等。
public static void main(String[] args) {
        TLinkedList<Integer> myLinkList = new TLinkedList<>();
        for(int i=1;i<11;i++){
            myLinkList.add(i);
        }
        for(int i=0;i<10;i++){
            System.out.println(myLinkList.get(i));
        }

        //System.out.println(myLinkList.size);

        //System.out.println(myLinkList.isEmpty());

        //System.out.println(myLinkList.contains(10));

        //Object[] array = myLinkList.toArray();
        //for (Object element : array) {
            //System.out.print(element + " ");
        //}

        //myLinkList.remove((Integer)5);
        //for(int i=0;i<9;i++){
            //System.out.println(myLinkList.get(i));
        //}

        //myLinkList.clear();
        //System.out.println(myLinkList.size);

        //myLinkList.set(0,11);
        //for(int i=0;i<10;i++){
            //System.out.println(myLinkList.get(i));
        //}

        //myLinkList.add(1,12);
        //for(int i=0;i<11;i++){
            //System.out.println(myLinkList.get(i));
        //}

        //myLinkList.remove(1);
        //for(int i=0;i<9;i++){
            //System.out.println(myLinkList.get(i));
        //}

        //System.out.println(myLinkList.indexOf(5));


        TLinkedList<Integer> testList1 = new TLinkedList<>();
        testList1.add(8);
        testList1.add(9);
        testList1.add(10);

        TLinkedList<Integer> testList2 = new TLinkedList<>();
        testList2.add(11);
        testList2.add(12);
        testList2.add(13);

        for(int i=0;i<3;i++){
            //System.out.println(testList1.get(i));
        }

        for(int i=0;i<3;i++){
            //System.out.println(testList2.get(i));
        }

        //System.out.println(myLinkList.containsAll(testList1));
        //System.out.println(myLinkList.containsAll(testList2));

        //myLinkList.addAll(testList2);
        //for(int i=0;i<13;i++){
            //System.out.println(myLinkList.get(i));
        //}

        //myLinkList.addAll(1,testList2);
        //for(int i=0;i<13;i++){
            //System.out.println(myLinkList.get(i));
        //}

        //myLinkList.removeAll(testList1);
        //for(int i=0;i<7;i++){
            //System.out.println(myLinkList.get(i));
        //}

    }

链表是一种常见的线性数据结构,具有以下特点:

  • 非连续存储: 链表中的元素在内存中可以是不连续存储的,每个元素包含一个数据域和一个指向下一个元素的引用。

  • 动态大小: 链表的大小可以动态改变,不像数组有固定的大小。

  • 插入和删除高效: 插入和删除操作在链表中相对高效,特别是在中间插入或删除元素,因为不需要移动整个数据结构。

  • 随机访问较慢: 相比于数组,链表的随机访问效率较低,需要从头节点开始遍历直到找到目标元素。

  • 不浪费内存空间: 链表可以动态分配内存,不需要预先指定固定大小,因此不会浪费内存。

适合执行以下操作:

  • 频繁的插入和删除: 由于插入和删除操作在链表中效率较高,链表适合在频繁进行这些操作的场景。

  • 不需要随机访问: 如果主要操作是在链表的首部或尾部进行插入、删除等操作,而不需要随机访问元素,链表是一个合适的选择。

  • 内存动态分配: 当不知道数据量的大小,或者需要动态分配内存时,链表可以更好地满足需求。

  • 不浪费内存空间: 由于链表可以动态调整大小,避免了固定大小数组可能带来的内存浪费。

需要注意的是,链表并不适合需要频繁随机访问元素的情况,因为这时数组更为高效。选择链表还是数组取决于具体的应用场景和操作需求。

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值