【note】【数据结构与算法】3-链表

 

单链表:插入O(1)、访问O(n)

循环链表:约瑟夫问题

双向链表:插入、删除等操作更加简单高效,如删除指定结点之前的结点

 

数组vs链表

  1. 数组可以借助CPU缓存机制预读数据,访问效率更高。缺点是大小固定,若过大,系统可能无法分配足够空间,而链表没有大小限制,天然支持动态扩容。(区别于ArrayList的动态扩容,没有空间时,会申请一个更大的空间,把数据拷贝进去,非常耗时)
  2. 链表消耗内存大,频繁插入、删除操作容易造成内存碎片,导致频繁的垃圾回收。

 

 

缓存淘汰策略:

FIFO:先进先出策略

LFU:最少使用策略

LRU:最近最少使用策略

 

Q1:用链表实现LRU?

思路:维护一个有序链表,越靠近尾部的是越早之前访问的。当有一个新的数据被访问时,从链表头开始顺序遍历链表。1、如果这个数据在此之前已经缓存在链表中了,则将其从原来的位置删除,并插入到链表头部。2、如果该数据没有缓存在链表中,分两种情况:若缓存未满,则直接插入链表头部;若缓存已满,则删除尾结点,将新的数据插入链表的头部。

package bishi360;

import java.util.Scanner;

public class LRUBasedLinkedList<T> {
    //结点类
    class SNode<T>{
        private T element;
        private SNode next;
        public SNode(T element){
            this.element = element;
        }
        public SNode(T element,SNode next){
            this.element = element;
            this.next = next;
        }
        public SNode(){
            this.next=null;
        }

        public T getElement() {
            return element;
        }

        public void setElement(T element) {
            this.element = element;
        }

        public SNode getNext() {
            return next;
        }

        public void setNext(SNode next) {
            this.next = next;
        }
    }

    //设置默认容量
    private final static Integer DEFAULT_CAPACITY = 10;
   //头节点
    private SNode<T> headNode;
    //链表长度
    private Integer length;

    //链表容量
    private Integer capacity;
    public LRUBasedLinkedList(){
        this.headNode = new SNode<>();
        this.capacity = DEFAULT_CAPACITY;
        this.length = 0;
    }
    public LRUBasedLinkedList(int capacity){
        this.headNode = new SNode<>();
        this.capacity = capacity;
        this.length = 0;
    }

    //添加最新访问结点add
    public void add(T data){
        //查找是否已经存在(找到他的前一个结点,则存在)
        SNode preNode = findPreNode(data);
        //链表中存在,则删除原数据,再插入链表头部
        if(preNode!=null){
            deleteNextElement(preNode);
            insertAtBegin(data);
        }else{     //不存在,若容量满了则删除尾结点,否则直接插入头部
            if(length>= this.capacity){
                deleteLastElement();
            }
            insertAtBegin(data);

        }
    }

    //获取查找元素的前一个结点findPreNode
     public SNode findPreNode(T data){
        SNode node = headNode;
        while (node.getNext()!= null){
            if(data.equals(node.getNext().getElement())){
                return  node;
            }
            node=node.getNext();
        }
        return null;

     }

    //删除PreNode结点后一个元素(即所查找的元素)deleteNextElement
     public void deleteNextElement(SNode preNode){
       SNode temp = preNode.getNext();
          preNode.setNext(temp.getNext());
          temp = null;
          length--;
     }

    //链表头部插入结点insertAtBegin
     public void insertAtBegin(T data){
        SNode next = headNode.getNext();
        headNode.setNext(new SNode(data, next));
        length++;

     }

    //删除链表尾部节点deleteLastElement
    private  void deleteLastElement(){
        SNode h = headNode;
        //空链表直接返回
        if(h.getNext()==null){
            return;
        }
        //获取倒数第二个结点
        while(h.getNext().getNext() !=null){
            h= h.getNext();
        }
        SNode temp = h.getNext();
        h.setNext(null);
        temp = null;
        length--;
    }

    //遍历链表
    private void printAll(){
        SNode node = headNode.getNext();
        while (node!=null){
            System.out.print(node.getElement()+",");
            node = node.getNext();
        }
    }
  //main函数
    public static void main(String[] args) {
        LRUBasedLinkedList list = new LRUBasedLinkedList();
        Scanner sc = new Scanner(System.in);
        while (true) {
            list.add(sc.nextInt());
            list.printAll();
        }
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值