第一次写就上榜了,记录一下

没想到第一次发博客就上了新人榜,原本只是想想将自己学到的东西整理一下,竟然能帮到别人,真的很不错!我会继续发帖的,这也将会给我的学习提供动力!

c5966c0be97549a1853e4715f5ba536c.jpg

CSDN每天最佳新人--2024-07-05-CSDN社区

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个跳表实现的玩家排行榜,支持快速查询玩家所在排名,并且支持不同玩家同积分按上榜时间排名。假设我们用一个玩家结构体来表示玩家信息,包含玩家ID、分数和上榜时间: ```c++ struct Player { int id; int score; time_t time; }; ``` 首先,我们需要定义跳表节点的结构体: ```c++ struct SkipNode { Player player; vector<SkipNode*> next; SkipNode(const Player& player, int level): player(player) { next.resize(level); } }; ``` 其中,`next` 是一个指向下一个节点的指针数组,长度为当前节点的层数。 接下来,我们定义一个玩家排行榜类: ```c++ class PlayerRanking { public: PlayerRanking(): head(new SkipNode(Player{-1, -1, 0}, MAX_LEVEL)), level(1) {} ~PlayerRanking() { SkipNode* p = head; while (p) { SkipNode* q = p; p = p->next[0]; delete q; } } void addPlayer(const Player& player) { SkipNode* p = head; vector<SkipNode*> update(MAX_LEVEL); for (int i = level - 1; i >= 0; i--) { while (p->next[i] && cmpPlayer(p->next[i]->player, player) < 0) { p = p->next[i]; } update[i] = p; } p = p->next[0]; if (p && cmpPlayer(p->player, player) == 0) { // 如果已经存在相同分数的玩家,则更新玩家信息 p->player = player; } else { // 否则插入新节点 int newLevel = randomLevel(); if (newLevel > level) { for (int i = level; i < newLevel; i++) { update[i] = head; } level = newLevel; } p = new SkipNode(player, newLevel); for (int i = 0; i < newLevel; i++) { p->next[i] = update[i]->next[i]; update[i]->next[i] = p; } } } int getPlayerRank(int playerId) { SkipNode* p = head; for (int i = level - 1; i >= 0; i--) { while (p->next[i] && p->next[i]->player.id <= playerId) { if (p->next[i]->player.id == playerId) { return getPlayerRank(p->next[i]); } p = p->next[i]; } } return -1; // 找不到对应的玩家 } private: static const int MAX_LEVEL = 16; SkipNode* head; int level; int getPlayerRank(SkipNode* node) { int rank = 0; SkipNode* p = head; for (int i = level - 1; i >= 0; i--) { while (p->next[i] && cmpPlayer(p->next[i]->player, node->player) < 0) { rank += countNodes(p->next[i]); p = p->next[i]; } } return rank + countNodes(node->next[0]) + 1; } int countNodes(SkipNode* node) { int cnt = 0; while (node) { cnt++; node = node->next[0]; } return cnt; } int cmpPlayer(const Player& p1, const Player& p2) { if (p1.score != p2.score) { return p1.score > p2.score ? 1 : -1; } else if (p1.time != p2.time) { return p1.time < p2.time ? 1 : -1; } else { return p1.id - p2.id; } } int randomLevel() { int level = 1; while (rand() % 2 == 0 && level < MAX_LEVEL) { level++; } return level; } }; ``` 在上面的实现中,我们使用了随机化的方法来决定每个节点的层数,以保证跳表高度的期望是 O(log n)。`addPlayer` 方法用于向排行榜中添加新玩家,如果已经存在相同分数和时间的玩家,则更新玩家信息。`getPlayerRank` 方法用于查询玩家所在排名。 在 `getPlayerRank` 方法中,我们先从跳表的最高层开始,一层一层向下查找,直到找到对应玩家的节点或者找到比该玩家分数低的节点。如果找到了对应玩家的节点,则调用 `getPlayerRank(SkipNode* node)` 方法来计算该玩家的排名。 在 `getPlayerRank(SkipNode* node)` 方法中,我们从跳表的顶层开始,一层一层向下查找,直到找到对应节点,中间经过的所有节点的数量就是该节点的排名。注意,这里的节点数量不包括该节点本身,因此最后要加上 1。 在 `cmpPlayer` 方法中,我们定义了一个比较函数,用于比较两个玩家的大小。首先比较分数,分数相同时比较上榜时间,时间相同时比较玩家ID。 完整代码如下:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值