用二叉查找树实现持久动态集合

本文探讨了在二叉查找树中实现持久动态集合的问题,指出插入操作会导致路径上所有结点改变,时间复杂度为O(h),空间复杂度与新分配结点数成正比。同时,为了避免影响旧树结构,需要复制整棵树,特别是在涉及父结点的情况下。文章还提到了使用红黑树实现该集合,通过辅助栈避免父指针,以达到最坏情况下O(lgn)的时间复杂度。
摘要由CSDN通过智能技术生成


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题目知可以通过辅助栈来实现不带父指针的红黑树,这样就能满足题意。


  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值