03-链表

链表的存储结构如图所示:

单链表:

循环链表:

 

 双向链表:

 

双向循环链表

单向链表添加数据动图:

单链表代码实现:

#单链表的实现
class ListNode:
    def __init__(self,data=None):
        self.data = data
        self.next = None

    def __repr__(self):
        """
        输出格式化信息
        :return:
        """
        return "node: {}".format(self.data)


class SingelLinkedList:
    def __init__(self, node=None):
        '''创建头节点_head指向第一个节点node'''
        self.__head = node

    def is_empty(self):
        '''判断是否空链表'''
        return self.__head is None

    def length(self):
        '''链表的长度'''
        current = self.__head  # 表示当前节点
        count = 0  # 用来统计已遍历的节点数目
        while current is not None:
            count += 1
            current = current.next  # 向后移动游标
        return count

    def ergodic(self):
        '''遍历整个链表'''
        current = self.__head  # 游标,用来表示当前节点
        while current is not None:
            yield current.data  # 生成当前节点的值
            current = current.next  # 向后移动游标

    def append(self, data):
        '''链表尾部添加节点'''
        node = ListNode(data)
        if self.is_empty():  # 如果是空链表
            self.__head = node
        else:
            current = self.__head
            while current.next is not None:
                current = current.next
            # 此时,current 表示尾节点,将它的 next 指向新增的节点即可
            current.next = node

    def head_add(self, data):
        '''在链表的头部添加节点'''
        node = ListNode(data)
        node.next = self.__head  # 将新增节点的 next 指向原来的头节点
        self.__head = node  # 再将链表的 __head 属性指向新增节点即可

    def insert(self, pos, data):
        '''在指定位置添加节点。 pos 表示节点的下标,为了跟列表等一样,这里规定 pos 从0开始计数,即头节点的 pos 为0'''
        if pos <= 0:  # 暂时不支持负数的下标。如果传入负数或者0,统一在头部插入
            self.head_add(data)
        elif pos > self.length() - 1:  # 如果传入的下标大于链表的长度减去1,默认使用在尾部插入
            self.append(data)
        else:
            pre = self.__head  # 用来表示 pos - 1 位置的节点
            count = 0
            while count < pos - 1:  # 当count = pos - 1时,表示已经找到了 pos - 1 的节点,退出循环
                count += 1
                pre = pre.next  # 向后移动游标
            # 退出循环后,pre 指向 pos - 1 所在的节点
            node = ListNode(data)
            node.next = pre.next  # 将新增节点的 next 指向 pre 的下一节点
            pre.next = node  # 再将 pre 的 next 重新指向新增的节点即可

    def search(self, data):
        '''查找元素'''
        current = self.__head
        while current is not None:
            if current.data == data:
                return True
            else:
                current = current.next
        return False

    def remove(self, data):
        '''链表中删除元素,跟列表中的 remove() 类似,也是删除第一个遇到的元素'''
        pre = None
        current = self.__head
        while current is not None:  # 遍历整个链表
            if current.data == data:  # 表示找到了要删除的节点
                #特殊1.要删除的节点是头节点时
                #特殊2.链表只有一个节点,刚好它就是要删除的节点,其实跟上面一样,也是头节点
                if current == self.__head:
                    self.__head = current.next
                else:  # 此时,current 指向要删除的节点,pre 指向要删除的节点的前一节点
                    pre.next = current.next  # 特殊情况3: 如果要删除的节点是尾节点时,也适合
                # 当找到要删除的节点时,需要退出 while 循环
                break
            else:
                pre = current  # 先让 pre 指向当前节点
                current = current.next  # 再让 current 向后移动

缓存是一种提高数据读取性能的技术,在硬件设计、软件开发中都有着非常广泛的应用,比如常见的 CPU(内存) 缓存、数据库缓存、浏览器缓存等等。

1、先进先出策略 FIFO(First In,First Out)

2、最少使用策略 LFU(Least Frequently Used)

3、最近最少使用策略 LRU(Least Recently Used)

LRU缓存代码实现:

class ListNode(object):
    def __init__(self, val, n=None):
        self.val = val
        self.next = n


class LRUCache:
    """
    一个 LRU 缓存
    维护了一个有序单链表,越靠近链表尾部的结点是越早之前访问的。
    """

    def __init__(self, capacity: int = 10):
        self.cap = capacity
        # 哨兵节点, 本身不存储任何数据
        self.head = ListNode(None, None)
        self.length = 0

    def __len__(self):
        return self.length

    def get(self, val: object) -> bool:
        '''获取指定缓存数据
        思路:从链表头开始顺序遍历链表:
        1. 如果此数据之前已经被缓存在链表中了,遍历得到这个数据对应的结点,并将其从原来的位置删除,然后再插入到链表的头部。
        2. 如果此数据没有在缓存链表中,则将新的数据结点插入链表的头部:
           - 如果此时缓存已满已超过容量,则将链表尾结点删除,
        参数:
            val:要获取的数据
        返回:
            存在于缓存中,返回True,否则返回 False。
        '''
        prev = None  # 用于记录尾节点的前一个节点
        p = self.head
        # 如果此数据之前已经被缓存在链表中了
        while p.next:
            if p.next.val == val:
                # 将目标节点从原来的位置删除
                dest = p.next  # dest临时保存目标节点
                p.next = dest.next
                # 将目标节点插入到头部
                self.insert_to_head(self.head, dest)
                return True
            prev = p
            p = p.next

        # 如果此数据没有缓存在链表中
        self.insert_to_head(self.head, ListNode(val))
        self.length += 1
        # 添加数据导致超过容量则要删除尾节点
        if self.length > self.cap:
            prev.next = None
        return False

    @staticmethod
    def insert_to_head(head, node):
        """将指定节点插入到头部"""
        node.next = head.next
        head.next = node

    def __str__(self):
        vals = []
        p = self.head.next
        while p:
            vals.append(str(p.val))
            p = p.next
        return '->'.join(vals)

 

posted @ 2020-05-05 19:53  一知.半解  阅读(32)  评论(0编辑  收藏