11.已知二叉树以二叉链表存储,编写算法完成:对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应空间
想法: 删除值x为根的子树,只要能删除左、右子树,就可以释放值为x的根结点,因此宜采用后序遍历。算法思想:删除值为x的根结点,将其父结点的左(右)子女指针置空,用层次遍历易于找到某结点的父结点。
void Delete(BiTree bt){
if(bt){
DeleteXTree(bt->lchild);
DeleteXTree(bt->rchild); //删除bt左子树、右子树
free(bt);
}
}
//在二叉树上擦护照所有以x为元素值的结点,并删除以其为根的子树
void Search(BiTree bt,Elemtype x){
BiTree Q[]; //Q是存放二叉树根结点指针的队列
if(bt){
if(b->data==x){ 若根结点值为x,则删除整棵树
DeleteXTree(bt);
exit(0);
}
Init Queue(Q);
EnQueue(Q,bt);
while(!IsEmpty(Q)){
DeQueue(Q,p);
if(p->lchild) //若左子女非空
if(p->child->data==x){ //左子树符合则删除左子树
DeleteXTree(p->lchild);
p->lchild=NULL;
} //父结点的左子女置空
else
EnQueue(Q,p->lchild); //左子树入队列
if(p->rchild)
if(p->rchild->data==x){ //右子树符合则删除左子树
DeleteXTree(p->rchild);
p->rchild=NULL;
}
else
EnQueue(Q,p->rchild); //右子女入队
}
}
}
12、在二叉树中查找值为x的结点,试编写算法打印值为x的结点的所有祖先,假设值为x的结点不多于1个
解:采用非递归后序遍历,最后访问到根结点,访问的值为x的结点时,栈中所有元素均为该结点的祖先,依次出栈即可。
typedef struct{
BiTree t;
int tag;
}stack; //tag=0表示左子女被访问,tag=1表示右子女被访问
void Search(BiTree bt,Elemtype x){
//在二叉树bt,查找值为x的结点,并打印其所有祖先
stack s[];
top=0;
while(bt!=NULL||>0){
while(bt!=NULL && bt->data!=x){ //结点入栈
s[++top].t=bt;
s[top].tag=0;
bt=bt->lchild; //沿左分支向下
}
if(bt->data==x){
printf("所查结点的所有祖先结点的值为:\n");
for(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;
bt=s[top].t->rchild; //沿分支向下遍历
}
}
}
13.设一棵二叉树的结点结构为(LLwINK,INFO,RLINK),ROOT为指向该二叉树根结点的指针,p和q分别为指向该二叉树中任意两个结点的指针,试编写算法ANCESTOR(ROOT,p,q,r),找到p和q的最近公共祖先结点r
算法思想:采用后序非递归算法,栈中存放二叉树结点的指针,当访问到某结点时,栈中所有元素均为该结点的祖先。
后序遍历必然先遍历到结点p,栈中元素均为p的祖先。
先将栈赋值到另一个辅助栈中。继续遍历到结点q时,将栈中元素从栈顶开始逐个到辅助栈中取匹配,第一个匹配的元素就是结点p和q的最近公共祖先
typedef struct{
BiTree t;
int tag; //tag=0表示左子女已被访问,tag=1表示右子女已被访问
}stack;
stack s[],s1[];
BiTree Ancestor(BiTree ROOT,BiTnode *p,BiTNode *q){
//求最近公共结点
top=0;bt=ROOT;
while(bt!=NULL || top>0){
while(bt!=NULL){
s[++top].t=bt;
s[top].tag=0;
bt=bt->lchild;
}
while(top!=0 && s[top].tag==1){
//假定p在q的左侧,遇到p时,栈中元素均为p的祖先
if(s[top].t==p)
for(i=1;i<top;i++)
s1[i]=s[i];
top1=top;
}
if(s[top].t==q)
for(i=0;i>0;i--){ //将栈中元素的树结点到s1中去匹配
for(j=top1;j>0;j--)
if(s[j].==s[i].t)
return s[i].t; //p和q的最近公共祖先已找到
}
top--; //退栈
}
if(top!=0){
s[top].tag=1;
bt=s[top].t->rchild;
} //沿右分支向下遍历
}
return NULL; //p和q公共祖先
}
14.顺序表操作实现
//顺序表动态存储初始化
void initList(SeqList& L){
L.data=new DtaType[initSize];
if(!L.data){ printf("分配错误\n");}
L.maxSize;
L.n=0;
}
//清空
void clearList(SeqList& L){
L.n=0;
}
//求长度
void Length(SeqList& L){
return L.n;
}
//判表空
int isEmpty(SeqList& L){
return (L.n==0)?1:0;
}
//判断表满
int isFull(SeqList &L){
return (L.n==L.maxSize)?1:0;
}
//查找
int Search(SeqList& L,DataType x){
for(int i=1;i<L.n;i++)
if(L.data[i-1]==x)
return i;
return 0;
}
//定位
int Locate(SeqList& L,int i){
if(i>=1 && i<=L.n) return i;
else
return 0;
}
//顺序复制
void Copy(SeqList& L1,SeqList& L2){
//复制表L2的全部内容到表L1
L1.maxSize=L2.maxSize;
L1.n=L2.n;
if(!L1.data){
L1.data=new DataType[L1.maxSize];
if(!L1.data){
cout<<"分配错误!";
exit(1);
}
for(int i=1;i<=L.n;i++)
L1.data[i-1]=L2.data[i-1];
}
//插入
int Insert(SeqList& L,int i,DataType& x){
//将元素x插入到表中第i个元素。若插入成功函数返回1,否则返回0
if(L.n==L.maxSize) return 0; //表满,不能插入
if(i<0 || i>L.n+1) return 0; //参数不合理,不可插入
for(int j=L.n;j>=i;j--)
L.data[j]=L.data[j-1]; //依次后移,空出第i号位置
L.data[i-1]=x; // 插入
L.n++;
return 1; //插入成功
}
//顺序表删除算法
int Remove(SeqList& L,int i,DataType& x){
if(!L.n) return 0; //表空,不能删除
if(i<1 ||i>L.n) return 0; //参数i不合理,不能删除
x=L.data[i-1]; //存被删元素的值
for(int j=i;i<L.n;j++)
L.data[j-1]=L.data[j]; //依次前移,填补
L.n--; //表长度减1
return 1; //删成功
}
15.不带头结点单链表的操作
//插入
int insert(LinkList& first,int i,DataType x){
if(!first || i==1){
LinkNode *newNode=new LinkNode;
if(!=newNode){
cerr<<"分配失败";
}
newNode->data=x;
newNode->link=first;
first=newNode; //新结点成为第一个结点
}else{
LinkNode *p=first;
int k=1;
while(p!=NULL && k<i-1){
p=p->link;k++;
}
if(p==NULL && first){ //非空表且链太短
cerr<<"无效的插入位置";
}else{
LinkNode * newNode=new LinkNode; //建立一个新结点
if(p==NULL && first){
cerr<<"分配错误";
newNode->data=x;
newNode->link=p->link;
p->link=newNode;
}
}
}
return 1; //正常插入
}
//删除
int remove(LinkList &first,i,DataType &x){
LinkNode *q,*p;
int k;
if(i<=1){ //删首元结点时表头退到下一个结点
q=first;
first=first->link;
}else{
p=first;
k=1;
while(p!==NULL ||p->link==NULL){ //空表或链太短
cerr<<"无效删除位置";
}
q=p->link; //保存第i号结点的位置
p->link=q->link; //第i-1和第i+1号结点链接
}
x=q->data;
delete q;
return 1;
}
16.带头结点的单链表
//计算长度
int Length(LinkList &first){
LinkNode *p=first->link;
int count=0;
while(p!=NULL)
{p=p->link;count++}
return count;
}
//search -value
LinkNode *Search(LinkList &first,DtaType x){
LinkNode *p=first->link;
while(p!=NULL && p->data!=x)
p=p->link;
return p;
}
//search -locate
LinkNode *locate(LinkList& first,int i){
if(i<0) return NULL; //找头结点时i=0,i<0不合理
LinkNode *p=first;
int k=0;
while(p!=NULL && k<i){ //循环找第i个结点,k作节点计数
p=p->link;
k++;
}
return p;
}
//insert
int insert(LinkList &first,int i,DataType x){
LinkNode *p=Locate(first,i-1);
if(p==NULL) return 0;
LinkNode *s=new LinkNode;
if(!s){ cerr<<分配错误\n;}
s->data=x;
s->link=p->link; p->link=s; //将*s皆在*p之后
return 1;
}
//remove
int remove(LinkList &first,int i,DataType){
LinkNode *p=Locate(first,i-1); //定位于第i-1个结点
if(p==NULL || p->link==NULL) return 0;
LinkNode *q=p->link; //用q保存被删除结点地址
p->link=q->link; //重新链接,将被删结点从链表摘下
x=q->data; delete q; //取出被删除结点中的数据,释放结点
return 1;
}