递归树以及循环树算法

一般情况下,前端所要的数据是直接带children的树,而数据库给的字段均是parent自关联,博主提供了两种方式生成树。

  1. 使用create_tree_children方法,可递归查找指定父节点下的所有孩子节点,但是python限制默认递归次数为1000,当数据量特别大的时候,很容易出现问题
  2. 既然递归容易出现问题,那么可以用循环实现树的递归吗?答案是肯定的。
    2-1. 通过to_tree_dict生成key为主键的字典
    2-2. 通过from_list过滤出根节点,并在父节点下建立对应的孩子节点
    2-3. 插入节点insert_node之所以传入字典,是因为有的孩子节点是跨表插入,比如文件夹下插入文件,而文件保存在其它表中,则可以先通过to_tree_dict转字典,再insert_node到文件夹树下,之后调用文件夹树的from_list即可。
class BTree(object):
	def __init__(self,tree,primary_key='id',parent_key='parent',label='children'):
		self.tree = tree
		self.primary_key = primary_key
		self.parent_key = parent_key
		self.label=label
		
	def create_tree_children(self,parent_id=None):
		"""
		每个节点下生成对应的孩子节点
		:param parent_id: 可返回指定节点下的孩子节点
		:return:
		"""
		if not len(self.tree):
			return []
		for item in self.tree:
			if parent_id:
				if item.get(self.primary_key) == parent_id:
					children = self.search_children_by_pid(item.get(self.primary_key),[])
					item.update({
						self.label:children
					})
					break
			else:
				# 通过parent来组装当前节点的孩子节点
				children = self.search_children_by_pid(item.get(self.primary_key),[])
				item.update({
					self.label:children
				})
		if parent_id:
			# 仅返回该节点
			self.tree = list(filter(lambda x: x and x.get(self.label),self.tree))
		return self.tree
		
	def search_children_by_pid(self,pid,id_results:list):
		"""
			返回指定节点下的所有孩子节点
			:params pid:父节点id
			:params id_results: 记录节点id,防止重复遍历
			:return:
		"""
		if not len(self.tree):
			return []
		children = []
		for item in self.tree:
			# 如果当前节点未被遍历过
			if item.get(self.primary_key) not in id_results:
				if item.get(self.parent_key)==pid:
					id_resultd.append(item.get(self.primary_key))
					# 递归插入子节点
					new_item.update({
						self.label:self.search_children_by_pid(new_item.get(self.primary_key),id_results)
					})
					children.append(new_item)
		return children
		
	def from_list(self):
		def __tree_filter(node,info):
			if node.get(self.parent_key) and info.get(node.get(self.parent_key)):
				# 在父节点下添加孩子
				info[node.get(self.parent_key)].get(self.label).append(node)
			# 过滤掉孩子节点
			return not node.get(self.parent_key)
		info=self.to_tree_dict()
		self.tree=list(filter(lambda x:__tree_filter(x,info),self.tree))
		
	def to_tree_dict(self):
		def allocate_node(cur_node,new_node):
			cur_node[new_node.get(self.primary_key)]=new_node
			new_node[self.label]=[]
			return cur_node
		# key为主键,方便直接索引获取
		info = reduce(allocate_node,self.tree,{})
		return info
		
	def insert_node(self,nodes:dict):
		# 传入一个key为主键的字典,插入节点
		for value in nodes.values():
			self.tree.append(value)
			
	def get_tree(self):
		return self.tree

效果展示:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值