剑指Offer:面试题27 二叉搜索树与双向链表
2014-09-08 20:01
375 查看
/* 二叉搜索树与双向链表: 输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中 节点指针的指向。比如,输入图中左边的二叉搜索树,则输出转换之后的排序双向链表。 10 6 14 4 812 16 转换为: 4->6->8->10->12->14->16 <- <- <- <- <- <- 分析: 通过中序,首先确定链表的基本轮廓;然后在原有基础上修改指针,修改的原则是依据中序的元素值去寻找在树中 的位置,然后修改指向 由于bst中存在两个指针,而双向链表中也存在两个指针,首先从结构上来说,是可能转换的。 调整原则:将bst中指向左孩子的指针改为指向链表中前一个节点,右孩子改为指向链表中的后一个节点 按照中序遍历的顺序,遍历到根节点时,左子树已经转换为一个排序的链表,且链表中最后一个结点是当前值 最大的结点,此时将左链表最后一个节点与根节点连接起来,接着遍历转换右子树,把根节点与右链表中最小 的结点链接起来。 疑问?不知道如何利用中序遍历与该题结合起来,遍历到中序的 输入: 输入可能包含多个测试样例。 对于每个测试案例,输入的第一行为一个数n(0<n<1000),代表测试样例的个数。 接下来的n行,每行为一个二叉搜索树的先序遍历序列,其中左右子树若为空则用0代替。 输出: 对应每个测试案例, 输出将二叉搜索树转换成排序的双向链表后,从链表头至链表尾的遍历结果。 样例输入: 1 2 1 0 0 3 0 0 样例输出: 1 2 3 给定的先序如何建立树,因为是二叉搜索树,因此凡是比根节点小的均是左子树,其他均是右子树。 难道要用递归建立树 未解决,不知道如何根据先序建立二叉搜索树。 有解决方法了: 去掉00的先序序列,通过从后向前遍历,每遇到两个连续的0就删除 可以把去掉00的先序序列拿过来得到中序序列。 然后根据:先序和中序,建立二叉树 */ /* 关键: 1 if(i != s2)//如果存在左子树,i = s2,说明第一个节点就是根节点,那么中序后面的全是右子树,没有左子树, //注意这里因该是i!=s2 2 while(pHeadList && pHeadList->_left)//如果头节点不空,且左孩子不空,即双向链表的前一个结点不空 3 if(pCurNode->_left)//左子树不空,递归调用左子树 { convertNode(pCurNode->_left,pLastNode); } pCurNode->_left = *pLastNode;//根节点指向双向链表最后一个节点 if(*pLastNode)//如果双向链表最后一个节点不空,指向根节点。(若为空,没必要指向) { (*pLastNode)->_right = pCurNode; } *pLastNode = pCurNode;//使根节点成为双向链表最后的末尾节点,为下面用根节点链接右链表的最小节点做准备 if(pCurNode->_right) { convertNode(pCurNode->_right,pLastNode); } */ #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; const int MAXSIZE = 1000; typedef struct Node { int _iVal; Node* _left; Node* _right; }Node; Node nodeArr[MAXSIZE]; int _iIndex; Node* createNode() { ++_iIndex; nodeArr[_iIndex]._left = nodeArr[_iIndex]._right = NULL; return &nodeArr[_iIndex]; } bool isValid(int* pArr,int iLen)//判断二叉搜索树的先序序列是否合法 { if(!pArr || iLen <= 0) { return false; } int iRoot = pArr[0]; int i; for(i = 1 ; i < iLen ; i++) { if(pArr[i] > iRoot)//找到左右分割的点 { break; } } for(int j = i ; j < iLen ; j++) { if(pArr[i] < iRoot) { return false; } } bool bLeft = true; if(i > 1)//i = 1表示全部大于根节点的值,只有右子树 { bLeft = isValid(pArr+1,i-1); } bool bRight = true; if(i < iLen)//i = iLen,说明全部小于根节点的值,只有左子树 { bRight = isValid(pArr+i,iLen - i); } return (bLeft && bRight); } Node* buildBST(int* pFront,int* pMid,int s1,int e1,int s2,int e2) { Node* root = createNode(); root->_iVal = pFront[s1]; int i; for(i = s2 ; i <= e2 ; i++)//在中序中寻找根节点所在位置 { if(root->_iVal == pMid[i]) { break; } } if(i != s2)//如果存在左子树,i = s2,说明第一个节点就是根节点,那么中序后面的全是右子树,没有左子树, //注意这里因该是i!=s2 { root->_left = buildBST(pFront,pMid,s1+1,s1 + i - s2,s2,i-1); } if(i != e2)//i = e2,说明只有左子树,没有右子树 { root->_right = buildBST(pFront,pMid,s1 + i - s2 + 1,e1,i+1,e2); } return root; } void convertNode(Node* pHead,Node** pLastNode) { if(!pHead) { return; } Node* pCurNode = pHead; if(pCurNode->_left)//左子树不空,递归调用左子树 { convertNode(pCurNode->_left,pLastNode); } pCurNode->_left = *pLastNode;//根节点指向双向链表最后一个节点 if(*pLastNode)//如果双向链表最后一个节点不空,指向根节点。(若为空,没必要指向) { (*pLastNode)->_right = pCurNode; } *pLastNode = pCurNode;//使根节点成为双向链表最后的末尾节点,为下面用根节点链接右链表的最小节点做准备 if(pCurNode->_right) { convertNode(pCurNode->_right,pLastNode); } } Node* convert(Node* pHead) { Node* pLastNode = NULL; convertNode(pHead,&pLastNode); Node* pHeadList = pLastNode; while(pHeadList && pHeadList->_left)//如果头节点不空,且左孩子不空,即双向链表的前一个结点不空 { pHeadList = pHeadList->_left; } return pHeadList; } int getFrontSeq(int* pArr,int n,int* pFront)//把所有的0去掉(如果0不作为键值的话,否则会有bug) { int iCnt = 0; for(int i = 0 ; i < n; i++) { if(pArr[i] != 0)//1 0 1 0。0 变成1 ,1变成2,然后结束,实际也只有2个元素 { pArr[iCnt] = pArr[i]; pFront[iCnt] = pArr[i]; iCnt++; } } return iCnt; } int* getMidSeq(int* pArr,int n) { sort(pArr,pArr+n);//排序 return pArr; } void printList(Node* pHead) { bool isFirst = true; while(pHead) { if(!isFirst) { printf(" %d",pHead->_iVal); } else { isFirst = false; printf("%d",pHead->_iVal); } pHead = pHead->_right; } printf("\n"); } void process() { int n; while(EOF != scanf("%d",&n)) { if(n <= 0 || n >= 1000) { continue; } while(n-- > 0) { int iArr[MAXSIZE]; memset(nodeArr,NULL,sizeof(nodeArr)); _iIndex = 0; int i = 0; //while(EOF != scanf("%d",&iArr[i])) while(cin >> iArr[i])//按ctrl+z结束输入 { i++; } int iFrontArr[MAXSIZE]; int iCnt = getFrontSeq(iArr,i,iFrontArr); int* pFront = iArr; getMidSeq(iArr,iCnt); int* pMid = iArr; Node* root = buildBST(iFrontArr,iArr,0,iCnt-1,0,iCnt-1);//注意,这里用iCnt-1,即最末位的下标,而不是数组的大小 Node* head = convert(root); printList(head); } } } int main(int argc,char* argv[]) { process(); getchar(); return 0; }
相关文章推荐
- 剑指offer面试题27:二叉搜索树和双向链表
- 剑指offer-面试题27.二叉搜索树与双向链表
- 剑指offer--面试题27:二叉搜索树与双向链表
- 剑指offer——面试题27:二叉搜索树与双向链表
- 《剑指offer》(面试题27):二叉搜索树与双向链表
- 《剑指Offer》学习笔记--面试题27:二叉搜索树与双向链表
- 剑指offer——面试题27:二叉搜索树与双向链表
- 剑指offer——面试题27:二叉搜索树与双向链表
- 剑指offer--面试题27:二叉搜索树与双向链表--Java实现
- 面试题27 二叉搜索树转换为双向链表
- 剑指offer面试题-二叉搜索树转换成一个排序的双向链表
- 剑指Offer面试题27(Java版):二叉搜索树与双向链表
- 【剑指Offer学习】【面试题27:二叉搜索树与双向链表】
- 《剑指offer》:[27]二叉搜索树与双向链表的转化过程
- 剑指Offer面试题27(Java版):二叉搜索树与双向链表
- 面试题27 二叉搜索树转换成双向链表
- 面试题27.二叉搜索树与双向链表
- 面试题27:二叉搜索树与双向链表
- 面试题27:二叉搜索树与双向链表
- 【剑指Offer学习】【面试题27:二叉搜索树与双向链表】