📜  门| GATE CS 2021 |设置 2 |第 61 题(1)

📅  最后修改于: 2023-12-03 15:42:12.917000             🧑  作者: Mango

题目介绍

这是2021年GATE计算机科学和工程考试的第61道题目。该题目的主题是有关三叉搜索树的相关知识点,需要求解插入和删除操作后树的后序遍历结果。

知识点分析

三叉搜索树,也称为2-3查找树,是一种特殊的平衡查找树。在每个节点中可以存储1个或2个键。具有以下特点:

  • 每个节点有两个数据项和三个子节点
  • 左子树的所有项都小于节点的较小项
  • 中间子树的所有项都位于节点的两个项之间
  • 右子树的所有项都大于节点的较大项

该树被广泛用于计算机科学和工程领域的查找和排序操作。

题目描述

给定一个空的三叉搜索树,和N个要插入或删除的数据项。用以下方式执行操作:

  1. 如果当前节点中没有数据项,则将新数据项插入到当前节点。
  2. 如果当前节点中有两个数据项,则保留两个数据项,并将第三个数据项插入到该节点的某一个子节点中。如果子节点中也有两个数据项,则需要分裂该子节点,使每个子节点中最多只包含两个数据项。
  3. 从当前节点开始,在三个子节点中找到可以包含给定项的子节点,并递归进行操作,直到找到空的子节点或目标项。

给定要执行的操作序列,输出每个操作后的树的后序遍历结果。

解题思路

根据以上分析,该题目需考虑以下几个方面:

  1. 如何插入一个新数据项?
  2. 如何在当前节点有两个数据项的情况下插入第三个数据项?
  3. 如何在三个子节点中找到可以包含给定项的子节点,并递归进行操作?
  4. 如何删除一个指定的数据项?

针对以上问题,可以采用如下策略解决:

  • 对于插入操作,可以采用标准的二叉搜索树插入算法,根据比对决定进入哪个子节点。对于三叉节点数据存储,则在插入新数据项时,需要对该节点进行拆分或者整合处理。
  • 对于删除操作,可以根据要删除的数据项和当前节点中的数据项比对进行判定,删除相应的数据项,并分裂或者合并节点。
  • 对于查找操作,可以采用递归算法,判定当前节点是否是叶子节点,如果是,则直接返回该节点作为结果,如果不是,则根据要查找的数据项与当前节点中数据项的比较结果,决定递归进入哪一个子节点。

简单总结一下,对于该题目,需要对三叉搜索树的构建和维护有比较全面的了解。并且需要对二叉查找树、递归算法等常见数据结构算法有一定的掌握。

代码实现

为了方便说明,以下代码分别展示构建三叉查找树、插入数据项、删除数据项、查找数据项等过程的实现。

构建三叉查找树
class TSTNode:
    def __init__(self, keys=None, children=None):
        self.keys = [] if keys is None else keys
        self.children = [None, None, None] if children is None else children

class TernarySearchTree:
    def __init__(self):
        self.root = TSTNode()

    def insert(self, data):
        pass

    def delete(self, data):
        pass

    def search(self, data):
        pass
插入数据项
def insert_node(node, data):
    """
    插入一个新数据项
    """
    if not node.keys:
        node.keys.append(data)
    elif len(node.keys) == 1:
        if data < node.keys[0]:
            node.keys.insert(0, data)
        else:
            node.keys.append(data)
    elif len(node.keys) == 2:
        if data < node.keys[0]:
            insert_node(node.children[0], data)
        elif data > node.keys[1]:
            insert_node(node.children[2], data)
        else:
            insert_node(node.children[1], data)
        
def split_node(node):
    """
    拆分一个节点
    """
    left_node = TSTNode(keys=[node.keys[0]], children=[node.children[0], None, None])
    right_node = TSTNode(keys=[node.keys[2]], children=[None, None, node.children[2]])
    return TSTNode(keys=[node.keys[1]], children=[left_node, right_node, None])

def insert_data(tree, data):
    """
    在三叉树上插入新的数据项
    """
    if not tree:
        tree.root = TSTNode(keys=[data])
    else:
        insert_node(tree.root, data)
        if len(tree.root.keys) == 3:
            tree.root = split_node(tree.root)
删除数据项
def remove_data(node, data):
    '''
    删除单个数据项
    '''
    if not node:
        return None

    if data in node.keys:
        idx = node.keys.index(data)
        if not node.children[idx] and not node.children[idx + 1]:
            node.keys.pop(idx)
        else:
            left_node, right_node = node.children[idx], node.children[idx + 1]
            if (left_node and len(left_node.keys) == 2) or (right_node and len(right_node.keys) == 2):
                if left_node and len(left_node.keys) == 2:
                    node.keys[idx] = remove_max_key(left_node)
                else:
                    node.keys[idx] = remove_min_key(right_node)
            else:
                tmp = node.keys.pop(idx)
                node = merge_nodes(left_node, right_node)
                node.keys.insert(idx, tmp)

    elif data < node.keys[0]:
        node.children[0] = remove_data(node.children[0], data)
    elif len(node.keys) == 1 or data < node.keys[1]:
        node.children[1] = remove_data(node.children[1], data)
    elif data > node.keys[1]:
        node.children[2] = remove_data(node.children[2], data)

    return node

def remove_min_key(node):
    '''
    移除左子树的最小值
    '''
    cur_node = node
    while cur_node.children[0]:
        cur_node = cur_node.children[0]
    val = cur_node.keys.pop()
    merged_node = merge_nodes(cur_node.children[1], cur_node.children[2])
    return val if not merged_node else merged_node.keys.pop(0)

def remove_max_key(node):
    '''
    移除右子树的最大值
    '''
    cur_node = node
    while cur_node.children[2]:
        cur_node = cur_node.children[2]
    val = cur_node.keys.pop()
    merged_node = merge_nodes(cur_node.children[1], cur_node.children[0])
    return val if not merged_node else merged_node.keys.pop()

def merge_nodes(left_node, right_node):
    '''
    合并左右子节点
    '''
    if left_node:
        if right_node:
            middle_node = TSTNode(keys=[right_node.keys.pop(0)], children=[
                left_node.children.pop(2), right_node.children.pop(0)])
            return TSTNode(keys=left_node.keys + right_node.keys, children=left_node.children + [middle_node] + right_node.children)
        else:
            return left_node
    elif right_node:
        return right_node
    else:
        return None

def delete_data(tree, data):
    '''
    在三叉树上删除数据项
    '''
    if tree and data in tree.root.keys:
        if len(tree.root.keys) == 1:
            if tree.root.children[0]:
                tree.root = tree.root.children[0]
            elif tree.root.children[2]:
                tree.root = tree.root.children[2]
            else:
                tree.root = None
        else:
            tree.root = remove_data(tree.root, data)

查找数据项
def search_node(node, data):
    """
    查找匹配的节点
    """
    if not node:
        return None
    elif data == node.keys[0]:
        return node
    elif len(node.keys) == 1:
        if data < node.keys[0]:
            return search_node(node.children[0], data)
        else:
            return search_node(node.children[1], data)
    elif len(node.keys) == 2:
        if data < node.keys[0]:
            return search_node(node.children[0], data)
        elif data > node.keys[1]:
            return search_node(node.children[2], data)
        else:
            return search_node(node.children[1], data)

def search_data(tree, data):
    """
    在三叉树上查找指定数据项
    """
    node = search_node(tree.root, data)
    return node.keys[0] if node else None

以上便是三叉树操作的实现过程,如果能够对其细节实现和分析思路进行透彻理解,相信对做数据结构类面试或其他算法类比赛有很大的帮助。