您的位置:首页 > 理论基础 > 数据结构算法

剑指offer--数据结构之二叉树(1、4、6、11、12、27、48、50、60)

2013-09-03 12:59 561 查看

offer1

输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。

二元查找树的中序遍历就是已经排序的序列,改成双向链表,可考虑,先把左子树改造成双向链表,保存好最后一个指针,然后将链表最后节点后驱指向跟节点,则根节点加入双向链表,然后在将右子树改造成双向链表。和中序遍历不同的是,需要一个指针保存双向链表的最后一个节点。

代码:

void ConvertNode(BSTNode* pNode, BSTNode* &pLastNodeList)
{
if (pNode)
{
ConvertNode(pNode->lchild, pLastNodeList);

pNode->lchild=pLastNodeList;
if (pLastNodeList!=NULL)
pLastNodeList->rchild=pNode;
pLastNodeList=pNode;

ConvertNode(pNode->rchild, pLastNodeList);
}
}

BSTNode* ConvertTreeToList(BSTNode* pNode)
{
BSTNode* pLastNodeList=NULL;
ConvertNode(pNode, pLastNodeList);

//找到链表的头
while (pNode->lchild!=NULL)
pNode = pNode->lchild;

return pNode;
}


offer4

题目:输入一个整数和一棵二元树。从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。打印出和与输入整数相等的所有路径。

可以从根节点开始,每访问一个节点就压入栈中,然后访问栈顶元素的左子树,再访问右子树,递归操作,当栈顶元素的左右子树为空时,检查栈中元素的和,符合要求则输出。

代码:

void Find(BTnode* T, Stack* S, int sum)
{
if (T)
{
push(S, T->data);
//栈中存在空闲的栈底,用来保存当前栈的和,每次push都会更新
//检查路径是否符合
if (sum==S->bottom->data && T->pLchild==NULL && T->pRchild==NULL)
{
Snode* p=S->top;
while (p!=S->bottom)
{
printf("%3d ",p->data);
p=p->pNext;
}
printf("\n");
}

Find(T->pLchild, S, sum);
Find(T->pRchild, S, sum);

pop(S);
//访问玩以该节点为根的二叉树后,要pop该根节点,然后访问下一个
}
}


offer6

输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。

二元查找树就是二叉排序树,类似于快速排序的操作,首先判断整个数组是否是二叉排序树(即存在一个位置,左边的值全部小于等于最末元素(根节点),右边的值全部大于等于最末元素),符合条件后,再分别判断左右部分是否符合条件,

代码:

bool Check(int* a, int low, int high)
{
if (!a || low<high)
return false;
//只有一个元素,肯定是排序树
if (low==high)
return true;

int i,j,k;
//找到一个位置,左边的全部小于根节点
for (i=low; a[i]<=a[high]&& i<=high; i++);

//检查该位置右边,是否全部大于根节点
for (j=i; j<high && a[j]>=a[high]; j++);
//符合条件,继续检查左右部分
if (j==high)
return Check(a,low,i-1)&&Check(a,i,high-1);
else
return false;
}


offer11

输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。用递归和循环两种方法完成树的镜像转换。

递归好理解:从根节点开始,交换左右孩子,然后将左孩子当作根节点递归,然后右孩子。

代码:

void Mirror_1(BSTNode* T)
{
if (T)
{
BSTNode* p=T->lchild;
T->lchild=T->rchild;
T->rchild=p;
Mirror_1(T->lchild);
Mirror_1(T->rchild);
}
}


循环则类似层序遍历,需要一个队列,从跟节点开始,出队,交换左右孩子,左右孩子入队,直到队列为空

代码:

void Mirror_2(BSTNode* T)
{
if (!T)
return;

BSTNode* pTemp=NULL;
Queue* pQueue=CreatQueue();
EnQueue(pQueue, T);

while (DeQueue(pQueue, pTemp))
{
if (pTemp)
{
BSTNode* p=pTemp->lchild;
pTemp->lchild=pTemp->rchild;
pTemp->rchild=p;

EnQueue(pQueue, pTemp->lchild);
EnQueue(pQueue, pTemp->rchild);
}
}
}


offer12

输入一颗二元树,从上往下按层打印树的每个结点,同一层中按照从左往右的顺序打印。

就是层序遍历,代码:

void (*pvisit)(BSTNode*);

void visit(BSTNode* T)
{
printf("%3d ",T->data);
}

void CengTraverseBST(BSTNode* T, void (*pvisit)(BSTNode*))
{
if (!T)
return;

BSTNode* pTemp=NULL;
Queue* pQueue=CreatQueue();
EnQueue(pQueue, T);

while (DeQueue(pQueue, pTemp))
{
if (pTemp)
{
visit(pTemp);
EnQueue(pQueue, pTemp->lchild);
EnQueue(pQueue, pTemp->rchild);
}
}
}
使用了下函数指针,可以怎加移植性。

offer27

输入一棵二元树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

用递归非常简单,代码:

int DeepBtree(BTnode *pB)
{
if (!pB)
return 0;
int lDeep=DeepBtree(pB->pLchild);
int rDeep=DeepBtree(pB->pRchild);
return lDeep>rDeep? 1+lDeep: 1+rDeep;
}


offer48

输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。

想找一个能够用遍历解决的思路,始终想不出来。原博客中是保存好两个节点的路径,然后从路径开始,找到第一个不同的节点的前驱,那么就是共同的父节点了。
http://zhedahht.blog.163.com/blog/static/25411174201081263815813/
以后写代码。

offer50

输入两棵二叉树A和B,判断树B是不是A的子结构。

可以先遍历树A,找到某个和B根节点相等的节点,然后继续遍历该节点的左右子树是否完全符合,是返回真,

否则就继续在A中寻找下一个和B根节点相等的节点。

以后写代码

//检查以 pTree1为根节点的树是否等于Tree2。
bool CheckTree2Nodes(BTnode* pTree1, BTnode* pTree2)
{
//两个都为空树,包含
if (!pTree1 && !pTree2)
return true;
//Tree1为空,Tree2不空,不包含
if (!pTree1)
return false;
//Tree1不空,Tree2空,说明Tree2已经检查到某个路径的末尾,包含
if (pTree1 && !pTree2)
return true;
//连个根节点相等,检查左右子树的节点是否符合
if (pTree1->data == pTree2->data)
return CheckTree2Nodes(pTree1->pLchild, pTree2->pLchild) && CheckTree2Nodes(pTree1->pRchild, pTree2->pRchild);
return false;
}

//检查以 pTree1为根节点的树是否包含Tree2。
bool Tree2InTree1(BTnode* pTree1, BTnode* pTree2)
{
if (!pTree1 && !pTree2)
return true;
if (!pTree1)
return false;
//前序遍历树,如果发现Tree1中某节点和pTree2根节点相等
//检查检查以 pTree1为根节点的树是否等于Tree2。
if (pTree1->data == pTree2->data)
{
if (CheckTree2Nodes(pTree1, pTree2))
return true;
}
//没有找到相等的结点,继续遍历
return Tree2InTree1(pTree1->pLchild, pTree2) || Tree2InTree1(pTree1->pRchild, pTree2);
}


offer60

输入一棵二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

类似后序遍历的操作,也类似求树深度的操作,先判断左右子树是否是平衡树,并且需要变量返回其深度信息,然后在判断左右子树深度差,差值小于等于1,那么就是平衡的,递归操作。

代码:

bool IsBalanced(BTnode* pBtree, int &deep)
{
if (!pBtree)
{
deep=0;
return true;
}

int left, right;
//递归判断左右子树深度
if (IsBalanced(pBtree->pLchild, left) && IsBalanced(pBtree->pRchild, right))
{
if (abs(left-right)<=1)
{
deep=1+(left>right? left: right);
return true;
}
}
return false;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: