小白之路: 链表在java中的实现;

链表简介;

链表是数据结构中较为常见且简单的一种线性表链式结构; 由链表存储的对象在内存中通常是分散的;链表中的每一个元素称为节点, 每一个节点都有一个直接后继, 如果双链表的话还有一个直接前驱, 首节点没有直接前驱, 但是在循环链表中可以将尾节点理解为直接前驱; 尾节点没有直接后继;

链表和数组对比:

链表对首尾元素的增删改查效率极高(O(1)); 而数组对数组中每个元素的删除插入总是会伴随着整体后移或前移, 效率比较低,其删改效率为O(n);

数组相较于链表优势是按索引进行取值的速度极快(O(1)), 而链表需要一层一层的寻值;

数组结构中往往需要占用内存的的成片空间, 内存利用率不高, 而链表元素都是分散的,可以有效利用空闲位置;

链表的基本分类:

1. 单链表   2. 双链表  3. 循环链表

各种链表在Java中的实现:

单链表在Java中的实现:

在Java中LinkedList类的底层实现是使用了双向链表, 本单链表的实现主要是参照了LinkedList类的方法命名;并实现了链表的增删改查的操作;

程序如下:

基础节点类: 定义了节点存储值属性----value/  next 所代表的是该节点的直接后继

public class LinkNode<T> {
    // 值
    private T value;
    // 指针
    private LinkNode<T> next;

    public LinkNode(T value) {
        this.value = value;
    }
    public LinkNode() {}
    

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public LinkNode<T> getNext() {
        return next;
    }

    public void setNext(LinkNode<T> next) {
        this.next = next;
    }
}

这是具体的方法实现,方法没有经过大量的测试, 但是基本功能应该是没有大问题的; 如果发现bug请告知;

package learn.linklist;
import lombok.Data;
import java.util.NoSuchElementException;

/**
 * @Author:张
 * @Version:1.0
 * @Date:2024/6/11-10:35
 * @Since:jdk1.8
 * @Description:
 */
@Data
public class MyLinkList<T> {
    // 头节点
    private LinkNode<T> head;
    // 尾节点
    private LinkNode<T> end;

    // 头节点标记
    private boolean isHead = true;

    // 节点个数
    private int size;



    // 插入
    // 首插入
    public void addFirst(T element) {
        // 如果首节点为null
        if(head == null) {
            head = new LinkNode<>();
            head.setValue(element);
            size ++;
            return;
        }
        // 1. 首先new一个节点
        LinkNode<T> tLinkNode = new LinkNode<>(element);
        // 2. 把这个节点的next属性设置为首节点
        tLinkNode.setNext(head);
        // 3. 将此节点变成首节点
        head = tLinkNode;

        // 节点个数增加
        size++;
    }
    // 尾插入
    public void addLast(T element) {
        if(end == null) {
            // 插入头节点
            addFirst(element);
            end = head;
            return;
        }
        // 1. 先初始化一个新节点
        LinkNode<T> tLinkNode = new LinkNode<>();
        tLinkNode.setValue(element);
        // 2. 将end的next指向这个新节点
        end.setNext(tLinkNode);
        // 3. 将end更新为新节点
        end = tLinkNode;
        size ++;
    }
    // 中间插入
    public void add(int index, T element) {
        // 异常判断
        if(index > size || index < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        // 首节点之前
        if(index == 0){
            addFirst(element);
            return;
        }
        //尾节点
        if(index == size) {
            addLast(element);
            return;
        }
        // 其他位置
        LinkNode<T> c = head;
        LinkNode<T> b = null;
        int i = 0;
        while (i <= size) {
            if(i > 0 && i == index) {
                LinkNode<T> newNode = new LinkNode<>(element);
                newNode.setValue(element);
                newNode.setNext(c);
                b.setNext(newNode);
                size++;
                return;
            }
            i++;
            b = c;
            c = c.getNext();
        }

    }
    // 普通插入
    public void add(T element) {
        addLast(element);
     }

    // 删除
    /**
     * 无参删除head
     */
    public void remove(){
        // 没有参数的删除就是移除首节点
        head =  head.getNext();
        size --;
    }

    /**
     * 删除第一个匹配的节点
     * @param element
     */
    public void remove(T element) {
        LinkNode<T> c = head;
        T targetValue = c.getValue();
        LinkNode<T> b = null;

        int i = 0;
        while (i <= size) {
            if(targetValue != null && targetValue.equals(element)) {
                if(i == size - 1) {
                    end = b;
                    b.setNext(null);
                }else {
                    if(i == 0) {
                        head = head.getNext();
                    }else {
                        b.setNext(c.getNext());
                    }
                }
                size--;
                return;
            }

            i++;
            b = c;
            c = c.getNext();
            targetValue = c.getValue();
        }
    }

    /**
     * 删除index位置的节点
     * @param index
     */
    public void remove(int index) {
        // 异常判断
        if(index > size || index < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        if(index == 0) {
            remove();
            return;
        }

        // 其他位置
        LinkNode<T> c = head;
        LinkNode<T> b = null;
        int i = 0;
        while (i <= size) {
            if(i > 0 && i == index) {
                if(index == size - 1) {
                    end = b;
                    b.setNext(null);
                }else {
                    b.setNext(c.getNext());
                }
                size--;
                return;
            }

            i++;
            b = c;
            c = c.getNext();
        }


    }

    // 查找
    public T get(int index) {
        // 异常判断
        if(index > size || index < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        if(index == 0) {
            return getFirst();
        }
        if(index == size - 1) {
            return getLast();
        }

        int i = 1;
        LinkNode<T> currentNode = head.getNext();
        T value = currentNode.getValue();
        while (i < size) {
            if(index == i) {
                return value;
            }
            currentNode = currentNode.getNext();
            value = currentNode.getValue();
            i++;
        }
        return  null;
    }
    public T getFirst() {
        if(head == null) {
            throw new NoSuchElementException();
        }
        return head.getValue();
    }
    public T getLast() {
        if(end == null) {
            throw new NoSuchElementException();
        }
        return end.getValue();
    }

    // 更新
    public void set(int index, T element){
        // 异常判断
        if(index > size || index < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        if(index == 0) {
            head.setValue(element);
            return;
        }
        if(index == size - 1) {
            end.setValue(element);
            return;
        }

        LinkNode<T> currentNode = head.getNext();
        int i = 1;
        while (i < size) {
            if (i == index) {
                currentNode.setValue(element);
                return;
            }
            i++;
            currentNode = currentNode.getNext();
        }
    }
    // 遍历打印链表
    public void show() {
        // 先打印头结点信息
        System.out.print("[ ");
        System.out.print(head.getValue() + " ");
        LinkNode<T> next = head.getNext();
        while (true) {
            if (next != null) {
                System.out.print(next.getValue() + " ");
            }else {
                break;
            }
            next = next.getNext();
        }

        System.out.println("]");

    }
}

双链表在Java中的实现:

因为双链表和单链表实现起来区别并不是很大,所以只做了简单的实现;

甚至双链表在前继后驱的指针改变上非常的方便;

public class LinkNode<T> {
    private LinkNode<T> preNode;
    private LinkNode<T> nextNode;
    private T value;

    public LinkNode(T value) {
        this.value = value;
    }
    public LinkNode() {}

    public LinkNode<T> getPreNode() {
        return preNode;
    }

    public void setPreNode(LinkNode<T> preNode) {
        this.preNode = preNode;
    }

    public LinkNode<T> getnextNode() {
        return nextNode;
    }

    public void setnextNode(LinkNode<T> nextNode) {
        this.nextNode = nextNode;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}

public class MyLinkedList<T> {
    @Setter
    @Getter
    private LinkNode<T> head;
    @Setter
    @Getter
    private LinkNode<T> tail;
    private int size;


    /**
     * 将元素添加的首部
     *
     * @param value
     */
    public void addFirst(T value) {
        LinkNode<T> newNode = new LinkNode<>(value);
        if (size == 0) { // 容器中没有一个元素
            head = newNode;
            // 因为只有一个元素,所以尾节点也是它
            tail = newNode;
        } else {
            // 首节点的前驱变成该节点
            head.setPreNode(newNode);
            // 该节点的后继变成首节点
            newNode.setnextNode(head);
            // 首节点易主
            head = newNode;
        }
        // 元素个数增加
        size++;
    }

    /**
     * 将新元素添加到容器尾部
     */
    public void addLast(T value) {
        if (size == 0) {
            addFirst(value);
        } else {
            LinkNode<T> newNode = new LinkNode<>(value);
            // 尾节点的后继变成该节点
            tail.setnextNode(newNode);
            // 新节点的前驱变成尾节点
            newNode.setPreNode(tail);
            // 新节点变成尾节点
            tail = newNode;
            size++;
        }

    }

    /**
     * 在index处插入节点
     *
     * @param index
     * @param value
     */
    public void add(int index, T value) {
        // 判断节点的合理性
        if (index < 0 || index > size) {
            throw new ArrayIndexOutOfBoundsException();
        }
        // 如果index为0
        if (index == 0) {
            addFirst(value);
            return;
        }
        // 如果index为size
        if (index == size) {
            addLast(value);
            return;
        }

        int i = 1;
        LinkNode<T> currentNode = head.getnextNode();
        LinkNode<T> newNode = new LinkNode<>(value);

        while (true) {
            if (i == index) {
                LinkNode<T> preNode = currentNode.getPreNode();
                preNode.setnextNode(newNode);
                newNode.setPreNode(preNode);
                newNode.setnextNode(currentNode);
                currentNode.setPreNode(newNode);
                size++;
                return;
            }
            currentNode = currentNode.getnextNode();
            i++;
        }
    }

    /**
     * 插入一个节点
     * @param value
     */
    public void add(T value) {
        addLast(value);
    }


    /**
     * 在index处批量插入一个list
     *
     * @param index
     * @param newList
     */
    public void addAll(int index, MyLinkedList<T> newList) {
        // 判断节点的合理性
        if (index < 0 || index > size) {
            throw new ArrayIndexOutOfBoundsException();
        }
        // index为零 首部直接插入
        if (index == 0) {
            LinkNode<T> newListTail = newList.getTail();
            newListTail.setnextNode(head);
            head.setPreNode(newListTail);
            head = newListTail;
            size += newList.size();
            return;
        }

        // 如果index为size
        if (index == size) {
            LinkNode<T> newListHead = newList.getHead();
            newListHead.setPreNode(tail);
            tail.setnextNode(newListHead);
            tail = newListHead;
            size += newList.size();
            return;
        }

        int i = 1;
        LinkNode<T> currentNode = head.getnextNode();
        while (true) {
            if(index == i) {
                LinkNode<T> nextNode = currentNode.getnextNode();
                currentNode.setnextNode(newList.getHead());
                newList.getHead().setPreNode(currentNode);
                newList.getTail().setnextNode(nextNode);
                nextNode.setPreNode(newList.getTail());
                size += newList.size();
            }
            currentNode = currentNode.getnextNode();
            i++;
        }
    }

    /**
     * 返回容器的长度
     *
     * @return
     */
    public int size() {
        return size;
    }


    public void show() {
        int i = 0;
        LinkNode<T> currentNode = head;
        System.out.print("[ " + currentNode.getValue());
        while (i < size - 1) {
            i++;
            currentNode = currentNode.getnextNode();
            System.out.print("," + currentNode.getValue());
        }
        System.out.println(" ]");
    }
}

至于循环链表,我觉得大差不差,首尾相接即可;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值