动态顺序统计

在之前的随机选择算法中,我们可以很快的在集合中寻找到第i小的元素,然而,这样的集合并不支持动态的扩充。这一节里,将介绍通过红黑树(具体可参考红黑树1红黑树2两篇文章)的扩充,使得任意的顺序统计量都可以在短时间内查找到,而这样的数据结构同时也支持数据的更新。

这样的数据结构称为顺序统计树,如下图。树的节点大致上与红黑树的类似,但增加了一个记录子树大小的域size[x],定义哨兵Nil的子树大小为0,即size[Nil[T]]=0。有等式size[x]=size[left[x]]+size[right[x]]+1


顺序统计树主要有两种算法:

1.检索具有给定排序的元素

其实就是x的顺序就保存在他的左孩子的节点上,所以每次和左孩子记录的值进行比较,匹配成功,则直接返回;比左孩子小了,那么在做孩子处递归调用算法;否则在右孩子处递归调用算法。

2.确定一个元素的秩

和上一个差不多,只是传入的节点,返回的节点所处的位置。

所有节点在插入的时候时需要注意,因为插入的过程就是和某一个节点比较大小,如果小于这个节点,那么就往左孩子处递归调用算法,否则的话向右孩子处递归。每次递归的时候,都需要给当前节点的size位加上1。一直递归到底层,这个时候,由于红黑树的插入性质,需要做左旋或者右旋的一些操作(颜色的改变不会影响到子树的大小),旋转之后需要重新确定好节点的大小。

下面给出代码(基于之前的红黑树的,所以嘛有点长==):

PS:其实改动的代码不到100行,其他的就是红黑树的源代码

#include <stdio.h>
#include <stdlib.h>

typedef enum Color{Red,Black}Color;

/*这里定义树的结构,每个节点为Node结构体,再加上一个头指针Tree*
在红黑树中,多了一个颜色的域Color,这里用枚举表示
顺序统计数中,多了一个表示子树大小的Size*/
typedef struct Node
{
    int data;
    Color color;
    struct Node* left;
    struct Node* right;
    struct Node* parent;
    int Size;
}Node;

Node Nil={0,Black,NULL,NULL,NULL};

typedef struct Tree
{
    Node* Root;
}Tree;


/*一下的操作主要针对普通的二叉搜索树进行,但一些搜索、前去后继等操作也是可以直接用的*/


/*对树进行中序遍历*/
void Mid_Traverse(Node* Root)
{
    if(Root!=&Nil)
    {
        Mid_Traverse(Root->left);
        printf("%d ",Root->data);
        Mid_Traverse(Root->right);
    }
}


/*普通二叉树的插入操作,对红黑树不能用这个函数!*/
/*以下函数是对树进行插入操作
定义两个Node变量x和y,一开始x指向根节点,y为空
然后将x的值一次往下递减向左边下降还是右边依据和z的比较,而y的值一直都是x的父节点,以防当x为空时,就找不到这棵树了
然后让z的父节点指向y,相当于把z放到x的地方
当然,需要判断这棵树是否一开始就是空的,如果y是空的话,那么直接把更节点给z
否则的话更具z的值与y比较大小,判断是把z放到左边还是右边*/
void Tree_Insert(Tree* T,Node* z)
{
    Node* y=NULL;
    Node* x=T->Root;
    while(x!=NULL)
    {
        y=x;
        if(z->data<x->data)
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值