2021-05-09-链表(上):如何实现LRU缓存淘汰算法

  • 链表的特点

通过指针将一组零散的内存块串联在一起;内存块称为链表的结点;为了将所有的结点联系起来,每个链表的结点除了存储数据之外,还需要记录链上下一个结点的地址,这个记录下个结点地址的指针叫后继指针;第一个结点叫头结点,记录链表的基地址;最后一个结点叫尾结点,指向一个空地址null,代表链表的最后一个结点;

不像数组对内存要求高,数组要求内存必须是连续的,申请100M的,如果没有连续的100M内存空间就会申请失败;

  • 单链表

  • 循环链表

循环链表是一种特殊的单链表,尾结点指针指向头结点;

优点是链表尾到链表头比较方便,适合处理具有循环结构特点的数据;

约瑟夫问题;

  • 双向链表

单链表只有一个方向,结点只有一个后继指针指向后面的结点;

双向链表支持两个方向,每个结点不止一个后继结点next指向后面的结点,还有一个前驱节点prev指向前面的结点;

双向链表需要额外的两个空间来存储后继结点和前驱结点的地址;

双向链表在删除指定位置结点的时候,更加高效,因为双向链表的结点已经存储了前驱结点的指针,不需要像单链表那样需要遍历;

除了删除,一个有序链表,在查找时,双向链表的按值查询也比单链表更加高效;

Java的LinkedHashMap就用到了双向链表这个结构;

利用空间换时间;

  • 双向循环链表

双向链表+循环链表

  • 链表vs数组性能

数组:代码对内存的使用非常苛刻;

  • 如何实现lru缓存淘汰算法

维护一个有序单链表,越靠近链表尾部的结点是越早之前访问的;

当有一个新的数据被访问时,从链表头部开始遍历:

1、如果此数据已经被缓存到链表中,我们遍历等到这个数据对应的结点,并将其从原来的位置删除,插入到链表的头部;

2、如果数据没有被缓存到链表中:

2.1、如果链表数据已满,就需要删除链表尾部的结点,将心的数据插入到链表的尾部;

2.2、如果链表数据未满,则将此结点插入链表的尾部;

  • 如何判断一个字符串是回文字符串,如果这个字符串是链表存储的,时间空间复杂度如何

利用快慢指针的方法;

快指针每次前进两个单位,慢指针每次前进一个单位并修改其后继指针指向前一个结点;

当fast指针走完(空结点或者空结点的前一个结点),慢指针刚好走到中间结点;此时慢指针继续向前走,同时开启一个新指针向后走,判断链表结点前后是否相等;

public class ListNode{
   int val;
   ListNode next;
   ListNode(int x){
      val=x;
   }
}

class solution{
   public boolean isPalindrome(ListNode head){
      if(head == null || head.next==null){
        return true;
      }
      ListNode prev=null;
      ListNode fast=head;
      ListNode slow=head;
      
      while(fast!=null && fast.next!=null){
        fast=fast.next.next;
        ListNode slowNext=slow.next;
        slow.next=prev;
        prev=slow;
        slow=slowNext;
      }

      if(fast!=null){
      // 当链表结点个数为奇数,慢结点需要往前走一个结点
         slow=slow.next;
      }

      while(prev!=null){
         if(slow.val!=prev.val){
           return false;
         }
         slow=slow.next;
         prev=prev.next;

      }
   }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值