文章目录
- 第3章 树与二叉树
- 3.1 顺序结构存储的二叉树求结点i,j的最近公共祖先结点
- *3.2 后序遍历二叉树的非递归算法
- 3.3 二叉树自下而上,从右到左的层次遍历
- *3.4 非递归计算二叉链表结构存储的二叉树高度
- 3.5 判断二叉链表结构存储的二叉树是否为完全二叉树
- 3.6 二叉链表结构存储的二叉树中计算所有双分支结点个数
- 3.7 链式结构存储的二叉树,把树B中所有结点的左右子树进行交换
- *3.8 二叉链表结构存储的二叉树,求先序遍历序列中第k个结点的值
- *3.9 二叉链表结构存储的二叉树,对于每个元素值为x的结点,删除以它为根的子树,并释放相应空间
- *3.10 二叉树中查找值为x的结点,打印所有值为x的结点的祖先(值为x的结点至多一个)
- *3.11 二叉链表结构存储的二叉树,求宽度
- ***3.12 已知满二叉树先序序列为pre,设计一个算法求其后序序列post
- 3.12 判断两二叉树是否相似
第3章 树与二叉树
3.1 顺序结构存储的二叉树求结点i,j的最近公共祖先结点
/* 算法思想:若i>j,结点i所在的层次大于或等于j所在层次。结点i的父亲结点为i/2,若i/2 = j,则i/2就是所要找的结点,否则i = i/2,重复上述过程,j>i同理。 */
ElemType Common_Ancestor(SqTree T,int i,int j){
if(!T[i] && !T[j]){ //结点存在
while(i != j){ //不是共同结点
if(i > j) //沿i向上
i = i/2;
else //沿j向上
j = j/2;
}
return T[i];
}
}
*3.2 后序遍历二叉树的非递归算法
/* 算法思想:后序遍历的顺序是左右根,所以需要判断返回根节点时刚访问的是左子树还是右子树,所以设置指针r指向最近访问过的结点。 */
void PostOrder(BiTree){
BiTNode *p = T;
BiTNode *r = NULL; //辅助指针
Stack S;
InitStack(S);
while(p || !StackEmpty(S)){
if(p){
Push(S,p); //走到最左边,压栈
p = p->lchild;
}
else{ //左边为空或者已经处理
GetTop(S,p); //回到对应头结点
if(p->rchild && r != p->rchild){ //如果有右孩子结点且未被访问
p = p->rchild;
Push(S,p);
}
else{ //没有右孩子或已经处理过
Pop(S,p); //p出栈
visit(p); //访问p结点输出对应数据
r = p;
p = NULL;
}
}
}
}
3.3 二叉树自下而上,从右到左的层次遍历
/* 算法思想:原有的层次遍历出队的同时各结点依次入栈,所有结点入栈后依次出栈访问即可。 */
void ReverseLevel(BiTree T){
Queue Q;
Stack S;
InitQueue(Q);
InitStack(S);
if(T){
EnQueue(T);
while(!QueueEmpty(Q)){
DeQueue(Q,p);
Push(S,p); //出队,入栈
if(p->lchild)
EnQueue(Q,p->lchild);
if(p->rchild)
EnQueue(Q,p->rchild);
}
while(!StackEmpty(S)){
Pop(S,p);
visit(p);
}
}
}
*3.4 非递归计算二叉链表结构存储的二叉树高度
/* 算法思想:层次遍历,用level记录当前高度,last指向下一层第一个结点,每层次遍历出队与last比较,若相等高度level加一,更新last。 */
int Btdepth(BiTree T){
if(T == NULL)
return 0;
BiTree Q[Maxsize];
int front = -1;
int rear = -1;
int last = 0;
int level = 0;
Q[++rear] = T;
while(front != rear){ //队不为空
p = Q[++ front];
if(p->lchild)
Q[++rear] = p->lchild;
if(p->rchild)
Q[++rear] = p->rchild;
if(front == last){
level ++;
last = rear; //遍历完一层,更新last
}
}
return level;
}
3.5 判断二叉链表结构存储的二叉树是否为完全二叉树
/* 算法思想:完全二叉树性质:只有最后一排不满,而且一旦出现空,后面均为空。因此采用层次遍历,若遇到空结点,查看其后是否还含有空结点。 */
bool is_complete(BiTree T){
if(T == NULL)
return true;
InitQueue(Q);
EnQueue(Q,T);
while(!QueueEmpty(Q)){
DeQueue(Q,p);
if(p){ //结点非空,孩子入队
EnQueue(Q,p->lchild);
EnQueue(Q,p->rchild);
}
else{ //结点为空,查看后续是否有非空结点
while(!QueueEmpty(Q)){
DeQueue(Q,p);
if(p)
return false;
}
}
}
return true;
}
3.6 二叉链表结构存储的二叉树中计算所有双分支结点个数
/* 算法思想:用num记录双分支结点个数,进行层次遍历,同时有左右孩子时num++ 。*/
int double_child_node(BiTree T){
if(T == NULL)
return 0;
InitQueue(Q);
EnQUeue(Q,T);
BiTNode *p;
int num = 0;
while(!QueueEmpty(Q)){
DeQueue(Q,p);
if(p->lchild && p->rchild)
num++;
if(p->lchild)
EnQueue(Q,p->lchild);
if(p->rchild)
EnQueue(Q,p->rchild);
}
return num;
}
/* 递归 */
/* 算法思想:采用递归的方法,若b = NULL,f(b) = 0;若b为双分支结点,则f(b) = f(b->lchild) + f(b->rchild) + 1(加上自己),否则f(b) = f(b->lchild) + f(b->rchild)。 */
int DsonNodes(BiTree b){
if(!b)
return 0;
else if(b->lchild && b->rchild)
return DsonNodes(b->lchild) + DsonNodes(b->rchild) + 1;
else
return DsonNodes(b->lchild) + DsonNodes(b->rchild);
}
3.7 链式结构存储的二叉树,把树B中所有结点的左右子树进行交换
/* 算法思想:采用递归方法,先交换左孩子的左右左子树,再交换右孩子的左右子树,最后交换根结点的左右子树。(后序遍历) */
void swap(BiTree B){
if(B){
swap(B->lchild);
swap(B->rchild);
temp = B->lchild;
B->lchild = B->rchild;
B->rchild = temp;
}
}
*3.8 二叉链表结构存储的二叉树,求先序遍历序列中第k个结点的值
/* 算法思想:设置全局变量i记录已访问的结点,其初值是根结点序号1,当i == k时找到结点,输出值。 */
int i = 1;
ElemType PreNode(BiTree T,int k){
if(!T) //空结点返回 '#'
return '#'
if(i == k)
return T->data;
i++;
ch = PreNode(T->lchild,k);
if(ch != '#')
return ch;
ch = PreNode(T->rchild,k);
return ch;
}
*3.9 二叉链表结构存储的二叉树,对于每个元素值为x的结点,删除以它为根的子树,并释放相应空间
//删除树
void DeleteTree(BiTree T){
if(T){
DeleteTree(T->lchild);
DeleteTree(T->rchild);
free(T);
T = NULL;
}
}
/* 递归 */
void search_X_Tree(BiTree T,ElemType x){
if(T){
if(T->data == x)
DeteleTree(T);
if(!T){
search_X_Tree(T->lchild);
search_X_Tree(T->rchild);
}
}
}
/* 非递归 */
void search(BiTree T,ElemType x){
BiTree Q[];
if(T){
if(T->data == x){
Delete(T);
exit(0);
}
InQueue(Q);
EnQueue(Q,T);
while(!QueueEmpty(Q)){
DeQueue(Q,p);
if(p->lchild){
if(p->lchild->data == x)
DeleteTree(p->lchild);
else
EnQueue(Q,p->lchild);
}
if(p->rchild){
if(p->rchild->data == x)
DeleteTree(p->rchild);
else
EnQueue(Q,p->rchild);
}
}
}
}
*3.10 二叉树中查找值为x的结点,打印所有值为x的结点的祖先(值为x的结点至多一个)
/* 算法思想:采用非递归的后序遍历,最后访问根结点,当访问到值为x的结点时,栈中所有元素均为该元素的祖先。 */
typedef struct{
BiTree T;
int tag; //tag = 0表示访问的是左结点,tag = 1表示访问的是右结点。
}stack;
void Search(BiTree T,ElemType x){
stack s[];
int top = 0;
while(T || top > 0){
while(T && T->data != x){ //结点入栈
s[++top].T = T;
s[top].tag = 0;
T = T->lchild;
}
if(T->data == x){
printf("值为x的所有祖先结点的值为:\n");
for(int i = 1;i < top;i++)
printf("%d",s[i].t->data);
exit(1);
}
while(top != 0 && s[top].tag == 1)
top --; //退栈
if(top != 0){
s[top].tag = 1;
T = s[top].T->rchild;
}
}
}
*3.11 二叉链表结构存储的二叉树,求宽度
/* 算法思想:采用层次遍历。设置last为本行结尾,count记录本行宽度,max记录最大宽度。 */
int width(BiTree T){
if(!T)
return 0;
BiTree Q[];
int front = -1;
int rear = -1;
Q[++ rear] = T;
int last = 0; //本行结束
int count = 1; //每行宽度
int max = 1;
while(fear < rear){
p = Q[++ front];
if(p->lchild)
Q[++ rear] = p->lchild;
if(p->rchild)
Q[++ rear] = p->rchild;
if(front == last){ //当front达到本行末尾时,利用rear - front计算下一行宽度
count = rear - front;
max = max > count? max : count;
last = rear;
}
}
return max;
}
***3.12 已知满二叉树先序序列为pre,设计一个算法求其后序序列post
https://blog.csdn.net/u012133341/article/details/119547234
/* 算法思想:对于任意满二叉树,任意子结点的左右子树结点数相等,同时,先序遍历的第一个结点为后序遍历的最后一个结点,采用递归的方法。 */
void PreToPost(ElemType pre[],int l1,h1,ElemType post[],int l2,int h2) {
int half;
if(h1 >= l1){
post[h2] = pre[l1];
half = (h1 - l1) / 2;
PreToPost(pre,l1 + 1,l1 + half,post,l2,l2 + half - 1); //转换左子树
PreToPost(pre,l1 + half + 1,h1,post,l2 + half,h2 -1); //转换右子树
}
}
3.12 判断两二叉树是否相似
所谓T1和T2相似是指,T1和T2都为空或者都只有一个根结点,或T1的左子树和T2的右子树是相似的并且T1和T2的右子树是相似的。
/* 算法思想:采用递归的算法,若T1和T2都是空则相似;若一个为空另一个不空则不相似,否则,递归比较左右子树。 */
bool Similar(BiTree T1,BiTree T2) {
if(!T1 && !T2)
return true;
if(!T || !T)
return false;
else{
leftS = Similar(T1->lchild,T2->lchild);
rightS = Similar(T1->rchild,T2->rchild);
return leftS && rightS;
}
}