二叉树算法习题:
1.设计算法,求解先序遍历序列第k(1<=k<=n)个节点的值
int getKNodeVal(BiTree tr, int k)
2.对于树中每个元素为x的节点,删去以它为根的子树,释放相应的空间
BiTree DeleteValX(BiTree tr, char x)
3. p和q分别为指向二叉树中的任意两个节点的值,其中数值不会重复,找到离p和q最近的公共祖先节点
BiNode *FindAncestor(BiTree tr, char p, char q)
4.求非空二叉树b的宽度:具有节点数目最多的那一层的节点个数
int GetTreeWidth(BiTree tr)
5.假设一颗满二叉树,所有节点都不同,已知先序序列是pre,设计算法求解后序序列post
void GetPostLine(int pre[], int h1, int t1, int post[], int h2, int t2)
6.1.非递归,设计算法将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head,二叉树按照二叉链表方式存储,链接时,用叶节点的右指针域来存放单链表指针
BiTree TransToLinkList(BiTree tr)
7.第6题的递归算法:只有这样从下向上的计算,才能保证头指针是head,而且能正常访问子节点
BiNode *InOrder(BiTree tr)
函数调用:
BiTree_use.cpp
int A[9] = {'1', '2', '3', '4', '5', '6', '7', '8'};
int B[9] = {'4', '3', '2', '5', '1', '7', '6', '8'};
BiTree tr2 = BuildTreeBeforeAndIn(A, B, 0, 7, 0, 7);
int k = 5;
std::cout << "先序遍历序列中第" << k << "个值为:" << char(getKNodeVal(tr2, k)) << std::endl;
//char ch = '2';
//tr2 = DeleteValX(tr2, ch);
//VisitTreeAfter(tr2);
char ch1 = '5';
char ch2 = '4';
std::cout << char(ch1) << "和" << char(ch2) << "的公共节点是" << char(FindAncestor(tr2, ch1, ch2)->data) << std::endl;
std::cout << "树的最大宽度是:" << GetTreeWidth(tr2) << std::endl;
int C[7]={0,1,3,4,2,5,6};
int D[7]={0};
GetPostLine(C,0,6,D,0,6); //设计算法求解满二叉树的后序序列post
for(int i=0;i<7;i++){
std::cout<<D[i]<<" ";
}
std::cout << std::endl;
BiNode* link= InOrder(tr2);
BiNode*iter=link;
while(iter){
std::cout<<char(iter->data)<<" " ;
iter=iter->rchild;
}
BiTree.h
/***
* 二叉树各个值不同,先序和中序遍历序列分别存于数组A[1..n],B[1....n]中,
* 算法建立该二叉树链表
*/
BiTree BuildTreeBeforeAndIn(int A[], int B[], int h1, int t1, int h2, int t2)
{
BiNode *root = (BiNode *)malloc(sizeof(BiNode));
root->data = A[h1]; //找到根节点
//std::cout << root->data << " ";
int i;
for (i = h2; B[i] != A[h1]; i++)
;
int llen = i - h2; //以根为中间节点,划分左右
int rlen = t2 - i;
//std::cout << llen << " " << rlen << " " << std::endl;
if (llen != 0)
root->lchild = BuildTreeBeforeAndIn(A, B, h1 + 1, h1 + llen, h2, h2 + llen - 1);
else
root->lchild = NULL;
if (rlen != 0)
root->rchild = BuildTreeBeforeAndIn(A, B, h1 + llen + 1, t1, h2 + llen + 1, t2);
else
root->rchild = NULL;
return root;
}
/**
* 设计算法,求解先序遍历序列仲第k(1<=k<=n)个节点的值
*/
int getKNodeVal(BiTree tr, int k)
{
std::stack<BiNode *> s;
BiNode *p = tr;
int i = 0;
while (!s.empty() || p)
{
if (p)
{
i += 1;
if (i == k)
return p->data;
s.push(p);
p = p->lchild;
}
else
{
p = s.top();
s.pop();
p = p->rchild;
}
}
return -1;
}
/**
* 对于树中每个元素为x的节点,删去以它为根的子树,释放相应的空间
*/
BiTree DeleteValX(BiTree tr, char x)
{
if (tr->data == x)
return NULL;
std::stack<BiNode *> s; //后序遍历的时候,栈顶的元素是这个节点的根节点
BiNode *p = tr, *r = NULL;
while (p || !s.empty())
{
if (p)
{
s.push(p);
p = p->lchild;
}
else
{
p = s.top();
if (p->rchild && p->rchild != r) //有右子节点且右子节点没有被访问过
{
p = p->rchild;
s.push(p);
p = p->lchild;
}
else
{
p = s.top();
s.pop();
std::cout << "正在访问节点" << char(p->data) << std::endl;
if (p->data == x)
{
std::cout << "正在删除节点" << x << std::endl;
BiNode *tmp = s.top();
if (tmp)
{
if (tmp->rchild->data == p->data)
{
std::cout << "正在删除右边的节点" << tmp->rchild << std::endl;
tmp->rchild = NULL;
}
else if (tmp->lchild->data == p->data)
{
std::cout << "正在删除左边的节点" << tmp->lchild << std::endl;
tmp->lchild = NULL;
}
}
}
r = p;
p = NULL;
}
}
}
return tr;
}
/***
* p和q分别为指向二叉树中的任意两个节点的值,其中数值不会重复
* 找到离p和q最近的公共祖先节点
*/
BiNode *FindAncestor(BiTree tr, char p, char q)
{
BiNode *tmp = tr, *r = NULL;
std::stack<BiNode *> s;
bool findp = false;
bool findq = false;
while (!s.empty() || tmp)
{
if (tmp)
{
s.push(tmp);
tmp = tmp->lchild;
}
else
{
tmp = s.top();
if (tmp->rchild && tmp->rchild != r)
{
tmp = tmp->rchild;
s.push(tmp);
tmp = tmp->lchild;
}
else
{
tmp = s.top();
s.pop();
if (tmp->data == p)
{
findp = true;
}
if (tmp->data == q)
{
findq = true;
}
if (findp && findq)
return s.top();
r = tmp;
tmp = NULL;
}
}
}
return NULL;
}
/**
* 求非空二叉树b的宽度:具有节点数目最多的那一层的节点个数
*/
int GetTreeWidth(BiTree tr)
{
//思路:层次遍历
std::queue<BiNode *> q;
BiNode *p = tr, *mark = tr;
int width = 0;
int maxWidth = 0;
q.push(p);
while (!q.empty())
{
width += 1;
p = q.front();
q.pop();
if (p)
{
if (p->lchild)
q.push(p->lchild);
if (p->rchild)
q.push(p->rchild);
}
if (p->data == mark->data)
{
//std::cout << "当前层宽度是:" << width << std::endl;
maxWidth = std::max(width, maxWidth);
mark = q.back();
width = 0;
}
}
return maxWidth;
}
/**
* 假设一颗满二叉树,所有节点都不同,已知先序序列是pre,设计算法求解后序序列post
*/
void GetPostLine(int pre[], int h1, int t1, int post[], int h2, int t2)
{
//满二叉树,所以层上是满的
int half;
if (t1 >= h1)
{
post[t2] = pre[h1];
half = (t1 - h1) / 2;
GetPostLine(pre, h1 + 1, h1 + half, post, h2, h2 + half - 1);
GetPostLine(pre, h1 + 1 + half, t1, post, h2 + half, t2 - 1);
}
}
/**
* 1.非递归
* 设计算法将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head
* 二叉树按照二叉链表方式存储,链接时,用叶节点的右指针域来存放单链表指针
*/
BiTree TransToLinkList(BiTree tr)
{
//需要判断是否是叶节点
BiNode *head = (BiNode *)malloc(sizeof(BiNode));
head->data = tr->data;
BiNode *p = tr, *next = head;
std::stack<BiNode *> s;
while (p || !s.empty())
{
if (p)
{
if (!p->lchild && !p->rchild) //都为空,是叶子节点
{
std::cout << "找到了叶子节点: " << char(p->data) << std::endl;
next->rchild = p;
next = next->rchild;
}
s.push(p);
p = p->lchild;
}
else
{
p = s.top();
s.pop();
p = p->rchild;
}
}
next->rchild = NULL;
tr= head->rchild;
return tr;
}
/**
* 2.递归算法:
* 设计算法将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head
* 二叉树按照二叉链表方式存储,链接时,用叶节点的右指针域来存放单链表指针
*
* 只有这样从下向上的计算,才能保证头指针是head,而且能正常访问子节点
*/
BiNode *head, *pre = NULL;
BiNode *InOrder(BiTree tr)
{
if (tr)
{
InOrder(tr->lchild);
if (tr->lchild == NULL && tr->rchild == NULL)
{
if (pre == NULL)
{
head = tr;
pre = tr;
} //处理第一个叶节点
else
{
pre->rchild = tr;
pre = tr;
}
}
InOrder(tr->rchild);
pre->rchild = NULL; //设置链表尾部
}
return head;
}