二叉搜索树转换成有序的双向循环链表(一)
来源:互联网 发布:小米查看支持什么网络 编辑:程序博客网 时间:2024/05/18 00:38
题目描述
给定一棵二叉排序树(BST),将该树转换成一棵双向循环链表。请看下面的图示说明,你可以更清楚的了解题意。
BST的结构定义如下:
struct node { int data; struct node* left; struct node* right;};typedef struct node Node;
图1)一棵存储1-5的二叉搜索树(BST)
图2)根据上面的BST转换得到的有序循环链表。其中,树的左右孩子指针替换成了pre和next指针,分别指向链表的前一个和后一个结点。
分析
看到这个题目,相信大多数人第一反应就是中序遍历这棵二叉树,同时改变树中结点的left和right指针。这里需要额外考虑的是如何将最后一个结点的right指针指向第一个结点,如下图所展示的那样。
图3)一个双向循环链表
以中序遍历遍历一棵二叉树的时候,每遍历到一个结点,我们就可以修改该结点的left指针指向前一个遍历到的结点,因为在后续操作中我们不会再用到left指针;与此同时,我们还需要修改前一个遍历结点的right指针,让前一个遍历结点的right指针指向当前结点。比如我们遍历到结点2,则我们修改结点2的left指针指向结点1,同时需要修改结点1的right指针指向结点2。需要注意一点,这里的前一个遍历结点不是当前结点的父结点,而是当前结点的前一个比它小的结点。
看似问题已经解决,慢着,我们其实落下了重要的两步。1)我们没有对头结点head赋值。 2)最后一个结点的right指针没有指向第一个结点。
解决这两个问题的方案非常简单:在每次递归调用的时候,更新当前遍历结点的right指针让其指向头结点head,同时更新头结点head的left指针让其指向当前遍历结点。当递归调用结束的时候,链表的头尾结点会指向正确的位置。不要忘记只有一个结点的特殊情况,它的left和right指针都是指向自己。
图4)只有一个结点的双向循环链表
这个解法非常的精巧,因为该算法是对中序遍历的一个改进,因此它的时间复杂度为O(N),N为结点数目。当然,相比中序遍历,我们在每次递归调用过程中增加了额外的赋值操作。
// 这是一个改进的中序遍历// prev (初始化为NULL) 用于跟踪前一个遍历结点// 当递归结束时,head指向链表的头部void treeToDoublyList(Node *p, Node *& prev, Node *& head) { if (!p) return; treeToDoublyList(p->left, prev, head); // 当前结点p的left指向前一个结点prev p->left = prev; if (prev) prev->right = p; //前一个结点的right指向当前结点 else head = p; //如果前面没有结点,则设置head为当前结点(当前结点为最小的结点)。 //递归结束后,head的left指针指向最后一个结点,最后一个结点的右指针指向head结点。注意保存p的right指针,因为在后面代码中会修改该指针。 Node *right = p->right; head->left = p; p->right = head; prev = p;//更新前一个结点 treeToDoublyList(right, prev, head); } //主函数,初始化prev和head为NULLNode* treeToDoublyList(Node *root) { Node *prev = NULL; Node *head = NULL; treeToDoublyList(root, prev, head); return head;}
代码解析
这个递归算法挺复杂的,还是从函数功能上来理解会容易懂一点。函数treeToDoublyList(Node *p, Node *&prev, Node *&head)的功能是将以p为根结点的树转换成有序的双向循环链表。函数执行前,prev总是指向遍历到p之前的前一个结点。函数执行完成后,prev指向p,head指向链表头结点。
以上面图中的二叉树为例,treeToDoublyList(Node *p, Node *&prev, Node *&head)过程如下:根结点为4,调用treeToDoublyList(p->left, prev, head)遍历完左子树后,左子树构成有序双向循环链表1=2=3,prev指向的是结点3,head指向当前双向循环链表的头结点1。更新p->left=prev,即4的left指针指向3,设置prev->right=p,即3的right指针指向4。同时更新head结点1的left为节点4,4的right指针更新为1,则此时双向循环链表变成1=2=3=4,接下来递归遍历右子树结点,保持双向循环链表的性质。
- 二叉搜索树转换成有序的双向循环链表(一)
- 二叉搜索树转换成有序双向链表
- 给出一颗二叉搜索树,将它转换为有序的双向链表输出
- 将搜索二叉树转换成有序的双向链表
- 360面试题——搜索二叉树转换成有序的双向链表
- 二叉搜索树转换为有序双向链表
- 二叉搜索树转换为有序双向链表
- 二叉搜索树转换为有序双向链表
- 二叉搜索树转换为有序双向链表
- 二叉搜索树转换为有序双向链表
- 如何将搜索二叉树转换成有序双向链表
- 面试题: 二叉搜索树转换成有序双向链表
- 将搜索二叉树转成有序的双向链表
- 输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表
- 微软面试100题---将 二叉搜索树 转化成 有序的双向链表
- 面试题27:二叉搜索树转换为有序双向链表
- 树(1)把二叉查找树转换成有序的双向链表
- 搜索二叉树转为有序双向链表
- 编写strcpy函数(10分
- 多线程
- 《如果让我重新读次研究生》——王泛森院士 [建议研究生看看]
- 从冯•诺依曼结构看计算机科学的发展史
- javase_21(DUp的学习-->*)
- 二叉搜索树转换成有序的双向循环链表(一)
- VB 中with的使用
- 找出字符串中对称的子字符串的最大长度(最长回文)
- maven中添加proguard来混淆代码
- ASP.NET图片上传
- 四对括号可以有多少种匹配排列方式?比如两对括号可以有两种:()()和(())
- android中设置AlertDialog的大小
- 你所不知道的SQL排序方法
- 网络流算法整理