【Python】python实现Apriori算法和FP-growth算法(附源代码)

使用一种你熟悉的程序设计语言,实现(1)Apriori算法和(2)FP-growth算法。

目录

  • 1、Apriori算法
  • 2、F-Growth算法
  • 3、两种算法比较

1、Apriori算法

def item(dataset):  # 求第一次扫描数据库后的 候选集,(它没法加入循环)c1 = []  # 存放候选集元素for x in dataset:  # 就是求这个数据库中出现了几个元素,然后返回for y in x:if [y] not in c1:c1.append([y])c1.sort()# print(c1)return c1def get_frequent_item(dataset, c, min_support):cut_branch = {}  # 用来存放所有项集的支持度的字典for x in c:for y in dataset:if set(x).issubset(set(y)):  # 如果 x 不在 y中,就把对应元素后面加 1cut_branch[tuple(x)] = cut_branch.get(tuple(x),0) + 1  # cut_branch[y] = new_cand.get(y, 0)表示如果字典里面没有想要的关键词,就返回0# print(cut_branch)Fk = []  # 支持度大于最小支持度的项集,  即频繁项集sup_dataK = {}  # 用来存放所有 频繁 项集的支持度的字典for i in cut_branch:if cut_branch[i] >= min_support:  # Apriori定律1  小于支持度,则就将它舍去,它的超集必然不是频繁项集Fk.append(list(i))sup_dataK[i] = cut_branch[i]return Fk, sup_dataKdef get_candidate(Fk, K):  # 求第k次候选集ck = []  # 存放产生候选集for i in range(len(Fk)):for j in range(i + 1, len(Fk)):L1 = list(Fk[i])[:K - 2]L2 = list(Fk[j])[:K - 2]L1.sort()L2.sort()  # 先排序,在进行组合if L1 == L2:if K > 2:  # 第二次求候选集,不需要进行减枝,因为第一次候选集都是单元素,且已经减枝了,组合为双元素肯定不会出现不满足支持度的元素new = list(set(Fk[i]) ^ set(Fk[j]))  # 集合运算 对称差集 ^ (含义,集合的元素在t或s中,但不会同时出现在二者中)# new表示,这两个记录中,不同的元素集合# 为什么要用new? 比如 1,2     1,3  两个合并成 1,2,3   我们知道1,2 和 1,3 一定是频繁项集,但 2,3呢,我们要判断2,3是否为频繁项集# Apriori定律1 如果一个集合不是频繁项集,则它的所有超集都不是频繁项集else:new = set()for x in Fk:if set(new).issubset(set(x)) and list(set(Fk[i]) | set(Fk[j])) not in ck:  # 减枝 new是 x 的子集,并且 还没有加入 ck 中ck.append(list(set(Fk[i]) | set(Fk[j])))# print(ck)return ckdef Apriori(dataset, min_support=2):c1 = item(dataset)  # 返回一个二维列表,里面的每一个一维列表,都是第一次候选集的元素f1, sup_1 = get_frequent_item(dataset, c1, min_support)  # 求第一次候选集F = [f1]  # 将第一次候选集产生的频繁项集放入 F ,以后每次扫描产生的所有频繁项集都放入里面sup_data = sup_1  # 一个字典,里面存放所有产生的候选集,及其支持度K = 2  # 从第二个开始循环求解,先求候选集,在求频繁项集while (len(F[K - 2]) > 1):  # k-2是因为F是从0开始数的     #前一个的频繁项集个数在2个或2个以上,才继续循环,否则退出ck = get_candidate(F[K - 2], K)  # 求第k次候选集fk, sup_k = get_frequent_item(dataset, ck, min_support)  # 求第k次频繁项集F.append(fk)  # 把新产生的候选集假如Fsup_data.update(sup_k)  # 字典更新,加入新得出的数据K += 1return F, sup_data  # 返回所有频繁项集, 以及存放频繁项集支持度的字典if __name__ == '__main__':n = int(input("共有几组数据?"))testList = [[] for i in range(n)]for i in range(n):testList[i] = list(map(str, input().split(' ')))  # 装入数据 二维列表print(testList)F, sup_data = Apriori(testList, min_support=2)  # 最小支持度设置为2print("具有关联的商品是{}".format(F))  # 带变量的字符串输出,必须为字典符号表示print('------------------')print("对应的支持度为{}".format(sup_data))

在这里插入图片描述

2、F-Growth算法

import copyclass FpNode():def __init__(self, name='', childs={}, parent={}, nextCommonId={}, idCount=0):self.idName = name  # 名字self.childs = childs  # 所有孩子结点self.parent = parent  # 父节点self.nextCommonId = nextCommonId  # 下一个相同的 id名字 结点self.idCount = idCount  # id 计数def getName(self):  # 获取该节点名字return self.idNamedef getAllChildsName(self):  # 获取该节点所有孩子节点的名字ch = self.childskeys = list(ch.keys())names = []for i in keys:names.append(list(i))return namesdef printAllInfo(self):  # 打印该节点所有信息print(self.idName, self.idCount, list(self.childs.keys()), list(self.parent.keys()), self.nextCommonId.items())@classmethoddef checkFirstTree(cls, rootNode):  # 前序遍历整个树(这不是二叉树,没有中序遍历)if rootNode is None:return ''# parent1 = rootNode.parent.keys()      #要加一个 强转 ,否则它会变成 Nopetype 型,rootNode.printAllInfo()  # print(rootNode.idName, type(rootNode.parent))  报错 root <class 'NoneType'>if rootNode.childs is not None:keys = list(rootNode.childs.keys())for i in keys:cls.checkFirstTree(rootNode.childs[i])@classmethoddef checkBehindTree(cls, rootNode):  # 后序遍历整个树if rootNode is None:return ''if rootNode.childs is not None:keys = list(rootNode.childs.keys())for i in keys:cls.checkBehindTree(rootNode.childs[i])rootNode.printAllInfo()def scan1_getCand1(database):  # 第一次扫描统计出现的次数c1 = {}  # 候选集for i in database:for j in i:c1[j] = c1.get(j, 0) + 1  # 表示如果字典里面没有想要的关键词,就返回0# print(c1)return c1# 返回排好序的字典# 对数据进行排序,按支持度由大到小排列
def sortData(**d):  # 形参前添加两个 '*'——字典形式  形参前添加一个 '*'——元组形式sortKey = list(d.keys())  # 直接使用sorted(my_dict.keys())就能按key值对字典排序sortValue = list(d.values())length = len(sortKey)for i in range(length - 1):  # 按照支持度大小,由大到小排序的算法for j in (i, length - 1 - 1):  # 必须 -1 (1,len)虽然不包含 len本身 但是数组【len-1】时最后一个元素,必须减去这个元素if sortValue[i] < sortValue[j + 1]:sortValue[i], sortValue[j + 1] = sortValue[j + 1], sortValue[i]  # 如果它的支持度小与另一个,交换位置sortKey[i], sortKey[j + 1] = sortKey[j + 1], sortKey[i]new_c1 = {}  # 存放排完序的数据记录for i in range(length):new_c1[sortKey[i]] = sortValue[i]return new_c1  # 返回排好序的字典# 得到 database 的频繁项集
def getFreq(database, minSup=3, **c1):  # 返回频繁项集,和频繁项集的支持度c1 = scan1_getCand1(database)  # 第一次扫面数据库,求第一次候选集,返回的是字典new_c1 = sortData(**c1)  # 排序,大到小keys = list(new_c1.keys())for i in keys:if new_c1[i] < minSup:  # 若支持度小于最小支持度,则删除该商品del new_c1[i]f1 = []  # 第一次频繁项集new_keys = list(new_c1.keys())for i in new_keys:if [i] not in f1:f1.append([i])  # 每个元素自成一项# print(f1,new_c1)return f1, new_c1def createRootNode():  # 创建一个根节点rootNode = FpNode('root', {}, {}, {}, -1)  # name, childs, parent, nextCommonId, idCountreturn rootNodedef buildTree(database, rootNode, f1):  # 构建频繁模式树 FpTreefor i in database:  # 第二次扫描数据库present = rootNode  # 指向当前节点next = FpNode(name='', childs={}, parent={}, nextCommonId={}, idCount=0)  # 创建一个新节点,并初始化for j in f1:  # 按支持度从大到小的顺序进行构建节点if set(j).issubset(set(i)):  # j如果在i里面if (present.getName() == 'root') and j not in rootNode.getAllChildsName():next.idName = str(j[0])  # 对新创建的节点进行赋值next.idCount = next.idCount + 1next.nextCommonId = {str(j[0]): 0}next.parent.update({rootNode.idName: rootNode})temp = copy.copy(next)rootNode.childs.update({str(j[0]): temp})  # 往它插入父亲节点##print(temp.parent)present = temp  # present = next 这样直接赋值是 引用 ,一定要注意next = FpNode(name='', childs={}, parent={}, nextCommonId={}, idCount=0)  # 创建并初始化下一个新节点else:if j in present.getAllChildsName():  # 如果需要插入的节点已经存在temp2 = present.childs[str(j[0])]present = temp2present.idCount = present.idCount + 1  # count+1即可else:next.idName = str(j[0])  # 对新插入的节点赋值next.idCount = next.idCount + 1next.nextCommonId = {str(j[0]): 0}next.parent.update({present.idName: present})# temp3 = copy.copy(next)present.childs.update({str(j[0]): next})  # 往它插入父亲节点# temp3.childs = {}present = nextnext = FpNode(name='', childs={}, parent={}, nextCommonId={}, idCount=0)# present = next# next = FpNode()# print(rootNode.getAllChildsName())# print('前序遍历如下:')# FpNode.checkFirstTree(rootNode)# print('后序遍历如下:')# FpNode.checkBehindTree(rootNode)return None# 构建线索,填节点的nextCommonId这个属性
def buildIndex(rootNode, d1):  # 传 列表或字典时,列表前,加*, 字典前加 ** 表示传给函数的是一个地址,在函数内部改变这个参数,不会影响到函数外的变量if rootNode is None:return ''next = rootNode  # 指向下一个节点,当前赋值为根节点value = rootNode.idName# print(value)# print(d1[str(value)])             #d1[value] {KeyError}'a'???????????????   如果value是根节点root,就会出错,表中本来就没有root这个值# print(d1)if value != 'root':indexAds1 = {value: d1[value]}if d1[value] == 0:  # 线索构造   我已经把初始化了所有的 nextCommonId 为 {'': 0}# 所以后面只要 这个节点的 nextCommonId字典的值为0,就说明这个字典就是构建的链表链尾d1[value] = next# print(indexAds1)else:while indexAds1[value] != 0:indexAds1 = indexAds1[value].nextCommonId  # 以链表形式把最后一个 表尾元素找出来# print(indexAds1)indexAds1[value] = next  # 这个元素后面加入 当前所在树的这个节点的地址# print(next.nextCommonId)if rootNode.childs is not None:  # 根节点孩子不是null,则对它的每个孩子,依次递归进行线索构建keys = list(rootNode.childs.keys())for i in keys:buildIndex(rootNode.childs[i], d1)def createIndexTableHead(**indexTableHead):  # 创建一个表头,用来构建线索,表头的名字是相应节点的名字keys = list(indexTableHead.keys())# print(keys)for i in keys:indexTableHead[i] = 0return indexTableHeaddef getNewRecord(idK, **indexTableHead):  # 得到新的数据记录newData = []address = indexTableHead[idK]while address != 0:times = 0times = address.idCount  # 当前节点count数l = []  # 临时存放这个分支上的所有节点元素,单个单个存储 二维列表getOneNewR = []  # 和l一样,是l的倒叙,因为l本来是倒叙的,现在把它改成倒叙# print(list(address.parent.keys())[0])  #这样写才是 字符 c  而不是 'c'nextAdress = copy.copy(address)  # 一个指针,指向父亲节点,初始化为表头第一个的地址while list(nextAdress.parent.keys())[0] != 'root':  # 该节点发父亲节点不是根节点。则# print(address.parent)l.append(list(nextAdress.parent.keys()))  # 把它的父亲节点加入l中parentIdName = list(nextAdress.parent.keys())[0]  # 父亲节的名字nextAdress = nextAdress.parent[parentIdName]  # 指向该节点父亲节点if l != []:for j in l:getOneNewR.append(j[0])if getOneNewR != []:for k in range(times):  # 若最后的那个 idk 计数为多次,要把它多次添加到新产生的newData中newData.append(list(getOneNewR))# 把得到的记录加入新的数据集中address = address.nextCommonId[idK]  # 指向下一个表头元素的开始地址,进行循环return newData#    idK表示当前新产生的数据集是在去除这个字母后形成的,  fk是去除掉idk后,新的第一次频繁项集  dk是fk的支持度
def getAllConditionBase(newDatabase, idK, fk, minSup, **dk):  # 返回条件频繁项集 base, 和支持度if fk != []:  # 频繁项集非空newRootNode = createRootNode()  # 创建新的头节点buildTree(newDatabase, newRootNode, fk)# newIndexTableHead = {}  #创建新表头newIndexTableHead = createIndexTableHead(**dk)  # **dk 就是传了个值,给了它一个拷贝,修改函数里面的这个拷贝,不会影响到外面的这个变量的值buildIndex(newRootNode, newIndexTableHead)else:return [idK], {idK: 9999}  # 频繁项集是空的,则返回idk的名字,支持度设为最大值9999,这样会出现一些问题,最后已经解决了,在主函数代码中有表现出来if len(newRootNode.getAllChildsName()) < 2:  # 新的FpTree只有1条分支,(这里只认为根节点只有1个孩子,就说他只有一条分支)# 若是实际数据,就不能这样写了,应当在写一个函数,从根节点开始遍历,确保每个节点都只有1个孩子,才能认为只有1条分支base = [[]]  # 条件基node = newRootNodewhile node.getAllChildsName() != []:  # 当前节点有孩子节点childName = list(node.childs.keys())  # 一个列表,孩子节点的所有名字,其实就1个孩子,前面已经判断了是单节点base.append(list(childName[0]))  # 把孩子节点加入条件基# print(node.childs)# print(childName)node = node.childs[childName[0]]  # 指向下一个节点# print(base)itemSup = {node.idName: node.idCount}  # 这一条分支出现的次数,最后求频繁项集支持度需要用到# print(itemSup)return base, itemSup  # 返回条件基,还有这一条分支出现的次数,else:  # 分支不止1条,进行递归查找,重复最开始的操作base = [[]]for commonId in fk[-1::-1]:  # 倒叙进行newIdK = str(commonId[0])newDataK = getNewRecord(newIdK, **newIndexTableHead)  # 传入这个表头的一个拷贝fk2, dk2 = getFreq(newDataK, minSup)conditionBase, itemSup = getAllConditionBase(newDataK, newIdK, fk2, minSup, **dk2)  # 得到该条件基下的条件基,及各个分支出现次数# 递归进行base.append(conditionBase)return base, itemSup# FpGrowth算法本身(Frequent Pattern Growth—-频繁模式增长)
def FpGrowth(database, minSup=3):f1, d1 = getFreq(database, minSup)  # 求第一次频繁项集,并返回一个字典存放支持度,且按大到小排序,返回频繁项和存放频繁项支持度的字典rootNode = createRootNode()  # 创建根节点# print(f1,d1)        #[['a'], ['b'], ['c'], ['d']]      {'a': 4, 'b': 4, 'c': 4, 'd': 3}# 第一步建造树buildTree(database, rootNode, f1)# indexTableHead = {}     #创建线索的表头,一个链表indexTableHead = createIndexTableHead(**d1)  # **d1 就是传了个值,给了它一个拷贝,修改函数里面的这个拷贝,不会影响到外面的这个变量的值buildIndex(rootNode, indexTableHead)  # 创建线索,用这个表头# print('构建线索后,前序遍历如下:')# FpNode.checkFirstTree(rootNode)# print('构建线索后,后序遍历如下:')# FpNode.checkBehindTree(rootNode)freAll = []  # 所有频繁项集freAllDic = {}  # 所有频繁项集的支持度# 第二步    进行频繁项集的挖掘,从表头header的最后一项开始。for commonId in f1[-1::-1]:  # 倒叙 从支持度小的到支持度大的,进行挖掘idK = str(commonId[0])newDataK = getNewRecord(idK, **indexTableHead)  # 传入这个表头的一个拷贝, 函数返回挖掘出来的新记录fk, dk = getFreq(newDataK, minSup)  # 对新数据集求频繁项集# print(fk,dk)base, itemSup = getAllConditionBase(newDataK, idK, fk, minSup, **dk)  # 得到当前节点的条件频繁模式集,返回# 有可能会发生这样一种情况,条件基是 a ,然后fk,dk为空,结果这个函数又返回了 a,那么最后的结果中,就会出现 a,a  这种情况,处理方法请往下看# print(base,idK)for i in base:# print(i)t = list(i)t.append(idK)t = set(t)  # 为了防止出现 重复 的情况,因为我的getAllConditionBase(newDataK, idK, fk, minSup, **dk)方法的编写,可能会形成重复,如   a,at = list(t)freAll.append(t)itemSupValue = list(itemSup.values())[0]x = tuple(t)  # 列表不能做字典的关键字,因为他可变,,而元组可以# <class 'list'>: ['c', 'd']# print(t[0])     # t是列表,字典的关键字不能是可变的列表, 所以用 t[0] 来取出里面的值freAllDic[x] = min(itemSupValue, d1[idK])# print(freAll)# print(freAllDic)return freAll, freAllDicif __name__ == '__main__':n = int(input("共有几组数据?"))testList = [[] for i in range(n)]for i in range(n):testList[i] = list(map(str, input().split(' ')))  # 装入数据 二维列表print("原始数据:", testList)freAll, freAllDic = FpGrowth(testList, minSup=3)  # 设置最小支持度为3print("频繁项集", freAll)print("各个频繁项集的支持度依次为:")for i in freAllDic.keys():print(i, ":", freAllDic[i])

在这里插入图片描述

3、两种算法比较

在以下情况下,FP-growth算法Apriori算法好:
数据量大。因为Apriori算法需要生成大量的候选项集,并对每个候选项集进行频繁项集的计数,这会消耗大量的时间和内存,而FP-growth算法通过构建FP树,将数据集压缩成了一个紧凑的数据结构,大大减少了存储空间和计算时间的开销。
数据分布不均匀。因为Apriori算法在生成候选项集时,需要遍历数据集多次,对于数据分布不均匀的情况,频繁项集的计算会受到影响。而FP-growth算法通过构建FP树,将频繁项集的计算转化为对FP树的遍历,不受数据分布的影响。
最小支持度阈值较低。因为Apriori算法在生成候选项集时,需要对每个候选项集进行频繁项集的计数,当最小支持度阈值较低时,需要计算大量的候选项集,导致计算时间较长。而FP-growth算法通过构建FP树,只需要遍历一次数据集,计算频繁项集,所以FP-growth算法更快速。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/741776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深圳服务器托管-优质的BGP机房

服务器只需要设置一个IP地址&#xff0c;最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的&#xff0c;不会占用服务器的任何系统资源。服务器的上行路由与下行路由都能选择最优的路径&#xff0c;所以能真正实现高速的单IP高速访问。 BGP协议本身具有冗…

OpenCV实战--利用级联分类器检测眼睛、行人、车牌等等

1、前言 opencv 提供级联分类器除了识别人脸外,还可以检测其他的物体 级联分类器的介绍:OpenCV实战--人脸跟踪(级联分类器) 检测人脸,戴上眼镜的演示: 这里只演示几个,更多的级联分类器文件可以百度自行查看 2、眼睛跟踪 haarcascade_eye.xml 检测眼睛的级联分类器文…

C#、C++、Java、Python 选择哪个好?

作者&#xff1a;网博汇智 链接&#xff1a;https://www.zhihu.com/question/298323023/answer/2789627224 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 一个好的程序员不能把自己绑定在一种语言上&#xff0c;不…

解决Nginx 404反向代理问题的方法

问题背景 当你在使用Nginx进行反向代理时&#xff0c;有时候会遇到404错误&#xff0c;这是因为Nginx无法找到对应的资源。这个问题通常出现在配置反向代理的过程中&#xff0c;导致用户无法正常访问所需的资源&#xff0c;给网站的稳定性和用户体验带来负面影响。 解决方法 …

复杂网络——半局部中心法

一、概述 由于最近写论文需要使用复杂网络知识中的半局部中心法&#xff0c;但是截止目前来说&#xff0c;网上几乎搜索不到有关的MATLAB程序代码&#xff0c;只有一篇用Python编写的程序&#xff0c;我的电脑中没有python&#xff0c;所以我花费一些时间&#xff0c;利用matla…

海豚调度系列之:任务类型——SPARK节点

海豚调度系列之&#xff1a;任务类型——SPARK节点 一、SPARK节点二、创建任务三、任务参数四、任务样例1.spark submit2.spark sql 五、注意事项&#xff1a; 一、SPARK节点 Spark 任务类型用于执行 Spark 应用。对于 Spark 节点&#xff0c;worker 支持两个不同类型的 spark…

53、WEB攻防——通用漏洞CRLF注入URL重定向资源处理拒绝服务

文章目录 CRLF注入原理&检测&利用URL重定向web拒绝服务 CRLF注入原理&检测&利用 URL重定向 就是url中存在urlhttps://xxx&#xff0c;重定向的页面没有限制。主要用来做钓鱼。 web拒绝服务 例如&#xff0c;图片的长宽参数由前端传入&#xff0c;恶意的数据…

分布式调用与高并发处理(二)| Dubbo

文章目录 Dubbo概念_什么是分布式系统单机架构集群架构分布式架构单机、集群和分布式的区别 Dubbo概念_什么是RPCRPC两个作用&#xff1a;常见 RPC 技术和框架&#xff1a; Dubbo概念_简介Dubbo能做什么Dubbo支持的协议 Dubbo概念_核心组件注册中心Registry服务提供者Provider服…

别再写传统简历了!AI简历5个超实用的功能,助你求职一臂之力(强烈建议收藏)

你们在制作简历时,是不是基本只关注两件事:简历模板,还有基本信息的填写。 当你再次坐下来更新你的简历时,可能会发现自己不自觉地选择了那个“看起来最好看的模板”,填写基本信息,却没有深入思考如何使简历更具吸引力。这其实是一个普遍现象:许多求职者仍停留在传统简历…

瑞萨:推迟加薪并裁员 | 百能云芯

随着全球半导体市场进入缓慢复苏阶段&#xff0c;日本汽车和工业芯片巨头瑞萨电子近期宣布了一系列重要的经营决策。据外媒报道&#xff0c;瑞萨电子已决定推迟今年4月至10月的定期加薪&#xff0c;并在自2023年11月以来进行了有限规模的裁员&#xff0c;以应对市场的变化和压力…

LC3014 输入单词需要的最少按键次数Ⅰ与方法内容的易读性

题目 刷题做到力扣 3014&#xff0c;题目要求设计电话键盘上的按键映射&#xff0c;返回按出 word 单词的最小按键次数&#xff0c;1 ≤ word.length ≤ 26&#xff0c;且仅由小写英文字母组成&#xff0c;所有字母互不相同 我的题解 简单题&#xff0c;略加思索拿下&#x…

代码随想录算法训练营第36天—动态规划04 | ● 背包问题 ● 01背包 (二维数组解法和滚动数组解法) ● *416. 分割等和子集

背包问题 常见的背包问题类型&#xff08;大厂面试重点掌握01背包和完全背包即可&#xff09;题目描述&#xff1a;有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品能用*次&#xff0c;求解怎么装物品使得装入…

识别恶意IP地址的有效方法

在互联网的环境中&#xff0c;恶意IP地址可能会对网络安全造成严重威胁&#xff0c;例如发起网络攻击、传播恶意软件等。因此&#xff0c;识别恶意IP地址是保护网络安全的重要一环。IP数据云将探讨一些有效的方法来识别恶意IP地址。 IP地址查询&#xff1a;https://www.ipdata…

S5PV210_视频编解码项目_裸机开发:实现按键的外部中断处理

加粗样式本文所作内容&#xff1a; 基于S5PV210芯片实现按键的外部中断处理程序&#xff0c;搭建中断处理流程框架 S5PV210对于中断处理的操作流程 1 外部中断得到触发&#xff1a; 1&#xff09;外部中断在初始化阶段得到使能 2&#xff09;外界达到了外部中断的触发条件 …

汉诺塔问题代码写法的详细解析

汉诺塔游戏规则&#xff1a; 规则&#xff1a; 汉诺塔问题是一个经典的问题。汉诺塔&#xff08;Hanoi Tower&#xff09;&#xff0c;又称河内塔&#xff0c;源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着…

30天学会QT(进阶)--------------第二天(创建项目)

1、如何规范的创建一个项目 由于本人也是从其他的项目上学来的&#xff0c;所以也不算是业界规范&#xff0c;每个公司或者个人都有自己的方式去创建项目&#xff0c;项目的创建是本着简洁&#xff0c;明了&#xff0c;方便而言的&#xff0c;所以对于我来说&#xff0c;不繁琐…

案例--某站视频爬取

众所周知&#xff0c;某站的视频是&#xff1a; 由视频和音频分开的。 所以我们进行获取&#xff0c;需要分别获得它的音频和视频数据&#xff0c;然后进行音视频合并。 这么多年了&#xff0c;某站还是老样子&#xff0c;只要加个防盗链就能绕过。&#xff08;防止403&#xf…

fs模块 文件写入 之 追加写入

文件的同步、异步追加写入&#xff1a; 一、异步追加 &#xff08;1&#xff09;语法&#xff1a;fs.appendFile(path,data,[options],callback(data,err)) &#xff08;2&#xff09;操作 1》引入fs模块 const fsrequire(fs); 2》调用appendFile fs.appendFile(./我可以…

学python新手如何安装pycharm;python小白如何安装pycharm

首先找到官网&#xff1a; Download PyCharm: The Python IDE for data science and web development by JetBrains 打开后选择下载&#xff0c;下图标红部分 点击exe程序&#xff0c;点击下一步&#xff01; 选择安装路径&#xff0c;下一步 弹出界面全选 选择默认 然后直接…

Java基于微信小程序的校园生活互助小助手

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…