Java 中从 BST 的先序遍历中显示叶节点

2024年9月10日 | 11 分钟阅读

给定一个输入数组。该输入数组是二叉搜索树 (BST) 的先序遍历。任务是检测并打印二叉搜索树的叶子节点。叶子节点是树中没有子节点的节点。

示例 1

输入

int preorderArr[] = {25, 20, 10, 5, 12, 22, 36, 30, 28, 40, 38, 48}

输出 {5, 12, 22, 28, 38, 48}

解释: 节点值 5、12、22、28、38 和 48 是叶子节点。

示例 2

输入

int preorderArr[] = {891, 326, 291, 531, 966}

输出 {291, 531, 966}

解释: 节点值 291、531 和 966 是叶子节点。

简单方法

简单或朴素的方法是进行一次额外的遍历。我们知道,如果我们从三者(中序、先序和后序)中获得任何两个遍历,我们就可以得到二叉树,然后从中可以轻松得到叶子节点。先序遍历已经给出。因此,我们的任务是找到后序遍历或中序遍历。我们知道,如果我们对二叉搜索树进行中序遍历,我们会按照排序的顺序得到节点的值(BST 的属性)。

因此,我们所要做的就是创建一个名为 inorderArr[] 的数组。将 preorderArr 的所有元素复制到其中并对 inorderArr[] 数组进行排序。现在,我们得到了两个遍历(一个是先序,另一个是中序)。我们所要做的就是从这两个遍历构建一个二叉搜索树,然后找到其中的叶子节点并显示它。以下程序使概念更加清晰。

文件名: DisplayLeafBST.java

输出

For a Binary Search Tree that has the preorder traversal as: 
25 20 10 5 12 22 36 30 28 40 38 48 

The leaf nodes are: 
5 12 22 28 38 48 

For a Binary Search Tree that has the preorder traversal as: 
891 326 291 531 966 

The leaf nodes are: 
291 531 966

复杂度分析: createBST() 方法需要 O(n2) 的时间来构建二叉搜索树。其他方法也需要时间来产生结果。然而,createBST() 方法消耗的时间最多。因此,程序的总体时间复杂度为 O(n2)。此外,程序使用一个辅助数组来存储叶子节点以及中序遍历。因此,空间复杂度为 O(n),其中 n 是 preorderArr[] 数组中的元素总数。

优化: 如果我们观察,会发现上面的程序中不需要 createBST() 方法。无需创建二叉搜索树,我们就可以轻松找到叶子节点。此外,在 inorderArr[] 中搜索元素不需要线性搜索。这是因为 inorderArr[] 是已排序的。因此,我们也可以进行二分搜索。它会将时间复杂度从 O(n) 降低到 O(log(n))。请看下面的程序。

文件名: DisplayLeafBST1.java

输出

For a Binary Search Tree that has the preorder traversal as: 
25 20 10 5 12 22 36 30 28 40 38 48 

The leaf nodes are: 
5 12 22 28 38 48 

For a Binary Search Tree that has the preorder traversal as: 
891 326 291 531 966 

The leaf nodes are: 
291 531 966

复杂度分析: leafNodesRecursion() 方法需要 O(n) 时间。在每次递归调用中,我们都会调用 binrySearch() 方法,该方法需要 O(log(n)) 时间。因此,程序的总体时间复杂度为 O(n x log(n)),其中 n 是 preorderArr[] 数组中的元素总数。程序的空间复杂度与前一个程序相同。

让我们进行更多优化以降低时间复杂度。

方法:使用栈

利用堆栈和二叉搜索树的属性,可以降低程序的时空复杂度。首先,我们需要使用两个指针 m 和 n 来遍历 preorderArr[]。最初,m = 0,n = 1。当 preorderArr[m] > preorderArr[n] 时,我们可以得出 preorderArr[n] 是 preorderArr[m] 的左子节点。我们知道先序遍历遵循根 -> 左 -> 右的模式。因此,元素 preorderArr[m] 被压入堆栈。

对于那些不实现 BST 规则的节点,需要从堆栈中移除元素,直到 preorderArr[m] 大于堆栈的顶部元素,并在不大于时中断循环,然后显示相应的 m 值。

文件名: DisplayLeafBST1.java

输出

For a Binary Search Tree that has the preorder traversal as: 
25 20 10 5 12 22 36 30 28 40 38 48 

The leaf nodes are: 
5 12 22 28 38 48


For a Binary Search Tree that has the preorder traversal as: 
891 326 291 531 966 

The leaf nodes are: 
291 531 966

复杂度分析: 节点最多被遍历两次。因此,程序的时空复杂度为 O(n)。程序使用堆栈来存储元素。因此,空间复杂度与前一个程序相同。