字典树、树的遍历、二叉查找树

本文详细介绍了数据结构中的字典树(前缀树),包括其概念和应用。接着讨论了树的遍历方法,如前序、中序和后续遍历。还探讨了如何计算树的高度和节点数量。最后,文章讲解了二叉查找树的特性,并阐述了如何在二叉查找树中查找第k小的元素。

字典树 前缀树

"""
一、题目
    实现一个字典树or前缀树,包含insert、search和startswith功能
"""


class Node():
    def __init__(self):
        self.childs = [None] * 26
        self.isLeaf = False


class Trie(object):
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.root = Node()

    def insert(self, word):
        """
        Inserts a word into the trie.
        :type word: str
        :rtype: void
        """
        self.inserthelper(word, self.root)

    def inserthelper(self, word, node):
        if node == Node:
            return
        if len(word) == 0:
            node.isLeaf = True
            return
        index = ord(word[0]) - ord('a')
        if node.childs[index] is None:
            node.childs[index] = Node()
        self.inserthelper(word[1:], node.childs[index])

    def search(self, word):
        """
        Returns if the word is in the trie.
        :type word: str
        :rtype: bool
        """
        return self.searchhepler(word, self.root)

    def searchhepler(self, word, node):
        if node is None:
            return False
        if len(word) == 0:
            return node.isLeaf
        index = ord(word[0]) - ord('a')
        return self.searchhepler(word[1:], node.childs[index])

    def startsWith(self, prefix):
        """
        Returns if there is any word in the trie that starts with the given prefix.
        :type prefix: str
        :rtype: bool
        """
        return self.startsWithhelper(prefix, self.root)

    def startsWithhelper(self, prefix, node):
        if node is None:
            return False
        if len(prefix) == 0:
            return True
        index = ord(prefix[0]) - ord('a')
        return self.startsWithhelper(prefix[1:], node.childs[index])


#if __name__ == '__main__':
#    trie = Trie()
#    trie.insert("apple")
#    print(trie.search("apple"))
#    print(trie.search("app"))
#    print(trie.startsWith("app"))
#    trie.insert("app")
#    print(trie.search("app"))

树的遍历

"""
一、题目
    按层次的遍历的方法打印一颗树
    例如有如下一棵树:
        5
       / \
      3   6
     / \   \
    2   4   7
    打印结果是
    5 3 6 2 4 7
二、思路
    层次遍历的步骤是:
    对于不为空的结点,先把该结点加入到队列中
    从队中拿出结点,如果该结点的左右结点不为空,就分别把左右结点加入到队列中
    重复以上操作直到队列为空
"""


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


def hierarchical_traversal(root):
    if root is None:
        return []
    # 用一个list和一个索引index模拟队列的先进先出
    queue = []
    index = 0
    result = []
    queue.append(root)
    while len(queue) > index:
        temp = queue[index]
        index += 1
        result.append(temp.val)
        if temp.left is not None:
            queue.append(temp.left)
        if temp.right is not None:
            queue.append(temp.right)
    return result
    
def in_order_traversal(root):  # 中序
    res = []
    stack = []
    if root is None:
        return res
    cur = root
    while len(stack) != 0 or cur is not None:
        while cur is not None:
            stack.append(cur)
            cur = cur.left
        node = stack.pop()
        res.append(node.val)
        cur = node.right
    return res
    
def pre_order_traversal(root):  # 前序
    result = []
    stack = []
    stack.append(root)
    while len(stack) != 0:
        node = stack.pop()
        if node is None:
            continue
        result.append(node.val)
        stack.append(node.right)
        stack.append(node.left)
    return result
    
def post_order_traversal(root):  # 后序
    """
    前序遍历为 root -> left -> right,后序遍历为 left -> right -> root,
    可以修改前序遍历成为 root -> right -> left,那么这个顺序就和后序遍历正好相反
    """
    result = []
    stack = []
    stack.append(root)
    while len(stack) != 0:
        node = stack.pop()
        if node is None:
            continue
        result.append(node.val)
        stack.append(node.left)
        stack.append(node.right)
    return result[::-1]
"""
          5
       /    \
      3      6
     / \    /
    2   4  7     
"""


def construct_tree():
    root = TreeNode(5)
    root.left = TreeNode(3)
    root.right = TreeNode(6)
    root.left.left = TreeNode(2)
    root.left.right = TreeNode(4)
    root.right.left = TreeNode(7)
    return root

if __name__ == '__main__':
#    from Tree.tree import construct_tree

    root = construct_tree()
    print(hierarchical_traversal(root))
    print(in_order_traversal(root))
    print(pre_order_traversal(root))
    print(post_order_traversal(root))
'''
print result
[5, 3, 6, 2, 4, 7]
[2, 3, 4, 5, 7, 6]
[5, 3, 2, 4, 6, 7]
[2, 4, 3, 7, 6, 5]
'''

计算树的高度和节点数

# 计算一颗完全二叉树的树高
def countHeight(node):
    height = 0
    while node:
        height += 1
        node = node.left
    return height


def count_complete_Num(height):
    """
    计算一颗满完全二叉树的节点个数
    :param height: 树高
    :return: 节点个数
    """
    count = 0
    for h in range(height):
        count += pow(2, h)
    return count


def tree_node_count(root):
    if root is None:
        return 0
    left_count = countHeight(root.left)
    right_count = countHeight(root.right)
    if left_count != right_count:  # 如果左右子树的树高不等,则右子树是一颗满完全二叉树
        return 1 + count_complete_Num(right_count) + tree_node_count(root.left)
    elif left_count == right_count:
        if left_count == 0:  # 树没有孩子节点
            return 1
        elif left_count == 1:  # 有左右孩子节点,都是叶节点
            return 3
        else:  # 如果左右子树的树高相等,则左子树是一颗满完全二叉树
            return 1 + count_complete_Num(left_count) + tree_node_count(root.right)
if __name__ == '__main__':
    root = construct_tree()   
    print(max_depth(root))
    print(tree_node_count(root))

二叉查找树

"""
0、定义
    二叉查找树,也称为二叉搜索树、有序二叉树或排序二叉树,
    是指一棵空树或者具有下列性质的二叉树: 
    若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 
    若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值; 
    任意节点的左、右子树也分别为二叉查找树; 没有键值相等的节点。
    
一、题目
    将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
    本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
二、思路
    递归大法
    利用二分查找的思路,二分建树。
    二分的中点是根节点(相对而言的,每个子树都有根节点),左边的序列建立左子树,右边的序列建立右子树
三、同
    LeetCode-108
"""

def to_BST(nums, start, end):
    if start > end:
        return None
    middle = (start + end) >> 1
    root = TreeNode(nums[middle])
    root.left = to_BST(nums, start, middle - 1)
    root.right = to_BST(nums, middle + 1, end)
    return root


def sortedArrayToBST(nums):
    return to_BST(nums, 0, len(nums) - 1)


"""
从有序链表构造平衡的二叉查找树
一、题目
    给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
    本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
二、思路
    递归大法
    利用二分查找的思路,二分建树。
    二分的中点是根节点(相对而言的,每个子树都有根节点),左边的序列建立左子树,右边的序列建立右子树
三、本题与“从有序数组中构建二叉查找树”的整体思路是一样的
    只是单链表无法直接获得中间节点,必须通过顺序遍历才能得到mid位置的节点。
    遍历的方法是用“快慢指针”: 快指针每走两步,慢指针只走1步,这样快指针走到重点时,慢指针在中间。
    *** “快慢指针”是单链表中的重要方法,很多问题都要用到这个技巧,才能实现最优解 ***
四、同
    LeetCode-109
"""


# Definition for singly-linked list.
class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None
        
def build_l(nums):
    head = ListNode(nums[0])
    cur = head
    for i in nums[1:]:
        cur.next = ListNode(i)
        cur = cur.next
    return head


def print_l(head, p_type="STR"):
    p = head
    result = []
    while p:
        if p_type in ["STR", "SINGLE"]:
            result.append(str(p.val))
        else:
            result.append(p.val)
        p = p.next
    if p_type == "STR":
        print(" ".join(result))
    elif p_type == "LIST":
        print(result)
    elif p_type == "SINGLE":
        print(" -> ".join(result))
    else:
        print("error dType!!!")

# 找到单链表中间节点mid的前驱
def pre_Mid(head):
    slow = head
    fast = head.next
    pre = head
    while fast is not None and fast.next is not None:
        pre = slow
        slow = slow.next
        fast = fast.next.next
    return pre


def sortedListToBST(head):
    if head is None:
        return None
    if head.next is None:
        return TreeNode(head.val)

    preMid = pre_Mid(head)
    mid = preMid.next
    preMid.next = None  # 断开链表

    t = TreeNode(mid.val)
    t.left = sortedListToBST(head)
    t.right = sortedListToBST(mid.next)
    return t
nums=[1,2,3,4,5,6,7]
head1 = build_l(nums)
print_l(head1, "SINGLE")
root=sortedArrayToBST(nums)
root=sortedListToBST(head1)

查找第k小的元素

"""
一、题目
    给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。
二、思路
    本题要充分利用二叉搜索树有序的性质。一个节点的左子树上的节点都比该节点小,右子树上的节点都比该节点大;
    因此我们可以求当前节点左子树的个数left_count:
        * 如果 left_count == k-1, 则该节点就是第k小的元素;
        * 如果 left_count < k-1, 则第K小的数在右子树中,而且在右子树中变成了第 k - left_count - 1 小的数了
        * 如果 left_count > k-1, 则第k小的数在左子树中,而且还是第k小的元素
三、同
    LeetCode-230
"""

# 采用递归的思路求一棵树的节点个数
def count(node):
    if node is None:
        return 0
    return count(node.left) + count(node.right) + 1


def kthSmallest(root, k):
    leftc = count(root.left)
    if leftc == k - 1:
        return root.val
    if leftc > k - 1:
        return kthSmallest(root.left, k)
    return kthSmallest(root.right, k - leftc - 1)


nums=[1,2,3,4,5,6,7]
root=sortedArrayToBST(nums)
print(kthSmallest(root, 4))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值