数据结构——树

引入(Intro)

树由根节点的值和一系列的子树构成,并且这些子树也是树。在构造一棵树时,用列表list表示这些子树,列表中的元素也是一颗颗树。

构造器(Constructor)

用来构造一棵树

def  tree(root_label, branches = []):
    """返回树的根节点值和一个列表元素为子树的列表
    root_label: 根节点值
    branches: 子树列表,初始为空
    """
    for branch in branches:
#           遍历子树,每个子树都要是树
        assert is_tree(branch), 'branches must be trees'
#     返回根节点+子树列表
    return [root_label] + list(branches)

选择器(Selector)

用来定义构造器中的参数

def label(tree):
    # 返回树的根节点,根节点索引为0
    return tree[0]

def branches(tree):
    #  返回子树,索引从1开始
    return tree[1:]

def is_tree(tree):
#     输入一颗树,判断是不是树, 即树需要是列表,并且长度大于1
    if type(tree) != list or len(tree) < 1:
        return False
    for branch in branches(tree):
#         检查子树是不是树
        if not is_tree(branch):
            return False
    return True

def is_leaf(tree):
#     判断一棵树是不是叶子节点, 如果没有子树,则是叶子节点
    return not branches(tree)

树的递归演示

斐波拉契树

def fib_tree(n):
	"""返回斐波拉契树的根节点值和一个列表元素为子树的列表
   		n: 根节点值
   		branches: 子树列表,初始为空
	"""
    if n == 0 or n == 1:
        return tree(n)
    else:
        left, right = fib_tree(n - 2), fib_tree(n - 1)
        # n号节点值为n-1号和n-2号之和
        fib_n = label(left) + label(right)
        return tree(fib_n, [left, right])

记录叶子节点个数

def count_leaves(tree):
#     是叶子节点就返回1
    if is_leaf(tree):
        return 1
    else:
#     在每个子树里寻找叶子节点
        branch_counts = [count_leaves(branch) for branch in branches(tree)]
#     把子树里的叶子节点加起来
        return sum(branch_counts)

分割树

def partition_tree(n, m):
#     父节点值为0,树只有这一个节点,返回True
    if n == 0:
        return tree(True)
    elif n < 0 or m == 0:
        return tree(False)
    else:
#         左节点值为n - m
        left = partition_tree(n - m, m)
#         右节点值为m - 1 分割的n
        right = partition_tree(n, m - 1)
        return tree(m, [left, right])

def print_parts(tree, partition = []):
#     如果是叶子节点
    if is_leaf(tree):
#         如果该节点值不为0
#        递归基本条件:在叶子节点前加 + 输出, 
        if label(tree):
            print'+'.join(partition))
    else:
        left, right = branches(tree)
        m = str(label(tree))
        print_parts(left, partition + [m])
        print_parts(right, partition)

二分树

def left_binarize(tree):
    if is_leaf(tree):
        return tree
    if len(tree) > 2:
        tree = [tree[1:],tree[0]]
    return (left_binarize(branch) for branch in tree)

left_binarize([1,2,3,4,5,6,7])

找出树节点最大值

def tree_max(t):
    """Return the maximum label in a tree.
    	通过遍历子树,将所有节点存放在一个列表
    """
    labels = [label(t)] + [label(b) for b in branches(t)]
    return max(labels)

树的高度

最深叶子节点的深度

def height(t):
    """Return the height of a tree.
    >>> t = tree(3, [tree(5, [tree(1)]), tree(2)])
    >>> height(t)
    2
    """
    #若是叶子节点,高度为0
    if is_leaf(t):
        return 0
    #若所有子树均为叶子节点,高度为1
    if all([is_leaf(b) for b in branches(t)]):
        return 1
    else:
    	#找出所有子树的深度,返回最大就是树的高度
        heights = [1 + height(b) for b in branches(t)]
        return max(heights)

变化整棵树

将树的每个节点值平方,输出一棵新的树

def square_tree(t):
    """Return a tree with the square of every element in t"""
    square = lambda x: x * x 
    label_s = square(label(t))
    if is_leaf(t):
        return tree(label_s)
    else:
        return tree(label_s, [square_tree(b) for b in branches(t)])

查找的路径

def find_path(tree,x):
	"""返回一个列表,该列表元素值依次为到查找元素x的路径
	   tree: 被遍历的树
	   x: 要查找的元素
	   >>> t = tree(2, [tree(7, [tree(3), tree(6, [tree(5), tree(11)])] ), tree(15)])
	   >>> find_path(t, 5)
	   [2, 7, 6, 5]
	   >>> find_path(t, 10) # returns None
	"""
	# base case 如果只有一个节点,返回这个节点值的列表
	if is_leaf(tree):
		return [label(tree)]
	# 遍历子树
	for b in branches(tree):
		path = find_path(b, x)
		if path:
			return [tree(label)] + path

输出深度为k的树

def prune(t, k):
    """returns a new tree that contains only the first k levels of the original tree"""
    # base case
    if k == 0:
    	return tree(label(t))
    return ([label(t)] + prune(b, k - 1) for b in branches(t)])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值