简单链表功能实现

 单向链表

public class Linked<E> {

    private Node<E> first;
    private Node<E> last;

    public void addFirst(E item){
        //新节点
        final Node<E> newNode = new Node<E>(item);

        //保存原头节点
        final Node<E> f = first;

        //新节点为头节点
        first = newNode;

        if (f == null){
            last = newNode;
        }else {
            //新节点指向原头节点
            newNode.next = f;
        }
    }

    public void addLast(E item){
        final Node<E> newNode = new Node<E>(item);

        final Node<E> l = last;

        last = newNode;

        if (l == null){
            first = newNode;
        }else {
            l.next = newNode;
        }
    }

    public String toString(){
        StringJoiner stringJoiner = new StringJoiner("->");
        for (Node<E> n = first;n != null;n = n.next){
            stringJoiner.add(n.item.toString());
        }
        return stringJoiner.toString();
    }

    static class Node<E>{
        E item;
        Node<E> next;

        public Node(E data){
            this.item = data;
        }
    }
}

双向链表

public class Linked2<E> {
    private int size;
    private Node<E> first;
    private Node<E> last;

    //头插法
    public void addFirst(E item){
        final Node<E> f = first;

        final Node<E> newNode = new Node<E>(null,item,f);

        first = newNode;

        if (f == null){
            last = newNode;
        }else {
            f.prev = newNode;
        }
        size ++;
    }

    //尾插法
    public void addLast(E item){
        final Node<E> l = last;

        Node<E> newNode = new Node<E>(l,item,null);

        last = newNode;

        if (last == null){
            first = newNode;
        }else {
            l.next = newNode;
        }
        size ++;
    }

    public void removeFirst(){
        final Node<E> f = first;
        final Node<E> next = f.next;

        f.item = null;
        f.next = null;

        first = next;

        if (next == null){
            last = null;
        }else{
            next.prev = null;
        }
        size --;
    }

    public void removeLast(){
        final Node<E> l = last;
        final Node<E> prev = l.prev;

        l.item = null;
        l.prev = null;

        last = prev;

        if (prev == null){
            first = null;
        }else {
            prev.next = null;
        }
        size --;
    }

    public String toStringFromFirst(){
        StringJoiner stringJoiner = new StringJoiner("->");
        for (Node<E> n = first; n != null; n = n.next){
            stringJoiner.add(n.item.toString());
        }
        return stringJoiner.toString();
    }

    public String toStringFromLast(){
        StringJoiner stringJoiner = new StringJoiner("<-");
        for (Node<E> n = last;n != null;n = n.prev){
            stringJoiner.add(n.item.toString());
        }
        return stringJoiner.toString();
    }

    static class Node<E>{
        private Node<E> prev;
        private E item;
        private Node<E> next;
        public Node(Node<E> prev,E element,Node<E> next){
            this.prev = prev;
            this.item = element;
            this.next = next;
        }
    }
}

 用例链表

public class Linked3<E> {
    public Node<E> first;
    public Node<E> last;
    public int size;

    public int size(){
        for (Node n = first;n != null;n = n.next){
            size ++;
        }
        return size;
    }

    public void addFirst(E item){
        final Node<E> newNode = new Node<E>(item);
        final Node<E> f = first;

        first = newNode;
        if (f == null){
            last = newNode;
        }else {
            newNode.next = f;
        }
    }

    public Node addLast(E item){
        final Node<E> newNode = new Node<E>(item);
        final Node<E> l = last;

        last = newNode;
        if (l == null){
            first = newNode;
        }else {
            l.next = newNode;
        }
        return newNode;
    }

    public String get(){
        StringJoiner stringJoiner = new StringJoiner("->");
        for(Node<E> n = first;n != null;n = n.next){
            stringJoiner.add(n.item.toString());
        }
        return stringJoiner.toString();
    }

    public void addNode(Node node){
        for (Node n = node;n != null;n = node.next){
            addLast((E) n.item);
        }
    }

    static class Node<E>{
        E item;
        Node<E> next;
        public Node(E item){
            this.item = item;
        }
    }
}

有序链表合并

        两链表从头节点开始遍历比较,小的放入结果链表中,后继节点继续比较,大的不动,直至一个链表为空,另一个则一直放,两链表都为空时合并完成。

    //有序链表合并,双指针法
    public static Linked3 meger(Linked3 l1,Linked3 l2){
        Linked3.Node<Integer> p1 = l1.first;
        Linked3.Node<Integer> p2 = l2.first;
        //结果链表
        Linked3<Integer> result = new Linked3<>();
        while (p1 != null || p2 != null){
            if (p1 == null){
                result.addLast(p2.item);
                p2  = p2.next;
                continue;
            }
            if (p2 == null){
                result.addLast(p1.item);
                p1 = p1.next;
                continue;
            }
            if (p1.item < p2.item){
                result.addLast(p1.item);
                p1 = p1.next;
            }else {
                result.addLast(p2.item);
                p2 = p2.next;
            }
        }
        return result;
    }

链表反转

        将链表遍历放入栈,再从栈取出存入链表,借助栈先进后出完成反转。

    //链表反转,借助栈
    public static Linked3 reverse(Linked3 l){
        Stack<Linked3.Node> stack = new Stack<>();
        for (Linked3.Node<Integer> n = l.first;n != null;n = n.next){
            stack.add(n);
        }
        l = new Linked3();
        while (!stack.isEmpty()){
            l.addLast(stack.pop().item);
        }
        return l;
    }

链表计算两数和

        两链表从头节点开始遍历(两链表都是头插法产生,方便运算,即头部低位,尾部高位),依次相加,算出当前位与进位值,当前位存入结果链表,进位值参与下一位预算。注意最高位的进位。

    //遍历头插法的每个node相加,注意进位
    public static Linked3 addTwoNumbers(Linked3 l1,Linked3 l2){
        Linked3.Node<Integer> n1 = l1.first;
        Linked3.Node<Integer> n2 = l2.first;

        Linked3<Integer> result = new Linked3<>();

        //进位
        int carry = 0;

        while (n1 != null || n2 != null){
            int x = n1 != null ? n1.item : 0;
            int y = n2 != null ? n2.item : 0;

            int sum = x + y + carry;

            carry = sum / 10;

            result.addFirst(sum % 10);

            if (n1 != null){
                n1 = n1.next;
            }
            if (n2 != null){
                n2 = n2.next;
            }
            //注意最终进位
            if (carry != 0){
                result.addFirst(carry);
            }

        }
        return result;
    }

判断链表是否有环

1. 使用set集合的特性,判断链表中是否有重复 Node ,有则有环,反之无环。

2. 使用快慢指针法。两个指针,快指针一次走两步,慢指针一次走一步,同时从头节点出发,若能指向同一个 Node 证明有环。

    //set判断
    public static boolean hasCycle1(Linked3.Node node){
        HashSet<Linked3.Node> set = new HashSet<>();
        while (node != null){
            if (set.contains(node)){
                return true;
            }
            set.add(node);
            node = node.next;
        }
        return false;
    }

    //快慢指针,判断有无环
    public static boolean hasCycle2(Linked3.Node node){
        if (node == null){
            return false;
        }

        Linked3.Node fast = node;
        Linked3.Node slow = node;
        while (fast != null && fast.next != null && slow != null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow){
                return true;
            }
        }
        return false;
    }

判断两链表是否相交

1. 将两个链表依次遍历,如有相同节点则相交。

2. 两链表长度若不相等,相交节点必然在长链表差值之后,则使长链表指针后移差值个节点,使得两个链表剩余长度相同,再同时后移遍历,遇到相同节点跳出循环,证明相交。

    //双遍历
    public static boolean isIntersect1(Linked3 link1, Linked3 link2) {
        for (Linked3.Node n = link1.first;n != null;n = n.next){
            for (Linked3.Node m = link2.first;m != null;m = m.next){
                if (n == m){
                    return true;
                }
            }
        }
        return false;
    }

    //双指针
    public static boolean isIntersect2(Linked3 link1, Linked3 link2) {
        if (link1 ==null || link2==null){
            return false;
        }
        //长链表头节点
        Linked3.Node p = link1.size() > link2.size()? link1.first:link2.first;
        //短链表头节点
        Linked3.Node q = link1.size() > link2.size()? link2.first:link1.first;

        //长度差
        int diff = Math.abs(link1.size() - link2.size());

        //长链表后移diff个节点,使长短链表长度一致
        while(diff-- > 0){
            p = p.next;
        }

        //判断是否相等(相交)
        while (p != q){
            p = p.next;
            q = q.next;
        }

        //跳出循环有相交
        if (q != null){
            return true;
        }else {
            return false;
        }
    }

链表实现LRU缓存

哈希表 + 双向链表(有固定头尾节点的)实现

哈希表的 value 与链表的节点形成映射关系

哈希表进行存取操作,对应的链表节点移动至首部(最近使用)

超出缓存容量删除链表尾部(最近最少使用)

public class LRUCache {
    //哈希表
    private Map<Integer,Node> cache = new HashMap<>();
    //链表长度
    private int size;
    //缓存容量
    private int capacity;
    //伪头节点
    private Node first;
    //伪尾节点
    private Node last;

    public LRUCache(int capacity) {
        size = 0;
        this.capacity = capacity;
        first = new Node();
        last = new Node();

        first.next = last;
        last.prev = first;
    }

    private void addFirst(Node newNode){
        newNode.prev = first;
        newNode.next = first.next;

        first.next.prev = newNode;
        first.next = newNode;
    }

    private void removeNode(Node node){
        node.next.prev = node.prev;
        node.prev.next = node.next;
    }

    private void moveToFirst(Node node){
        removeNode(node);
        addFirst(node);
    }

    private Node removeLast(){
        Node node = last.prev;
        removeNode(node);
        return node;
    }


    public void put(int key, int value) {
        Node node = cache.get(key);
        if (node == null){
            Node newNode = new Node(key,value);
            //移至首部
            addFirst(newNode);
            //map中添加新元素与映射关系
            cache.put(key, newNode);

            //判断容量
            if (++size > capacity){
                //超出容量,链表中删除最近最少使用
                Node lastNode = removeLast();
                //map中删除对应元素
                cache.remove(lastNode.key);

                size--;
            }
        }else {
            node.value = value;
            moveToFirst(node);
        }
    }

    public int get(int key) {
        Node node = cache.get(key);
        if (node == null) {
            //不存在返回-1
            return -1;
        }

        //被使用移至首部
        moveToFirst(node);
        return node.value;
    }

    public String toString(){
        StringJoiner ret = new StringJoiner(",");
        for (Map.Entry<Integer,Node> entry : cache.entrySet()){
            ret.add(String.format("[%d:%d]",entry.getKey(),entry.getValue().value));
        }
        return ret.toString();
    }

    static class Node{
        private Node prev;
        private Node next;
        public int key;
        public int value;
        public Node(){

        }
        public Node(int key,int value){
            this.key = key;
            this.value = value;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值