《剑指offer》刷题笔记(分解让复杂问题简单):二叉搜索树与双向链表
2017-11-20 11:46
483 查看
《剑指offer》刷题笔记(分解让复杂问题简单):二叉搜索树与双向链表
转载请注明作者和出处:http://blog.csdn.net/u011475210代码地址:https://github.com/WordZzzz/Note/tree/master/AtOffer
刷题平台:https://www.nowcoder.com/
题 库:剑指offer
编 者:WordZzzz
剑指offer刷题笔记分解让复杂问题简单二叉搜索树与双向链表
前言
题目描述
解题思路
C版代码实现
递归1
递归2
循环
Python版代码实现
递归
循环
前言
在计算机领域有一类算法叫分治法,即“分而治之”。采用的就是各个击破的思想,我们把分解后的小问题各个解决,然后把小问题的解决方案结合起来解决大问题。题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。解题思路
哇偶,中序遍历啊!中序遍历,递归和循环都可以撒~二叉搜索树是一种排序的数据结构,每个结点都有两个指向子结点的指针。在双向链表中,每个结点也有两个指针,他们分别指向前一个结点和后一个结点。在二叉搜索树中,左子结点的值总是小于父结点的值,右子结点的值总是大于父结点的值。因此我们在转换成排序双向链表时,原先指向左子结点的指针调整为链表中指向前一结点的指针,原先指向右子结点的指针调整为链表中指向后一个结点指针。
中序遍历在二叉搜索树中的特点是按照从小到大的顺序遍历二叉树的每一个结点。下图中,我们可以把树分成三个部分:值为10的结点、根结点为6的左子树、根结点为14的右子树。根绝排序链表的定义,值为10的结点将和它的左子树的最大一个结点链接起来,同时它还将和右子树最小的结点链接起来。
按照中序遍历的顺序,当我们遍历转换到根结点时,它的左子树已经转换成一个排序的链表了,并且处在链表中最后一个的结点是当前值最大的结点。我们把值为8的结点和根结点链接起来,10就成了最后一个借点,接着我们就去遍历转换右子树,并把根结点和右子树中最小的结点链接起来。
下面个分别用C/C++和Python来实现,其中递归1是书中的解法,递归2是更加容易理解的解法,原理都是一样的,只不过递归1中涉及到指针的指针,容易把自己搞蒙。
C++版代码实现
递归1
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: TreeNode* Convert(TreeNode* pRootOfTree) { TreeNode *pLastNodeInList = NULL; ConvertNode(pRootOfTree, &pLastNodeInList); //需要返回头结点,所以需要遍历到头结点(最左子叶) TreeNode *pHeadOfList = pLastNodeInList; while(pHeadOfList != NULL && pHeadOfList->left != NULL) pHeadOfList = pHeadOfList->left; return pHeadOfList; } void ConvertNode(TreeNode* pNode, TreeNode** pLastNodeInList){ if(pNode == NULL) return; TreeNode* pCurrent = pNode; //递归左子树 if(pCurrent->left != NULL) ConvertNode(pCurrent->left, pLastNodeInList); //处理指针 pCurrent->left = *pLastNodeInList; if(*pLastNodeInList != NULL) (*pLastNodeInList)->right = pCurrent; *pLastNodeInList = pCurrent; //递归右子树 if(pCurrent->right != NULL) ConvertNode(pCurrent->right, pLastNodeInList); } };
递归2
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: TreeNode* Convert(TreeNode* pRootOfTree) { if(pRootOfTree == NULL) return NULL; if(pRootOfTree->left == NULL && pRootOfTree->right == NULL) return pRootOfTree; //遍历左子树 TreeNode* pLeft = Convert(pRootOfTree->left); TreeNode* pCurrent = pLeft; //定位至左子树最右的一个结点 while(pCurrent != NULL && pCurrent->right != NULL) pCurrent = pCurrent->right; //如果左子树不为空,则将当前pRootOfTree加到左子树链表 if(pLeft != NULL){ pCurrent->right = pRootOfTree; pRootOfTree->left = pCurrent; } //遍历右子树 TreeNode* pRight = Convert(pRootOfTree->right); //如果右子树不为空,则将当前pRootOfTree加到右子树链表 if(pRight != NULL){ pRight->left = pRootOfTree; pRootOfTree->right= pRight; } return pLeft != NULL?pLeft:pRootOfTree; } };
循环
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: TreeNode* Convert(TreeNode* pRootOfTree) { stack<TreeNode*> s; TreeNode* pHeadOfList = NULL; TreeNode* pLastNodeInList = NULL; TreeNode* pCurrent = pRootOfTree; while(pCurrent != NULL || !s.empty()){ while(pCurrent != NULL){ s.push(pCurrent); pCurrent = pCurrent->left; } if(!s.empty()){ pCurrent = s.top(); s.pop(); if(pLastNodeInList != NULL){ pLastNodeInList->right = pCurrent; pCurrent->left = pLastNodeInList; } //如果为空,则说明是最左边子结点,未来的头结点 else pHeadOfList = pCurrent; pLastNodeInList = pCurrent; pCurrent = pCurrent->right; } } return pHeadOfList; } };
Python版代码实现
递归
# -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def Convert(self, pRootOfTree): # write code here if not pRootOfTree: return None if not pRootOfTree.left and not pRootOfTree.right: return pRootOfTree #遍历左子树 pLeft = self.Convert(pRootOfTree.left) pCurrent = pLeft #定位至左子树最右的一个结点 while pCurrent and pCurrent.right: pCurrent = pCurrent.right #如果左子树不为空,则将当前pRootOfTree加到左子树链表 if pLeft: pCurrent.right = pRootOfTree pRootOfTree.left = pCurrent #遍历右子树 pRight = self.Convert(pRootOfTree.right) #如果右子树不为空,则将当前pRootOfTree加到右子树链表 if pRight: pRight.left = pRootOfTree pRootOfTree.right = pRight return pLeft if pLeft else pRootOfTree
循环
# -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def Convert(self, pRootOfTree): # write code here s = [] pCurrent = pRootOfTree pHeadOfList = None pLastNodeInList = None while pCurrent or s: while pCurrent: s.append(pCurrent) pCurrent = pCurrent.left if s: pCurrent = s.pop() if pLastNodeInList: pLastNodeInList.right = pCurrent pCurrent.left = pLastNodeInList else: pHeadOfList = pCurrent pLastNodeInList = pCurrent pCurrent = pCurrent.right return pHeadOfList
系列教程持续发布中,欢迎订阅、关注、收藏、评论、点赞哦~~( ̄▽ ̄~)~
完的汪(∪。∪)。。。zzz
相关文章推荐
- (C++)剑指offer-26:二叉搜索树与双向链表(分解让复杂问题简单)
- 《剑指offer》刷题笔记(分解让复杂问题简单):复杂链表的复制
- 分解让复杂问题简单化-面试题27-二叉搜索树与双向链表
- 《剑指offer》刷题笔记(分解让复杂问题简单):字符串的排列
- 链表问题----复杂链表的复制+二叉搜索树与双向链表(Java)
- 动态规划(Dynamic programming,DP),通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。通常许多
- 剑指offer 算法 (分解让复杂问题简单)
- (C++)剑指offer-27:字符串的排列(分解让复杂问题简单)(没太懂)
- 动态规划(Dynamic programming,DP),通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。通常许多子问题非-
- 剑指offer 28题 【分解让复杂问题简单】字符串的排列
- 剑指offer:(27)分解让复杂问题简单化 :二叉搜索树与双链表
- 【剑指offer】4.4分解让复杂问题简单化——面试题27:二叉搜索树与双向链表
- 分解让复杂问题简单化:二叉搜索树与双向链表
- (C++)剑指offer-25:复杂链表的复制(分解让复杂问题简单)(再理解)
- 《剑指offer》-二叉搜索树与双向链表
- 如果是能简单解决的问题,就不用想得太复杂了
- 分布式消息队列RocketMQ&Kafka -- 消息的“顺序消费”-- 一个看似简单的复杂问题
- 剑指OFFER之二叉搜索树与双向链表(九度OJ1503)
- //栈//为什么我总把简单的问题搞那么复杂?//Ignatius Train Station------二X
- js中简单和复杂数据类型存储和传递问题