【王道数据结构】【chapter7查找】【P309t10】

文章描述了一种在随机建立的二叉排序树中,通过递归算法查找第k小元素的解决方案,利用节点的count属性优化平均时间复杂度为O(log2n),并给出了一个实际操作的例子。

边那些一个递归算法,在一棵有n个几点的、随机建立起来的二叉排序树上查找第k(1<=k<=n)小的元素并返回指向该节点的指针。要求算法的平均时间复杂度为O(log2n).二叉排序树的每个结点中除data,lchild,rchild等数据成员外,增加一个count成员,保存以该节点为根的子树上的结点个数

#include <iostream>
#include <queue>
typedef struct node{
    int data;
    struct node* left;
    struct node* right;
    int count;
}node,*pnode;

pnode buynode(int x)
{
    pnode tmp=(pnode) malloc(sizeof (node));
    tmp->data=x;
    tmp->left= nullptr,tmp->right= nullptr,tmp->count=0;
    return tmp;
}

void build_tree(pnode &root,int data)
{
    if(root== nullptr) {
        root= buynode(data);
        return;
    }
    if(data<root->data)build_tree(root->left,data);
    if(data==root->data) return;
    if(data>root->data) build_tree(root->right,data);
}

void print(pnode root)
{
    if(root== nullptr) return;
    std::queue<pnode> record;
    record.push(root);
    int size=record.size();
    while(!record.empty()){
        pnode head=record.front();
        printf("%3d",head->data);
        record.pop();
        if(head->left) record.push(head->left);
        if(head->right) record.push(head->right);
        if(--size==0) puts(""),size=record.size();
    }
}

void set_count(pnode &root)
{
    if(root== nullptr) return;
    int count = 1; // 初始化节点计数为1,包括当前节点
    if(root->left) {
        set_count(root->left);
        count += root->left->count;
    }
    if(root->right) {
        set_count(root->right);
        count += root->right->count;
    }
    root->count = count;
}


pnode search_small(pnode root,int k)
{
    if(k<1||k> root->count) return nullptr;
    if(root->left== nullptr)
    {
        //如果没有左子树,并且k==1,那么第一小的结点就是当前根节点
        if(k==1) return root;
        //因为没有左子树,并且当前结点比它的右节点的全部节点都要小,所以在右子树中找第k-1小的结点
        if(root->right&&k>1) return search_small(root->right,k-1);
    }else{
        if(root->left->count==k-1) return root;
        //左子树的结点个数比k-1多,继续从左子树中找第k大的结点
        if(root->left->count>k-1) return search_small(root->left,k);
        //如果左子树的节点小于k个,并且算上当前的节点也没有k个,那么要查找的结点就在右子树里面
        //当前结点和左子树的值都是要比当前结点的右子树的值要小的,所以要在右子树查找k-左子树节点数-当前节点本身(1)
        if(root->left->count<k-1) return search_small(root->right,k-root->left->count-1);
    }
}
int main() {
    pnode r1= nullptr;
    //p295图7.8(a),这是一棵平衡二叉排序树
    int a[]={45,24,12,37,28,40,55,53,60,70};
    for(int i=0;i<10;i++)
    {
        build_tree(r1,a[i]);
    }
    print(r1);
    set_count(r1);//将每个结点的count值设置好
    puts("");
    for(int i=0;i<10;i++)
    {
        printf("the node number %3d is the %3d th small number \n", search_small(r1,i+1)->data,i+1);
    }

    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桜キャンドル淵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值