C++ 伸展树的实现

 首先我们应该知道什么是伸展树?伸展树是Bst(二叉查找树)的扩展版,而且伸展树不需要存储像AVL树那样的平衡因子或者高来保持平衡,那伸展树是不是会出现严重不平衡的情况呢?就行斜树,答案:不会的哦。后面大家就明白了。伸展树的功能是什么呢?当我们搜索大量数据时为了提高搜索的效率,往往搜索到的数据,下次使用的概率往往会比较大,比如我们使用的智能输入法,浏览网页等等。这里就用到了伸展树哦。

告诉大家:伸展树也要进行旋转的哦!等等,这时有人会诧异,伸展树不具有AVL树的特性,为什么要旋转呢?让我给大家慢慢解释:伸展树的作用就是把搜索到的数据“转移”到树根,那怎么“转移”到树根呢?这就要通过伸展,这也是伸展树的核心所在。而伸展是通过什么实现的呢?答案就是旋转哦。伸展过程中有三种旋转:单旋转,一字型旋转,之字型旋转。

在介绍旋转之前,必须要说一下伸展树的两种伸展的思想:自底向上的伸展,自顶向下的伸展。

自底向上:就是从底端向上伸展,伸展的过程中要保存其父节点,而且有时候在伸展的过程中有些的节点的深度往往还会变大。所以说这种思想往往不适用,而且效率还较低。

自顶向下:从顶部向下伸展,伸展的过程中会有两个空树:RightTreeMin,LeftTreeMax. RightTreeMin存放的是比根节点大的节点,但是往往在连续存放过程中,其存放的数据会愈来愈大,所以叫"RightTreeMin"。LeftTreeMax也是同样的道理哦。

单旋转:

之字形旋转:

大家发现没,单旋转和之字形旋转是一模一样的哦。

一字型旋转:

大家发现没,一字型旋转就是AVL树种的左旋或右旋。

那为什么叫伸展树呢?不叫其他的树呢?其实这和它的实现密切相关。伸展树有两种实现的思想:自底向上的实现,自顶向下的实现。

旋转完后最终要形成一颗完整的树。

完整代码如下: 

	typedef struct SplayNode *TreeNode; 
	typedef int ElemType;

	struct SplayNode {
		ElemType element;
		TreeNode lchild;
		TreeNode rchild;
	};

	class SplayTree
	{
	public:
		SplayTree() :nullnode(new SplayNode()) {
			stroot = nullnode;
		};
		~SplayTree() {
			if (nullnode)
				delete nullnode;
		}
		void Insert(const ElemType X );
		void Display();
		void Delete(const ElemType X);
		ElemType Find(const ElemType X);
		ElemType FindMax();
		ElemType FindMin();
	private:
		void Splay(const ElemType, TreeNode& stree);
		void Display(const TreeNode& stree);
		void RotateRR(TreeNode& stree);  //右旋
		void RotateLL(TreeNode& stree);  //左旋
		void FindMax(TreeNode& stree);
		void FindMin(TreeNode& stree);
	private:
		TreeNode stroot;   //根节点
		TreeNode nullnode;  //为什么要这个节点的呢?这样可以避免出现nullptr->左右孩子的情况
	};

	void SplayTree::Splay(const ElemType X, TreeNode &stroot) {

		TreeNode RightChildMin, LeftChildMax;   
		RightChildMin = LeftChildMax = nullnode;
		RightChildMin->lchild = RightChildMin->rchild = nullnode;
		LeftChildMax->lchild = LeftChildMax->rchild = nullnode;
		nullnode->element = X;      //防止重复

		while (X != stroot->element) {   //不在根节点
			if (X < stroot->element) {         //先判断一字型,然后再进行单旋转。
				if (stroot->lchild == nullnode) 
					break;
				if (X < stroot->lchild->element) 
					RotateRR(stroot);

				RightChildMin->lchild = stroot;
				RightChildMin = stroot; 
				stroot = stroot->lchild; 
			}

			else {
				if (stroot->rchild == nullnode)
					break;
				if (X > stroot->rchild->element) 
					RotateLL(stroot);

				LeftChildMax->rchild = stroot;
				LeftChildMax = stroot; 
				stroot = stroot->rchild; 
			}
		}
	
		LeftChildMax->rchild = stroot->lchild;     
		RightChildMin->lchild = stroot->rchild;

		stroot->lchild = LeftChildMax->rchild;
		stroot->rchild = RightChildMin->lchild;

	}

	void SplayTree::RotateRR(TreeNode& stree) {
		if (!stree)
			return;
		else {
			auto ptr = stree->lchild;
			stree->lchild = ptr->rchild;
			ptr->rchild = stree;
			stree = ptr;
		}
	}

	void SplayTree::RotateLL(TreeNode& stree) {
		if (!stree)
			return;
		else {
			auto ptr = stree->rchild;
			stree->rchild = ptr->lchild;
			ptr->lchild = stree;
			stree = ptr;
		}
	}

	void SplayTree::Insert(const ElemType X) {
		TreeNode newnode = nullptr;
		if (newnode == nullptr) { 
			newnode = new SplayNode(); 
			if (newnode == nullptr)
				throw std::out_of_range("Out of MemorySpace!!");
		
		}

		newnode->element = X;

		if (stroot == nullnode) { 
	
			newnode->lchild = newnode->rchild = nullnode;
			stroot = newnode;
		}

		else {
			Splay(X, stroot); 

		
			if (X < stroot->element) {/*
			                                   newnode
				                              /       \
				                             /         \
				                      stroot->lchild   stroot */

				newnode->lchild = stroot->lchild;
				newnode->rchild = stroot;
				stroot->lchild = nullnode;
				stroot = newnode;
			}

			else if (X > stroot->element) {
			
				newnode->rchild = stroot->rchild;
				newnode->lchild = stroot;
				stroot->rchild = nullnode;
				stroot = newnode;
			}

			else 
				return;
		}
	}

	void SplayTree::Delete(const ElemType X) {
		TreeNode newnode = nullnode;
		if (stroot==nullnode)
			return;
		else {
			Splay(X, stroot);
			if (X == stroot->element) {  
				if (stroot->lchild == nullnode)    //左子树为空
					newnode = stroot->rchild;
				else {
					newnode= stroot->lchild;   
					Splay(X, stroot);   
					newnode->rchild = stroot->rchild;
				}
				delete stroot;
				stroot = newnode;
			}
		}
	}

	ElemType SplayTree::Find(const ElemType X) {
		if (!stroot)
			return 0;
		else {
			Splay(X, stroot);
			if (stroot->element == X) {
				std::cout << "X is exit!!";
				return stroot->element;
			}
			else
				std::cout << "X is not exit!!";
		}
	}

	ElemType SplayTree::FindMax() {
		FindMax(stroot);

		return stroot->element;
	}

	ElemType SplayTree::FindMin() {
		FindMin(stroot);

		return stroot->element;
	}

	void SplayTree::FindMax(TreeNode& stree) {
		if (stree != nullnode)
			while (stree->rchild != nullnode)
				stree = stree->rchild;
		Splay(stree->element, stree);
	}

	void SplayTree::FindMin(TreeNode& stree) {
		if (stree != nullnode)
			while (stree->lchild != nullnode)
				stree = stree->lchild;
		Splay(stree->element, stree);
	}

	void SplayTree::Display() {
		Display(stroot); 
	}

	void SplayTree::Display(const TreeNode &stree) {
		if (stree != nullnode) {
			std::cout<<stree->element << std::endl;
			Display(stree->lchild); 

			Display(stree->rchild);
		}
		else
			return;
	}

参考:《数据结构与算法分析》

发布了50 篇原创文章 · 获赞 11 · 访问量 4092

猜你喜欢

转载自blog.csdn.net/qq_43145594/article/details/102234869