zoukankan      html  css  js  c++  java
  • 算法之python创建链表实现cache

    算法之python创建链表实现cache

    本节内容

    1. 问题由来
    2. 解决思路
    3. 实现代码
    4. 总结

    1. 问题由来

    问题起因于朋友的一次面试题,面试公司直接给出两道题,要求四十八小时之内做出来,语言不限,做出来之后才能参加接下来的面试。
    于是,朋友拿到这套题给我们看看,本人看到这道题之后,感觉挺好玩的,刚好这几天正处在入职前的无聊时期,闲着也是闲着,于是花了两个小时,简单弄了弄。下面是原题目:

    • 对Cache进行程序模拟操作, Cache最多容纳100个Item,进行较特别的新增和淘汰的处理逻辑。
    • Item: Cache item为单向链表结构;每秒钟所有Item的age加1 ;
    • 新增:每秒钟在队列的随机位置新增一个Item ;
    • 淘汰:每秒钟只能淘汰一个item,淘汰条件是 要么item的age大于10;要么Cache已满又无{age>10}的item,则淘汰第一个item。
    • 程序需求:
    • Cache单向链表中已有50个Item, 写简单程序模拟新增和淘汰的过程,至少需模拟200个item的新增或淘汰。

    2. 解决思路

    由于python中不像C语言或者C++里面那样有结构体这个东西,所以。。。目前的解决办法就是使用类去实现类似于结构体这样的东西。(但是个人感觉用类去实现类似结构体的东西有点像是大炮打蚊子。。。占用资源会不会比结构体夸张很多?)

    下面是用类实现一个结构体,模拟链表中的item:

    class item:
        def __init__(self,data=None,next=None,age=0):
            self.data=data  # 节点数据
            self.next=next  # 节点的下一个地址
            self.age=age  # 节点的age
    

    上面是对这个问题的第一层抽象,也是最底层抽象(定义好数据结构)

    对链表的抽象

    但是光有这个抽象还不够,我们还得自己抽象一层链表的操作出来,对于链表的基本操作有:

    1. 统计链表长度
    2. 链表追加数据
    3. 链表插入数据
    4. 链表删除数据

    当然,这只是对链表的一个基本操作的抽象,可能还有一些抽象没有实现,但是基本可以完成这个题目中的功能。

    对cache的抽象

    上面抽象出来了一个链表的基本操作,但是这个cache还需要满足一定的逻辑:

    • 对Cache进行程序模拟操作, Cache最多容纳100个Item,进行较特别的新增和淘汰的处理逻辑。
    • Item: Cache item为单向链表结构;每秒钟所有Item的age加1 ;
    • 新增:每秒钟在队列的随机位置新增一个Item ;
    • 淘汰:每秒钟只能淘汰一个item,淘汰条件是 要么item的age大于10;要么Cache已满又无{age>10}的item,则淘汰第一个item。

    处理这些逻辑还需要抽抽象出一层cache来比较好实现。

    完成上面这三步抽象,剩下的就不难了。

    3. 实现代码

    # item节点抽象
    class item:
        def __init__(self,data=None,next=None,age=0):
            self.data=data  # 节点数据
            self.next=next  # 节点的下一个节点
            self.age=age  # 节点age
    
    
    # 注意,链表的0位置存储的是root节点,不作为实际存储信息,里面的data用来存储该链表长度
    class linked_list:
        def __init__(self):
            self.root=item(0)  # 初始化链表,创建链表头,这时候链表长度为0
    
        @property
        def len(self):
            # count=0
            # item=self.root
            # while item.next!=None:
            #     item=item.next
            #     count+=1
            # return count  # count是实际节点个数减一,从0开始
            return self.root.data  # 上面在链表头中记录了链表长度,就不需要这里每次计算统计链表长度了,直接读取数据,时间复杂度由O(N)降到了O(1)
    
        def append_item(self,data=None):  # 模拟python中的列表append数据,将数据插入到链表最后并将链表长度+1,时间复杂度O(1)
            append_item_node=item(data)  # 初始化插入节点
            node=self.root
            for i in range(self.len):  # 找到链表结尾,并把新节点插入到最后,然后将链表长度+1
                node=node.next
            else:
                node.next=append_item_node
                self.root.data += 1
                return append_item_node
    
        def insert_item(self,num,data=None):  # 模拟python中列表插入数据,在某个位置前面插入数据,时间复杂度o(1)
            insert_item_node=item(data)  # 初始化插入节点
            node = self.root
            if num >self.len:  # 插入位置超过长度,则直接插入到最后一个元素的前面
                num=self.len
            elif num<1:  # 插入位置太小,则直接返回False,插入失败
                return False
            for i in range(num-1):  #找到相应的位置,在该位置前面插入,并将链表长度+1
                node=node.next
            else:
                tmp=node.next
                node.next=insert_item_node
                insert_item_node.next=tmp
                self.root.data += 1
                return insert_item_node
    
        def remove_item(self,num):  # 模拟python中的列表删除数据,在某个位置删除数据之后,后面的数据自动往前补,时间复杂度O(1)
            node=self.root
            if num < 1 or num > self.len:  # 如果删除位置不在长度范围内,则返回False,插入失败
                return False
            for i in range(num-1):  # 找到要删除的节点前一个节点,先用中间变量接收要删除节点后一个节点,然后再将要删除的节点删掉,再将两段链表接起来,最后,链表长度-1
                node = node.next
            else:
                tmp = node.next.next
                del node.next
                node.next = tmp
                self.root.data -= 1
                return True
    
        def add_allitem_age(self):  # 对所有节点的age自加一(只是为了适应当前题目加的一个方法,通用链表中不需要该方法)
            node=self.root
            for i in range(self.len):
                node=node.next
                node.age+=1
    
        def __iter__(self):  # 将链表改成一个迭代器,这样在外部就可以使用for循环遍历链表
            self.current_node=self.root
            return self
    
        def __next__(self):  # 实现迭代器协议
            if self.current_node.next!=None:
                self.current_node=self.current_node.next
                return self.current_node
            raise StopIteration
    
        def __str__(self):  # 自定义打印改链表样式
            node =self.root.next
            result_str="linked_list:"+str(self.len)+": "+":".join((str(node.data),str(node.age)))
            for i in range(1,self.len):
                node=node.next
                result_str="->".join((result_str,":".join((str(node.data),str(node.age)))))
            return result_str
    
    class cache:
        def __init__(self,max_num=100):  # 初始化cache,生成一个链表,并设定好cache最大值
            self.data=linked_list()
            self.max_num=max_num
    
        @property
        def add_age(self):  # 每隔一秒钟需要调用该函数,对链表中所有节点age自加一
            self.data.add_allitem_age()
    
        def insert_item(self,num,data):
            if self.data.len<self.max_num:  # 小于最大值时才让插入
                return self.data.insert_item(num,data)
            return False
    
        def append_item(self,data):
            if self.data.len<self.max_num:  # 小于最大值时才让追加
                return self.data.append_item(data)
            return False
    
        def eliminate(self):
        # 消除某个节点,可能有满足条件的节点,就消除,没有就不消除
        # 条件:要么item的age大于10;要么Cache已满又无{age>10}的item,则淘汰第一个item
            num=0
            for i in self.data:  #循环链表,如果找到age大于10的节点,则删除该节点
                num+=1
                if i.age>10:
                    self.data.remove_item(num)
                    return True
            else:  # 否则,判断是否cache已满,若满了,则删除第一个节点,否则什么都不干
                if self.data.len==100:
                    self.data.remove_item(1)
                    return True
                else:
                    return False
    
    import random
    import time
    def simulate_cache():  # 模拟cache
        cache_obj=cache()  # 创建cache对象
        for i in range(50):  # 放入50个初始化数据到cache中
            cache_obj.append_item(i)
        print(cache_obj.data)  # 打印生成50个最初始的值
        for  i in range(200):  # 进行两百秒的cache动态添加删除动作
            num=random.randint(1,cache_obj.data.len)  # 生成随机数
            cache_obj.insert_item(num,num)  # 在链表随机位置插入刚生成的随机数创建的节点
            cache_obj.add_age  # 将链表中每一个item节点的age自加一
            cache_obj.eliminate()  # 调用消除节点方法,自行判断是否需要删除某个节点
            print(cache_obj.data)  # 打印这次处理后链表中的数据
            time.sleep(1)  # 暂停一秒
    
    simulate_cache()  # 调用模拟cache函数
    

    4. 总结

    第一次用python实现链表这样的数据结构,感觉很新奇,花了两个小时完成这道题,在这也是对自己的一个交代吧。

    PS:这也从侧面印证了一个结论,那就是学习开发,并没有哪门语言好坏之分,学习的是开发的思想,语言只是工具,思想会了,用不同的工具都能造出自己想要的东西。加油,共勉。

  • 相关阅读:
    cookie
    sql 语句
    页面宽高
    分页
    asp.net中如何防止用户重复点击提交按钮
    小试简单工厂模式之简单计算器
    用函数实现交换的疑问
    结构体变量输入输出的问题
    scanf函数输入float数需要注意的问题
    oracle学习手记(1)
  • 原文地址:https://www.cnblogs.com/huxianglin/p/6641297.html
Copyright © 2011-2022 走看看