数据结构:伸展树原理及C++实现(自顶向下实现)

本文介绍了伸展树的基本原理,并提供了C++的自顶向下实现。重点讲解了Zig-Zag情况和单旋转操作,指出所有旋转都在根部进行,因此旋转后的节点不需要与其父节点链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

    我现在是一个大二的学生,因为下个学期就要开始学习数据结构这门课程,出于兴趣我提前将数据结构自学了一遍,在学习的过程中发现了许多有趣的结构,最近终于有了一点时间,决定开始写点博客,记录一下自己的想法;这是我第一次写博客,如果有不好的地方欢迎大家指出,我们可以一同讨论共同进步。


原理:

     伸展树(SplayTree)是一种平衡树的结构,是二叉搜索树的一种,他保证从空树开始的任意连续M次对树的操作最多花费O(M logN)时间。虽然与AVL树以及红黑树相比它的时间复杂度似乎要高一些,但是其空间要求以及编程复杂度要更低。接下来,我就来介绍一下伸展树的特性。

    有一种原则叫做叫做"二八原则",也就是说百分之八十的搜索都发生在百分之二十的数据上,伸展树也就是满足这种需求出现的。为了满足这些需求,伸展树在每一次操作后都会把操作的元素,通过一系列的旋转放置到树的根部(插入,删除,查找),在图一中,我们可以看到被查找元素被移动到树根。这样,根据二八原则,访问次数更多的元素,总是在离树根更近的地方,也就减少了检索的时间消耗,增加了效率。在我看来,这是一种非常有想法的一种数据结构,也让人印象深刻。 

 

C++实现:

1.旋转操作:
    如果学习过了AVL树,那么你对旋转操作一定不会陌生,在AVL树中旋转被分为了双旋转和单旋转两种情况(当然,双旋转也就是两个单旋转)。而在我们的伸展树中,也将使用到旋转操作,不过与AVL树有点不同。
     旋转操作可以说是平衡树结构中最最最基础的东西了,它是移动节点的一种有效方式,以图二右旋转为例,我们将当前节点( N节点)变为父节点( F节点),父节点变为当前节点的右儿子,同时将原来的右儿子( S节点)链接到 F节点的左儿子,完成旋转操作。左旋转操作与右旋转操作相同,只是方向相反,这里就不再讲解了。(其实是不想画图了)
下面是我们的实现代码:
/* 右旋转函数:将目标节点向右旋转
 * 返回值:无
 * 参数:Tree:想要进行右旋转的目标节点
 */
void SplayTree::SingleRotateWithLeft(TreeNode &Tree) {
	TreeNode LeftChild; // 储存左子树
	// 进行旋转操作
	LeftChild = Tree->Left;
	Tree->Left = LeftChild->Right;
	LeftChild->Right = Tree;

	Tree = LeftChild; // 更新目标节点
}

/* 左旋转函数:将目标节点向左旋转
 * 返回值:无
 * 参数:Tree:想要进行左旋转的目标节点
 */
void SplayTree::SingleRotateWithRight(TreeNode &Tree) {
	TreeNode RightChild; // 储存右子树
	// 进行旋转操作
	RightChild = Tree->Right;
	Tree->Right = RightChild->Left;
	RightChild->Left = Tree;

	Tree = RightChild; // 更新目标节点
}
PS:有些朋友可能会觉得奇怪,因为这里的旋转代码并没有将父节点与祖父节点链接,难道不会出错吗?不用担心,这是因为伸展树的特殊性,同时也与我们使用的伸展方法有关系,会在后面具体解释。

2. 伸展操作:
        接下来的就是伸展操作,可以说伸展操作是整个伸展树的核心功能,因为所有的功能,都是根据伸展操作进行的(查找,插入,删除)。而伸展操作有两种实现方式。
自底向上伸展:
       这是一种很容易想到的伸展方式,我们通过从树根处开始检索,当我们检索到目标元素时,我们就开始向上伸展,通过旋转的方式将目标元素旋转到树根上。但是,我们可以想到,我们从顶部向下检索的过程中,以及从底部向上伸展的过程中,都需要保存许多的父指针来完成,或将路径储存到某个栈中进行保存,这样讲会带来大量的开销!因此我们更加常用的是另外一个方法——自顶向下伸展。
(有兴趣的朋友可以自己尝试用自底向上方法实现,我在这里就不再多讲了~~)

自顶向下伸展:

        在这里,我们先使用一种叫做标志节点的东西来代替空节点,它的代码如下:
typedef struct SplayNode *TreeNode;
TreeNode NullNode; // 储存空标志节点
N
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值