您的位置:首页 > 职场人生

剑指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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: