Treap的读书笔记1

       最近开始了自己高级数据结构之旅,在这次旅行中,我将持续把一些高级的数据结构从理论到编码都过一遍,同时通过博客形式分享出来,希望大家指出不足之处!

       二叉排序树是一种动态排序的数据结构,支持插入、删除、查找等操作,且平均时间复杂度为O(log(N)),但是普通二叉排序树不能保证树退化为一颗分支的情况,此时最坏情况下的时间复杂度为O(N)。此时,平衡二叉树的产生了。平衡二叉树是一种动态调整平衡的数据结构,但理想的平衡二叉树很难,于是人们使用AVL、红黑树、Treap、伸展树等来替代平衡二叉树,这些数据结构可以很好地改善最坏情况。但实现起来并不是很容易的事。

        Treap是Heap+Tree,通俗来讲就是堆与树的结合,每个节点除了关键字key以及节点之间的连接关系外,还要保存一个优先级priority,注意这里的优先级不同于其他节点的随机数字,随机才能较好的期望平衡度,保证可以很好维护二叉树的性质。其中在Treap中关键字key遵循二叉查找树的性质,即:

(1)、空树是一颗二叉查找树;
(2)、若左子树不为空,则左子树中的全部关键字均小于该节点关键字;
(3)、若右子树不为空,则右子树中的全部关键字均不小于该节点关键字;
(4)、若左右子树非空,则左右子树也是一颗二叉查找树。

         Treap中的优先级priority遵循Heap的性质,此处的堆已不再是棵完全二叉树,而是用指针代替数组下标实现的树结构,满足所有根节点优先级小于(或大于)左右孩子节点的优先级(在左右孩子存在的情况下,小于为小顶堆,大于为大顶堆)。

           由于每个节点上的优先级是随机产生的,所以期望高度可以达到很好的程度。在算法导论的12.4节中,其证明了随机构造的二叉查找树的期望高度为O(lgn),因而treap的期望高度亦是O(lgn)。

           Treap支持二叉树的所有操作,且平摊时间复杂度为O(log(N)),便于实现,性能好,克服了二叉查找树最坏情况时间复杂度为O(N)的弊端,有不存在AVL、红黑树等编码和理解难度,与伸展树有类似好处。下面简要谈谈Treap的几种基本操作。

左旋:

                        Treap的读书笔记1_第1张图片

右旋:

                 Treap的读书笔记1_第2张图片

             以上截图来自http://www.cnblogs.com/huangxincheng/archive/2012/07/30/2614484.html,在此表示感谢!

查找:

        查找直接用二叉树的性质,参考源代码。

插入:

       先找到插入位置,在执行插入操作,然后维护堆的性质,即根据优先级调整以维护小顶堆或大顶堆的性质。关于维护队的性质,参考我前面的关于对的博客。

删除:

       类比二叉查找树一样,删除结点存在三种情况:
(1)、叶子结点,跟二叉查找树一样,直接释放本节点即可。
(2)、只有一个还自己节点,跟二叉查找树一样操作。
(3)、有两个孩子节点,可以像二叉查找树一样转换为删除右子树最小节点或左子树最大节点,然后将只赋值到本应删除的节点处,此时可以一起复制优先级,然后向该分支调整,也可不赋值优先级保留原来的优先级,我的程序保留原来优先级。

更新:

      先删除原节点,然后插入新节点。

      由于期望高度为O(log(N)),所以以上所有操作的平潭时间复杂度为O(log(N))。

 

下面贴段代码:

//Treap头文件TreapNode.h
#include<iostream>
using namespace std;

/**********************************
*功能:防止头文件多次包含
**********************************/
#ifndef TREAPNODE_H
#define TREAPNODE_H

class TreapNode
{
public:
	TreapNode *leftChild;
	TreapNode *rightChild;
	TreapNode *parent;
	int key;
	int priority;
	TreapNode(int tempKey,int tempPriority)
	{
		this->priority=tempPriority;
		this->key=tempKey;
		this->leftChild=NULL;
		this->rightChild=NULL;
		this->parent=NULL;
	}
};

#endif TREAPNODE_H


 

//Treap源文件Treap.cpp

#include<iostream>
#include<cstring>
#include<ctime>
#include"TreapNode.h"
using namespace std;

class Treap
{
private:
	TreapNode *root;
	bool usedPriority[RAND_MAX];
	void LeftRotate(TreapNode *);
	void RightRotate(TreapNode *);
	void PreOrderTPPrint(TreapNode *);
	void InOrderTPPrint(TreapNode *);
	void RotateTPPrint(TreapNode *,int);
	void SufOrderTPPrint(TreapNode *);
	void DeleteNoOrOneChildTPNode(TreapNode *,TreapNode *);
	void ModifyTreap(TreapNode *);
	int SetNodePriority();
public:
	Treap();
	void InsertTreap(int);
	bool DeleteTreap(int);
	bool UpdataTreap(int,int);
	TreapNode *FindTreap(int);
	void PreOrderTPPrint();
	void InOrderTPPrint();
	void RotateTPPrint();
	void SufOrderTPPrint();
};

Treap::Treap()
{
	memset(usedPriority,false,sizeof(usedPriority));
	this->root=NULL;
} 

/**************************************************************
*参数:无
*返回值:整形
*功能:产生未使用的随机数作为优先级
***************************************************************/
int Treap::SetNodePriority()
{
	int val;
	while(usedPriority[val=rand()]);
	usedPriority[val]=true;
	return val;
}

/**************************************************************
*参数:待左旋的节点
*返回值:空
*功能:左旋
***************************************************************/
void Treap::LeftRotate(TreapNode *tempTPNode)
{
	TreapNode *rChild=tempTPNode->rightChild;
	if(NULL==rChild)return;
	if(NULL!=tempTPNode->parent)//不为根节点
	{
		if(tempTPNode->parent->leftChild==tempTPNode)
			tempTPNode->parent->leftChild=rChild;
		else 
			tempTPNode->parent->rightChild=rChild;
	}
	rChild->parent=tempTPNode->parent;
	tempTPNode->parent=rChild;
	if(rChild->leftChild!=NULL)
		rChild->leftChild->parent=tempTPNode;
	tempTPNode->rightChild=rChild->leftChild;
	rChild->leftChild=tempTPNode;
	if(NULL==rChild->parent)
		this->root=rChild;
}

/**************************************************************
*参数:待右旋的节点
*返回值:空
*功能:右旋
***************************************************************/
void Treap::RightRotate(TreapNode *tempTPNode)
{
	TreapNode *lChild=tempTPNode->leftChild;
	if(NULL==lChild)return;
	if(NULL!=tempTPNode->parent)//不为根节点
	{
		if(tempTPNode->parent->rightChild==tempTPNode)
			tempTPNode->parent->rightChild=lChild;
		else 
			tempTPNode->parent->leftChild=lChild;
	}
	lChild->parent=tempTPNode->parent;
	tempTPNode->parent=lChild;
	if(lChild->rightChild!=NULL)
		lChild->rightChild->parent=tempTPNode;
	tempTPNode->leftChild=lChild->rightChild;
	lChild->rightChild=tempTPNode;
	if(NULL==lChild->parent)
		this->root=lChild;
}

/**************************************************************
*参数:待调整节点
*返回值:空
*功能:根据优先级按小顶堆来调整
***************************************************************/
void Treap::ModifyTreap(TreapNode *tempTPNode)
{
	TreapNode *parTempTPNode=tempTPNode->parent;
	while(parTempTPNode!=NULL&&parTempTPNode->priority>tempTPNode->priority)//大于父亲节点优先级
	{
		if(tempTPNode==parTempTPNode->leftChild)
			RightRotate(parTempTPNode);
		else LeftRotate(parTempTPNode);
		parTempTPNode=tempTPNode->parent;
	}
}

/**************************************************************
*参数:带插入元素
*返回值:空
*功能:将当前元素插入Treap
***************************************************************/
void Treap::InsertTreap(int tempKey)
{
	TreapNode *pre=NULL,*cur=this->root;
	while(cur!=NULL)
	{
		pre=cur;
		if(cur->key>tempKey)//tempKey插到左子树
			cur=cur->leftChild;
		else cur=cur->rightChild;//插到左子树
	}
	TreapNode *tempTPNode=new TreapNode(tempKey,SetNodePriority());
	tempTPNode->parent=pre;
	if(pre==NULL)//若插入的为根节点
	{
		this->root=tempTPNode;
	}
	else if(pre->key>tempTPNode->key)
		pre->leftChild=tempTPNode;
	else pre->rightChild=tempTPNode;
	ModifyTreap(tempTPNode);//调整
}

/**************************************************************
*参数:带查找元素
*返回值:返回查找元素在Treap中的位置
*功能:查找当前元素是否在Treap
***************************************************************/
TreapNode *Treap::FindTreap(int tempKey)
{
	TreapNode *cur=this->root;
	while(cur!=NULL)
	{
		if(cur->key==tempKey)
			break;
		else if(cur->key>tempKey)
			cur=cur->leftChild;
		else cur=cur->rightChild;
	}
	return cur;
}

/**********************************************************
*参数:pre待删除节点的父节点,cur待删除节点
*返回值:空
*功能:删除左右孩子有为空的情况
************************************************************/
void Treap::DeleteNoOrOneChildTPNode(TreapNode *pre,TreapNode *cur)
{
	if(NULL==cur->leftChild&&NULL==cur->rightChild)//左右孩子为空
	{
		if(NULL==pre)
			this->root=NULL;
		else if(pre->leftChild==cur)
			pre->leftChild=NULL;
		else pre->rightChild=NULL;
		delete cur;
	}
	else if(cur->rightChild!=NULL)//若右子树不为空
	{
		if(NULL==pre)
		{
			this->root=cur->rightChild;
			cur->rightChild->parent=NULL;
		}
		else if(pre->leftChild==cur)
		{
			pre->leftChild=cur->rightChild;
			cur->rightChild->parent=pre;
		}
		else 
		{
			pre->rightChild=cur->rightChild;
			cur->rightChild->parent=pre;
		}
		delete cur;
	}
	else if(cur->leftChild!=NULL)//若左子树不为空
	{
		if(NULL==pre)
		{
			this->root=cur->leftChild;
			cur->leftChild->parent=NULL;
		}
		else if(pre->leftChild==cur)
		{
			pre->leftChild=cur->leftChild;
			cur->leftChild->parent=pre;
		}
		else
		{
			pre->rightChild=cur->leftChild;
			cur->leftChild->parent=pre;
		}
		delete cur;
	}
}


/**********************************************************
*参数:待删除节点元素
*返回值:空
*功能:删除元素主函数
************************************************************/
bool Treap::DeleteTreap(int tempKey)
{
	TreapNode *pre=NULL,*cur=root;
	while(cur!=NULL)//寻找待删除元素
	{
		if(cur->key==tempKey)
			break;
		else
		{
			pre=cur;
			if(cur->key>tempKey)
				cur=cur->leftChild;
			else cur=cur->rightChild;
		}
	}
	if(NULL==cur)return false;
	if(NULL==cur->leftChild||NULL==cur->rightChild)
		DeleteNoOrOneChildTPNode(pre,cur);
	else //左右子树都不为空
	{
		TreapNode *rPre=cur,*rCur=cur->rightChild;//找到右子树最小元素
		bool isLeft;
		while(rCur->leftChild!=NULL)
		{
			rPre=rCur;
			rCur=rCur->leftChild;
		}
		cur->key=rCur->key;//直接填充元素,不复制优先级
		if(rPre->leftChild==rCur)
			isLeft=true;
		else isLeft=false;
		DeleteNoOrOneChildTPNode(rPre,rCur);
		if(isLeft)
			ModifyTreap(rPre->leftChild);
		else ModifyTreap(rPre->rightChild);
	}
	return true;
}

/**********************************************************
*参数:待修改节点元素、修改后的元素
*返回值:返回修改是否成功
*功能:修改函数
************************************************************/
bool Treap::UpdataTreap(int oldKey,int newKey)
{
	if(DeleteTreap(oldKey))
	{
		InsertTreap(newKey);
		return true;
	}
	return false;
}

/**********************************************************
*参数:当前子树根节点
*返回值:空
*功能:前序遍历Treap
************************************************************/
void Treap::PreOrderTPPrint(TreapNode *tempTPNode)
{
	if(NULL==tempTPNode)
		return ;
	cout<<"("<<tempTPNode->key<<","<<tempTPNode->priority<<")   ";
	PreOrderTPPrint(tempTPNode->leftChild);
	PreOrderTPPrint(tempTPNode->rightChild);
}
void Treap::PreOrderTPPrint()
{
	PreOrderTPPrint(this->root);
}

/**********************************************************
*参数:当前子树根节点
*返回值:空
*功能:中序遍历Treap
************************************************************/
void Treap::InOrderTPPrint(TreapNode *tempTPNode)
{
	if(NULL==tempTPNode)
		return ;
	InOrderTPPrint(tempTPNode->leftChild);
	cout<<"("<<tempTPNode->key<<","<<tempTPNode->priority<<")   ";
	InOrderTPPrint(tempTPNode->rightChild);
}
void Treap::InOrderTPPrint()
{
	InOrderTPPrint(this->root);
}

/**********************************************************
*参数:当前子树根节点
*返回值:空
*功能:后序遍历Treap
************************************************************/
void Treap::SufOrderTPPrint(TreapNode *tempTPNode)
{
	if(NULL==tempTPNode)
		return ;
	SufOrderTPPrint(tempTPNode->leftChild);
	SufOrderTPPrint(tempTPNode->rightChild);
	cout<<"("<<tempTPNode->key<<","<<tempTPNode->priority<<")   ";
}
void Treap::SufOrderTPPrint()
{
	SufOrderTPPrint(this->root);
}

/**********************************************************
*参数:当前子树根节点,缩进列数
*返回值:空
*功能:翻转打印Treap
************************************************************/
void Treap::RotateTPPrint(TreapNode *tempTPNode,int tempColumn)
{
	if(NULL==tempTPNode)
		return ;
	RotateTPPrint(tempTPNode->leftChild,tempColumn+1);
	for(int i=0;i<tempColumn;i++)
		cout<<"    ";
	cout<<"("<<tempTPNode->key<<","<<tempTPNode->priority<<")"<<endl;
	RotateTPPrint(tempTPNode->rightChild,tempColumn+1);
}
void Treap::RotateTPPrint()
{
	RotateTPPrint(this->root,0);
}


void Menu()
{
	int val,choice,newVal;
	Treap myTreap;
	while(true)
	{
		do
		{
			cout<<"&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&"<<endl;
			cout<<"       1.插入"<<endl;
			cout<<"       2.删除"<<endl;
			cout<<"       3.修改"<<endl;
			cout<<"       4.查找"<<endl;
			cout<<"       5.显示"<<endl;
			cout<<"       6.返回"<<endl;
			cout<<"请输入你的选项[ ]\b\b";
			cin>>choice; 
		}while(choice!=1&&choice!=2&&choice!=3&&choice!=4&&choice!=5&&choice!=6);
		if(1==choice)
		{
			cin>>val;
			myTreap.InsertTreap(val);
		}
		else if(2==choice)
		{
			cin>>val;
			if(myTreap.DeleteTreap(val))
				cout<<"删除成功!"<<endl;
			else cout<<"删除失败!"<<endl;
		}
		else if(3==choice)
		{
			cin>>val>>newVal;
			if(myTreap.UpdataTreap(val,newVal))
				cout<<"修改成功!"<<endl;
			else cout<<"修改失败!"<<endl;
		}
		else if(4==choice)
		{
			cin>>val;
			if(NULL!=myTreap.FindTreap(val))
				cout<<"查找成功!"<<endl;
			else cout<<"查找失败!"<<endl;
		}
		else if(5==choice)
		{
			cout<<endl<<"*****************************"<<endl;
			cout<<endl<<"==========前序=============="<<endl;
			myTreap.PreOrderTPPrint();
			cout<<endl<<"==========中序================"<<endl;
			myTreap.InOrderTPPrint();
			cout<<endl<<"==========后续==============="<<endl;
			myTreap.SufOrderTPPrint();
			cout<<endl<<"==========对称+旋转==============="<<endl;
			myTreap.RotateTPPrint();
			cout<<endl<<"*****************************"<<endl;
		}
		else return ;
	}
}


int main()
{
	while(true)
		Menu();
	system("pause");
	return 0;
}


     由于时间有限,疏于测试,如有错误,欢迎斧正!

 

 

你可能感兴趣的:(二叉查找树,treap,平衡二叉树)