二叉搜索树与双向链表的转换
1. 题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示
注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构4.你不用输出或者处理,示例中输出里面的英文,比如"From left to right are:"这样的,程序会根据你的返回值自动打印输出
2. 二叉搜索树定义
二叉搜索树(BST),有时也被称为二叉排序树,是一种特殊类型的容器: 在内存中存储“项目”(例如数字,名称等)的数据结构。它们允许快速查找、添加和删除项目,并且可以用于实现动态项目集,或者允许通过其关键字查找项目的查找表(例如,通过名称查找人员的电话号码)。
二叉排序树有序保存它们的关键字,以便查找和其他操作可以使用 二分的原则:当在树中寻找关键字(或插入新关键字的位置)时,他们从根到叶遍历树,与存储在树结点中的关键字进行比较,并根据比较结果决定继续在左或右子树中搜索。平均而言,这意味着每次比较都允许操作跳过树的大约一半结点,因此每次查找、插入或删除都需要存储在树中的项目数的对数级别的时间复杂度。这比在(未排序的)数组中按关键字查找项目需要的线性时间复杂的好多了 ,但比哈希表上的相应操作要慢。
二叉搜索树经过中序遍历后产生的结果为是有序。
3. 分析
根据上述二叉搜索树的介绍,我们知道 二叉搜索树经过中序遍历后产生的结果为是有序,所以我们将其转换为有序的双向链表只需借助中序遍历即可,只不过要将其结果转换为双向链表形式。
题目中所给节点有left和right属性,我们刚好可以将其看作链表节点的pre(前驱)和next(后继),因此我们在遍历时将节点的左右孩子指针指向其对应前驱和后继节点即可。
根据中序遍历性质 我们可以知道所形成的链表=左子树形成的链表 + 根节点 +右子树形成的链表
但是要将左子树形成的链表与中间节点相连,必须要知道左子树的尾结点,所以我们还要单独找到其尾结点
综上 链表=左子树头节点(如果不为空)+左子树形成的链表尾结点 + 根节点 +右子树形成的链表头节点(如果不为空)
4. 代码
public TreeNode Convert(TreeNode pRootOfTree)
{
//为了保证搜索二叉树的有序性,需要对齐进行中序遍历
//如果根节点为空,直接返回空
if (pRootOfTree == null)
{
return null;
}
//如果当前节点没有子树,返回当前节点
if (pRootOfTree.left == null && pRootOfTree.right == null)
{
return pRootOfTree;
}
//链表=左子树的链表 + 根节点 +右子树链表
//左子树链表尾结点+根节点+右子树头节点
//递归处理左子树,返回值为左子树得到链表的头节点
TreeNode left = Convert(pRootOfTree.left);
//找到左子树链表的尾结点
TreeNode leftTail = left;
while (leftTail != null && leftTail.right != null)
{
leftTail = leftTail.right;
}
//连接左子树与根节点
if (left != null)
{
leftTail.right = pRootOfTree;
pRootOfTree.left = leftTail;
}
//递归处理右子树,返回值为右子树得到链表的头节点
TreeNode right = Convert(pRootOfTree.right);
//连接右子树与根节点
if (right != null)
{
right.left = pRootOfTree;
pRootOfTree.right = right;
}
//最终返回新的链表的头节点
//如果left为空,链表的头节点就是pRootOfTree
//如果left不为空,链表的头节点就是left
return left == null ? pRootOfTree : left;
}
5. 实例分析
![二叉搜索树](https://i.loli.net/2021/07/24/qvkI1gTWDmEBYa8.png)
5. 实例分析
![二叉搜索树](https://i.loli.net/2021/07/24/qvkI1gTWDmEBYa8.png)