a) 从根结点到待插入结点的这条路径上的所有结点都需要改变。
b)代码如下:
//13-1持久动态集合
#include <iostream>
#include <time.h>
using namespace std;
#define LEN sizeof(struct Tree)
#define m 10//栈的最大容纳空间可以调整
struct Tree
{
int key;
struct Tree*lchild;
struct Tree*rchild;
};
//非递归的插入函数
struct Tree*PERSISTENT_TREE_INSERT(struct Tree*&root,struct Tree*z)
{//只要是注释都是与12章插入函数不同之处。
struct Tree*y=NULL;
struct Tree*x=root;
struct Tree*root1=NULL,*p=NULL,*p2=NULL;//p为当前新树T’的当前结点。p2为原树T中等于当前结点p->key的值的父结点。
while (x)
{
y=new struct Tree[LEN];
y->key=x->key;//复制原树T的结点值。
if (root->key==x->key)
{
p=root1=y;//设置新的复制后的根结点。
}
else if (z->key<p2->key)
{
p->lchild=y;//设置复制后的新树T’的当前结点的左右孩子
p->rchild=p2->rchild;
p=p->lchild;//更新新树当前结点。
}
else
{
p->rchild=y;
p->lchild=p2->lchild;
p=p->rchild;
}
p2=x;
if (z->key<p2->key)
x=x->lchild;
else
x=x->rchild;
}
y->lchild=y->rchild=NULL;//找到且复制待插入结点的父结点后,把复制后的新父结点左右孩子置空。
if (y==NULL)
{
root=z;
}
else if(z->key<y->key)
{
y->lchild=z;
}
else y->rchild=z;
z->lchild=z->rchild=NULL;
return root1;
}
//非递归的插入函数
void ITERATIVE_TREE_INSERT(struct Tree*&root,struct Tree*z)
{
struct Tree*y=NULL;
struct Tree*x=root;
while (x)
{
y=x;
if (z->key<x->key)
x=x->lchild;
else x=x->rchild;
}
if (y==NULL)
{
root=z;
}
else if(z->key<y->key)
{
y->lchild=z;
}
else y->rchild=z;
z->lchild=z->rchild=NULL;
}
//中序遍历
void InOderTraverse(struct Tree *p)
{
if (p)
{
InOderTraverse(p->lchild);
cout<<p->key<<" ";
InOderTraverse(p->rchild);
}
}
void main()
{
int array[6]={4,3,8,2,7,10};
//int array[10]={5,3,8,2,4,7,10,6,9,11};
int i=0;
struct Tree*root=NULL;
struct Tree*z=new struct Tree[LEN];
z->key=array[i++];//20
ITERATIVE_TREE_INSERT(root,z);
while (i!=6)
{
z=new struct Tree[LEN];
z->key=array[i++];
ITERATIVE_TREE_INSERT(root,z);
}
z=new struct Tree[LEN];
z->key=5;//12
struct Tree*root1=PERSISTENT_TREE_INSERT(root,z);
InOderTraverse(root);//原树T
cout<<endl;
InOderTraverse(root1);//新树T’
cout<<endl;
c)时间就是a部分所说的路径上的所有结点,这个结点数量等于树高。而空间上又和新分配结点数成正比,所以时间空间都为O(h).
d)由于增加了父结点,那么需要复制整棵树,为什么呢? 比如题目中的二叉树图所给例子,结点3和4,如果在调用新插入函数时,不对结点3也就是旧结点复制,那么新树T’中的结点3的父结点就会指向旧树中结点4,而不是新树中的结点4,查看结点地址就会明白。所以需要的时间就是Ω(n),在不是必须引入父指针时,最好不要使用它,以免增加时间空间上的工作量。
e)用红黑树实现持久动态集合,又要求最坏时间为O(lgn),那么就不能有父结点,根据13,3-6题目知可以通过辅助栈来实现不带父指针的红黑树,这样就能满足题意。