算法之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. XSS Attacks - Exploiting XSS Filter

    XSS Attacks - Exploiting XSS Filter mramydnei · 2015/12/21 10:11 from:http://l0.cm/xxn/ 0x00 前言 这又是一 ...

  2. 【LeetCode】【矩阵旋转】Rotate Image

    描述 You are given an n x n 2D matrix representing an image. Rotate the image by 90 degrees (clockwise ...

  3. g高分屏DataGrid里面checkbox不显示的解决办法

  4. 【HackerRank】Service Lane

     Calvin is driving his favorite vehicle on the 101 freeway. He notices that the check engine light o ...

  5. 面向过程编程实例------grep-rl 'root 路径

    #应用:grep -rl 'root' /etc import os def deco(func): def wrapper(*args): g=func(*args) next(g) return ...

  6. Shell 语句

    一 test 测试: 测试命令 test [ ] [[ ]] (( ))打开man test 逐一介绍每个参数 浮点计算:echo 'scale=2;1/3'|bc -l  测试操作命令执行后会返回到 ...

  7. linux下安装jsp开发运行环境(centos7)

    1 开发环境包括 1)apache-tomcat 2)java-jdk 3)mysql 2 apache-tomcat安装(应该先装java再装tomcat) 1)到官网下载最新版本(不建议用yum安 ...

  8. 2018.7.12训练赛 -G

    第二道水题 前边说了很多话,但就最后两段有用. 就是给你一个序列,然后你判断一下这个序列是不是递增的,是就输出yes,否则输出no. 所以以后不管题目看起来多长.多复杂,都要读一遍. 代码就不贴了.

  9. problem-1003(恢复一下)

    问题: Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequenc ...

  10. HTML5 画布canvas

    SVG的<defs> <symbols> 元素用于预定义一个元素使其能够在SVG图像中重复使用 <svg xmlns="http://www.w3.org/20 ...