第六章
PE06
/**********
【题目】若两棵二叉树T1和T2皆为空,或者皆不空
且T1的左、右子树和T2的左、右子树分别相似,则
称二叉树T1和T2相似。试编写算法,判别给定两棵
二叉树是否相似。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
**********/
Status Similar(BiTree T1, BiTree T2)
/* 判断两棵二叉树是否相似的递归算法 */
{
if(T1==NULL&&T2==NULL)
return TRUE;
else if(T1==NULL||T2==NULL)
return FALSE;
if(Similar(T1->lchild,T2->lchild)&&Similar(T1->rchild,T2->rchild))
return TRUE;
else return FALSE;
}
PE17
/**********
【题目】编写递归算法,求对二叉树T先序遍历时
第k个访问的结点的值。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
**********/
TElemType PreOrder(BiTree T, int &rek){
TElemType re = '#';
if(T == NULL)
return '#';
if(rek == 1)
return T -> data;
rek--;
if(T -> lchild)
re = PreOrder(T -> lchild, rek);
if(T -> rchild && re == '#')
re = PreOrder(T -> rchild, rek);
return re;
}
TElemType PreOrderK(BiTree T, int k)
/* 求对二叉树T先序遍历时第k个访问的结点的值。*/
/* 若失败,则返回'#' */
{
return PreOrder(T , k);
}
/*
int countNodes(BiTree bt){
return bt?(1 + countNodes(bt->lchild)+countNodes(bt->rchild)):0;
}
TElemType PreOrderK(BiTree T, int k)
{
int count;
if(k <= 0 || !T) return '#';
if(k==1) return T->data;
count = countNodes(T->lchild);
return count >= --k ? PreOrderK(T->lchild,k) : PreOrderK(T->rchild,k-count);
}
*/
PE12
/**********
【题目】编写递归算法,计算二叉树T中叶子结点的数目。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
**********/
int Leaves(BiTree T)
/* 计算二叉树T中叶子结点的数目 */
{
if(T==NULL)
return 0;
if(T->lchild==NULL&&T->rchild==NULL)
return 1;
return Leaves(T->lchild)+Leaves(T->rchild);
}
PE21
/**********
【题目】试利用栈及其基本操作写出二叉树T的非递归
的先序遍历算法。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild,*rchild;
} BiTNode, *BiTree;
可用栈类型Stack的相关定义:
typedef BiTree SElemType; // 栈的元素类型
Status InitStack(Stack &S);
Status StackEmpty(Stack S);
Status Push(Stack &S, SElemType e);
Status Pop(Stack &S, SElemType &e);
Status GetTop(Stack S, SElemType &e);
**********/
void PreOrder(BiTree T, void (*visit)(TElemType))
/* 使用栈,非递归先序遍历二叉树T, */
/* 对每个结点的元素域data调用函数visit */
{
Stack S;
InitStack(S);
BiTree p=T;
while(p){
visit(p->data);
if(p->rchild)
Push(S,p->rchild);
if(p->lchild)
p=p->lchild;
else if(StackEmpty(S)!=TRUE)
Pop(S,p);
else p=NULL;
}
}
PE23
/**********
【题目】试利用栈及其基本操作写出二叉树T的非递归
的后序遍历算法(提示:为分辨后序遍历时两次进栈的
不同返回点,需在指针进栈时同时将一个标志进栈)。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild,*rchild;
} BiTNode, *BiTree;
可用栈类型Stack的相关定义:
typedef struct {
struct BiTNode *ptr; // 二叉树结点的指针类型
int tag; // 0…1
} SElemType; // 栈的元素类型
Status InitStack(Stack &S);
Status StackEmpty(Stack S);
Status Push(Stack &S, SElemType e);
Status Pop(Stack &S, SElemType &e);
Status GetTop(Stack S, SElemType &e);
**********/
void PostOrder(BiTree T, void (*visit)(TElemType))
/* 使用栈,非递归后序遍历二叉树T, */
/* 对每个结点的元素域data调用函数visit */
{
if(T == NULL) return;
Stack s; InitStack(s);
int fistIn=0,left=1,right=2;
SElemType now;
now.ptr=T;
now.tag=fistIn;
Push(s,now);
while(!StackEmpty(s)){
Pop(s,now);
if(now.tag==fistIn){ //如果当前是第一次进栈,先置为从左栈返回.
now.tag=left;
Push(s,now);
if(now.ptr->lchild){
now.ptr=now.ptr->lchild;
now.tag=fistIn;
Push(s,now);
}
}else if(now.tag==left){ //如果当前是从左栈返回的,先置为从右栈返回.
now.tag=right;
Push(s,now);
if(now.ptr->rchild){
now.ptr=now.ptr->rchild;
now.tag=fistIn;
Push(s,now);
}
}else{ //如果当前是从右栈返回的,则打印当前节点
visit(now.ptr->data);
}
}
}
PE27
/**********
【题目】二叉树采用三叉链表的存储结构,试编写
不借助栈的非递归中序遍历算法。
三叉链表类型定义:
typedef struct TriTNode {
TElemType data;
struct TriTNode *parent, *lchild, *rchild;
} TriTNode, *TriTree;
**********/
void InOrder(TriTree PT, void (*visit)(TElemType))
/* 不使用栈,非递归中序遍历二叉树PT, */
/* 对每个结点的元素域data调用函数visit */
{
TriTree p=PT;
while(p->lchild)
p=p->lchild; //找到最左子树
while(p){
visit(p->data);
if(p->rchild){ //p有右子树
p=p->rchild; //右子树的输出顺序是从根到叶
while(p->lchild) //如果右子树存在左子树
p=p->lchild; //找到右子树的最左子树并输出
}
else if(p->parent->lchild==p) //p是左子树
p=p->parent; //输出双亲节点
else{ //p是右子树并且没有右子树了,说明p的双亲节点已经输出了
p=p->parent; //判断一个右子树的双亲的双亲
while(p->parent&&p->parent->rchild==p) //p是右子树并且还有双亲时
p=p->parent; //右子树的双亲都已经被输出了
p=p->parent; //如果是左子树,输出双亲结点
} //如果是没有双亲在循环结束后函数结束
}
}
PE29
/**********
【题目】假设在三叉链表的结点中增设一个标志域
(mark取值0,1或2)以区分在遍历过程中到达该结点
时应继续向左或向右或访问该结点。试以此存储结
构编写不用栈辅助的二叉树非递归后序遍历算法。
带标志域的三叉链表类型定义:
typedef struct TriTNode {
TElemType data;
struct TriTNode *lchild, *rchild, *parent;
int mark; // 标志域
} TriTNode, *TriTree;
**********/
void PostOrder(TriTree T, void (*visit)(TElemType))
/* 不使用栈,非递归后序遍历二叉树T, */
/* 对每个结点的元素域data调用函数visit */
{
TriTree p;
p=T;
while(p){
while(p->mark==0){ //先从叶遍历左孩子
p->mark=1;
if(p->lchild)
p=p->lchild;
}
while(p->mark==1){ //再从叶遍历右孩子
p->mark=2;
if(p->rchild)
p=p->rchild;
}
if(p->mark==2){ //夫节点一定为mark==1
visit(p->data);
p=p->parent;
}
}
}
PE33
/**********
【题目】编写递归算法,将二叉树中所有结点的
左、右子树相互交换。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
**********/
void ExchangeSubTree(BiTree &T)
/* 将二叉树中所有结点的左、右子树相互交换 */
{
BiTree p;
if(T->lchild||T->rchild){
p=T->lchild;
T->lchild=T->rchild;
T->rchild=p;
}
if(T->lchild)
ExchangeSubTree(T->lchild);
if(T->rchild)
ExchangeSubTree(T->rchild);
}
PE37
/**********
【题目】编写递归算法:求二叉树中以元素值
为x的结点为根的子树的深度。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
**********/
int Depthx(BiTree T, TElemType x)
/* 求二叉树中以值为x的结点为根的子树深度 */
{
int depthLeft,depthRight;
if(!T)
return 0;
if(T->data==x){
depthLeft = Depthx(T->lchild,T->lchild->data);
depthRight = Depthx(T->rchild,T->rchild->data);
return 1+(depthLeft>depthRight?depthLeft:depthRight);
}
else{
depthLeft = Depthx(T->lchild,x);
depthRight = Depthx(T->rchild,x);
return depthLeft>depthRight?depthLeft:depthRight;
}
}
/**********
【题目】编写递归算法:对于二叉树中每一个元素值为x
的结点,删去以它为根的子树,并释放相应的空间。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
**********/
void ReleaseX(BiTree &T, char x)
/* 对于二叉树T中每一个元素值为x的结点, */
/* 删去以它为根的子树,并释放相应的空间 */
{
if(!T) return ;
if(T->data==x){
ReleaseX(T->lchild,T->lchild->data);
ReleaseX(T->rchild,T->rchild->data);
free(T);
}
else{
ReleaseX(T->lchild,x);
ReleaseX(T->rchild,x);
}
}
/**********
【题目】编写复制一棵二叉树的递归算法。
二叉链表类型定义:
typedef char TElemType; // 设二叉树的元素为char类型
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
**********/
void CopyBiTree(BiTree T, BiTree &TT)
/* 递归复制二叉树T得到TT */
{
if(!T){
TT=NULL;
return ;
}
TT=(BiTree)malloc(sizeof(BiTNode));
TT->data=T->data;
CopyBiTree(T->lchild,TT->lchild);
CopyBiTree(T->rchild,TT->rchild);
}
/**********
【题目】编写算法判别给定二叉树是否为完全二叉树。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;
可用队列类型Queue的相关定义:
typedef BiTree QElemType; // 设队列元素为二叉树的指针类型
Status InitQueue(Queue &Q);
Status EnQueue(Queue &Q, QElemType e);
Status DeQueue(Queue &Q, QElemType &e);
Status GetHead(Queue Q, QElemType &e);
Status QueueEmpty(Queue Q);
**********/
Status CompleteBiTree(BiTree T)
/* 判别二叉树T是否为完全二叉树 */
{
if(T==NULL)
return TRUE;
int F = 0;
BiTree p = T;
Queue Q;
InitQueue(Q);
EnQueue(Q,p);
while(DeQueue(Q,p)){
//将所有位置都入队,任一个位置为空后,后面再有就是非完全二叉树
if(p==NULL)
F=1;
else if(F)
return false;
else{
EnQueue(Q,p->lchild);
EnQueue(Q,p->rchild);
}
}
return true;
}
/**********
【题目】试编写一个二叉排序树的判定算法。
二叉排序树的类型BSTree定义如下:
typedef struct {
KeyType key;
… … // 其他数据域
} TElemType;
typedef struct BiTNode {
TElemType data;
struct BSTNode *lchild, *rchild;
}BSTNode, *BSTree;
**********/
/没有考虑左子树的右孩子比根节点大的情况/
Status IsBSTree(BSTree T)
/* 判别二叉树T是否为二叉排序树。*/
/* 若是,则返回TRUE,否则FALSE */
{
if(!T||(!T->lchild&&!T->rchild))
return TRUE;
if(T->lchild->data.key>=T->data.key)
return FALSE;
if(T->rchild->data.key<=T->data.key)
return FALSE;
if(IsBSTree(T->lchild))
return IsBSTree(T->rchild);
return FALSE;
}
/**********
【题目】编写递归算法,从大到小输出给定二叉排序树
中所有关键字不小于x的数据元素。
二叉排序树的类型BSTree定义如下:
typedef struct {
KeyType key;
… … // 其他数据域
} TElemType;
typedef struct BSTNode {
TElemType data;
struct BSTNode *lchild,*rchild;
}BSTNode, *BSTree;
**********/
void OrderOut(BSTree T, KeyType k, void(*visit)(TElemType))
/* 调用visit(T->data)输出 */
{
if(!T)
return ;
OrderOut(T->rchild,k,visit);
if(T->data.key>=k){
visit(T->data);
OrderOut(T->lchild,k,visit);
}
}
/**********
【题目】试写一非递归算法,在二叉查找树T中插入元素e。
二叉查找树的类型BSTree定义如下:
typedef struct {
KeyType key;
… … // 其他数据域
} TElemType;
typedef struct BSTNode {
TElemType data;
struct BSTNode *lchild,*rchild;
} BSTNode, *BSTree;
**********/
Status InsertBST_I(BSTree &T, TElemType k)
/* 在二叉查找树T中插入元素e的非递归算法 */
{
BSTree s,p = T;
s = (BSTree)malloc(sizeof(BSTNode));
if(!s) return OVERFLOW;
s->data = k; s->lchild = NULL; s->rchild = NULL;
while(T){
if(p->data.key==k.key)
return OVERFLOW;
if(p->data.key>k.key){
if(p->lchild)
p = p->lchild;
else
p->lchild = s;
}
if(p->data.key<k.key){
if(p->rchild)
p = p->rchild;
else
p->rchild = s;
}
}
}
/**********
【题目】试编写算法,求二叉树T中结点a和b的最近共同祖先。
二叉链表类型定义:
typedef struct BiTNode {
TElemType data;
struct BiTNode *lchild,*rchild;
} BiTNode, *BiTree;
可用栈类型Stack的相关定义:
typedef struct {
BiTNode *ptr; // 二叉树结点的指针类型
int tag; // 0…1
} SElemType; // 栈的元素类型
Status InitStack(Stack &S);
Status StackEmpty(Stack S);
int StackLength(SqStack S);
Status Push(Stack &S, SElemType e);
Status Pop(Stack &S, SElemType &e);
Status GetTop(Stack S, SElemType &e);
**********/
Status getPathStack(Stack &s,BiTree t,TElemType v)
{
if(t == NULL) return ERROR;
SElemType e;
e.ptr = t;
if (t->data == v) {
Push(s,e);
return OK;
}
if (OK == getPathStack(s,t->lchild,v)) {
Push(s,e);
return OK;
}
if (OK == getPathStack(s,t->rchild,v)) {
Push(s,e);
return OK;
}
Pop(s,e);
return ERROR;
}
BiTree CommAncestor(BiTree T, TElemType a, TElemType b)
/* 求二叉树T中结点a和b的最近共同祖先 */
{
if (T == NULL) return NULL;
Stack sa,sb;
InitStack(sa);
InitStack(sb);
if (ERROR == getPathStack(sa,T,a)) return NULL;
if (ERROR == getPathStack(sb,T,b)) return NULL;
SElemType E1,E2,e1,e2;
Pop(sa,E1);
Pop(sb,E2);
while (!StackEmpty(sa) && !StackEmpty(sb)) {
e1 = E1;
e2 = E2;
if (ERROR == Pop(sa,E1) || ERROR == Pop(sb,E2) || E1.ptr->data != E2.ptr->data || E1.ptr->data == a || E2.ptr->data == b)
return e1.ptr;
}
return NULL;
}
/**********
【题目】在二叉排序树的每个结点中增设一个lsize域,
其值为该结点的左子树中的结点数加1。试编写时间复杂
度为O(logn)的算法,求树中第k小的结点的位置。
二叉排序树的类型BSTree定义如下:
typedef char KeyType;
typedef struct BSTNode {
KeyType key;
struct BSTNode *lchild,*rchild;
int lsize; // 新增域,值为左子树的结点数+1
} BSTNode, *BSTree;
**********/
{
if(!T)
return NULL;
if(T->lsize==k)
return T;
else if(T->lsize > k)
return Ranking(T->lchild,k); //最小在左子树的最左孩子
else
return Ranking(T->rchild,k-T->lsize); //最大在右子树的最右孩子
//右子树比根结点和其左子树都要大,所以要减去
}
/**********
【题目】假设二叉排序树T的每个结点的平衡因子域bf当前
均为0。试编写算法,求二叉排序树T的深度,并为每个结点
的bf域赋予正确的平衡因子值。
平衡二叉排序树的类型BBSTree定义如下:
typedef char KeyType;
typedef struct BBSTNode {
KeyType key;
int bf; // 平衡因子
struct BBSTNode *lchild,*rchild;
} BBSTNode, *BBSTree;
**********/
int Depth_BF(BBSTree T)
/* 求二叉排序树T的深度,并为每个结点 */
/* 的bf域赋予正确的平衡因子值。 */
{
int lf,rf;
if(!T)
return 0;
lf = Depth_BF(T->lchild);
rf = Depth_BF(T->rchild);
T->bf = lf-rf;
return 1+(lf>rf?lf:rf);
}