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

算法之python创建链表实现cache的更多相关文章

  1. LeetCode初级算法的Python实现--链表

    LeetCode初级算法的Python实现--链表 之前没有接触过Python编写的链表,所以这里记录一下思路.这里前面的代码是和leetcode中的一样,因为做题需要调用,所以下面会给出. 首先定义 ...

  2. python算法与数据结构-单链表(38)

    一.链表 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括 ...

  3. 常用查找数据结构及算法(Python实现)

    目录 一.基本概念 二.无序表查找 三.有序表查找 3.1 二分查找(Binary Search) 3.2 插值查找 3.3 斐波那契查找 四.线性索引查找 4.1 稠密索引 4.2 分块索引 4.3 ...

  4. 常用排序算法的python实现和性能分析

    常用排序算法的python实现和性能分析 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试 ...

  5. 七大查找算法(Python)

    查找算法 -- 简介 查找(Searching)就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素.    查找表(Search Table):由同一类型的数据元素构成的集合    ...

  6. 机器学习算法与Python实践之(四)支持向量机(SVM)实现

    机器学习算法与Python实践之(四)支持向量机(SVM)实现 机器学习算法与Python实践之(四)支持向量机(SVM)实现 zouxy09@qq.com http://blog.csdn.net/ ...

  7. JavaScript 版数据结构与算法(三)链表

    今天,我们要讲的是数据结构与算法中的链表. 链表简介 链表是什么?链表是一种动态的数据结构,这意味着我们可以任意增删元素,它会按需扩容.为何要使用链表?下面列举一些链表的用途: 因为数组的存储有缺陷: ...

  8. 机器学习算法与Python实践之(五)k均值聚类(k-means)

    机器学习算法与Python实践这个系列主要是参考<机器学习实战>这本书.因为自己想学习Python,然后也想对一些机器学习算法加深下了解,所以就想通过Python来实现几个比较常用的机器学 ...

  9. 狄克斯特拉算法(Python实现)

    概述 狄克斯特拉算法--用于在加权图中找到最短路径 ps: 广度优先搜索--用于解决非加权图的最短路径问题 存在负权边时--贝尔曼-福德算法 下面是来自维基百科的权威解释. 戴克斯特拉算法(英语:Di ...

随机推荐

  1. json教程系列(1)-使用json所要用到的jar包下载

    json是个非常重要的数据结构,在web开发中应用十分广泛.我觉得每个人都应该好好的去研究一下json的底层实现,基于这样的认识,金丝燕网推出了一个关于json的系列教程,分析一下json的相关内容, ...

  2. ios-如何搭建IPv6网络测试环境(转)

    工具/原料   mac一台 iPhone手机2台(一台用于测试,另一台提供网络) 方法/步骤     准备网络.通过数据线连接iPhone和Mac,并将iPhone手机连接的Wi-Fi关闭,使用自己的 ...

  3. 一句white-space:nowrap解决IE6,IE7下浮动元素不自动换行

    一句white-space:nowrap解决IE6,IE7下浮动元素不自动换行

  4. python 中文字符的处理

    刚开始学习python的时候,都是对这英文的翻译书学习的.没有解除到中文编码的相关问题,直到自己用python去做相关的项目的时候才发先中文编码问题真的非常头疼啊.这里分享一下本人所了解的一些经验. ...

  5. Sqoop将MySQL表结构同步到hive(text、orc)

    Sqoop将MySQL表结构同步到hive sqoop create-hive-table --connect jdbc:mysql://localhost:3306/sqooptest --user ...

  6. java应用线上CPU过高问题排查

    1.top 命令,查看占用CPU最高的PID.ps aux|grep PID 进一步确定tomcat进程出现问题.2.ps -mp pid -o THREAD,tid,time显示线程列表3.prin ...

  7. Effective java第一章引言

    菜鸟一枚,开始读第一本书<Effective Java>(第二版)~ 看引言就有好多名词不懂(>_<) 导出的API由所有可在定义该API的包之外访问的API元素组成.一个包的 ...

  8. android、ipone在文本框中输入文字的不同

    1.android机会输入时会在键盘上先显示,你确定后再填充如文本框 2.ipone机是你输入时就直接填充到文本框,当你选择输入信息时,就会先把文本框的内容清空,在填充选择的文字,这时就会有个问题,如 ...

  9. Python给数字前固定位数加零

    python中有一个zfill方法用来给字符串前面补0,非常有用 n = " s = n.zfill(5) " zfill()也可以给负数补0 n = "-123&quo ...

  10. How to use the ZooKeeper driver for ServiceGroup in OpenStack Nova

    ServiceGroup APIs Nova会从ServiceGroup API 中查询节点的存活信息. ServiceGroup API 工作流程是: 当一个compute worker (runn ...