微三云小爱头像
关注
279 模式的排队与滑落:二叉关系网的状态机实现封面图

279 模式的排队与滑落:二叉关系网的状态机实现

279 这一类模式的组织方式很有意思:每个点位下面只允许挂两个子位(左区/右区),用户按注册或下单顺序进关系网,推荐人双区满了就把新进来的人"滑落"到下级空闲位置,整体凑成固定规模的团队后出局并循环。它本质上是一棵受约束的二叉树,加一个排队滑落调度器,再加一套状态机管出局与重排。本文从开发视角拆这套二叉关系网怎么落地。

目录

  1. 279 模式的关系网长什么样
  2. 把关系网写成平铺用户表的天花板
  3. 技术本质:二叉树 + 排队滑落 + 状态机
  4. 数据支撑,标出处
  5. 二二复制与自由多叉树对比
  6. 关键组件矩阵
  7. 落地步骤与代码
  8. 边界与风险

一、279 模式的关系网长什么样

先看结构。关系网是一棵二叉树:每个节点至多两个子位,约定为左区和右区。新用户注册或下单后进入排队,关系网按"先挂推荐人、双区满再滑落"的规则把人落到某个空位上。当某个子树凑满固定规模(常见为七人:1 个根加左右 2 个、再各带 2 个共 7 个),根节点成团出局,并按"下帮上、左帮右"的规则重新占位,进入下一轮。

滑落是这套结构的关键动作:推荐人直推超过双区容量时,超出的人不丢,而是沿推荐人的关系网向下找首个空闲指定区填进去,填进去那一刻,那个空位的直接上级拿到滑落奖。规则本身可以归纳成三条:直推优先、从上到下、从左到右,并且只填约定区(如只填左区)。

        [1号]
       /      \
   [2号]      [3号]
   /   \      /   \
 [4]  [5]  [6]   [7]      七人团:1号成团出局
             ↑
   滑落示意:1号直推第4人,2号双区已满,则滑落到2号名下
   首个空闲左区(即 [4] 位),2号获得滑落奖

这张图是整篇主线:二叉树管结构,排队滑落管占位,状态机管出局与循环。

二、把关系网写成平铺用户表的天花板

很多团队初期把"谁推荐谁"存成一张用户表:user.sponsor_id、user.zone。这种写法有三个工程痛点,放到二二复制场景会被放大。

其一,约束表达不了。二二复制要求每点严格两个子位,平铺表只能靠应用层自觉,哪天写错一个 zone 就变成三子位,结构被破坏却无感知。

其二,滑落逻辑散落。滑落要同时满足"直推优先、从上到下、从左到右、只填某区",用一堆 UPDATE 拼出来,条件一多就容易错位,明明该填左区却填了右区,账目就乱了。

其三,出局状态无统一机。成团、出局、重排如果没有状态机兜底,常见 bug 是重复出局、漏发奖、循环占位时死循环。关系网的完整性必须靠状态转移来保障,不能靠业务逻辑里到处 if。

要破这三件事,得把关系网抽象成"二叉树节点 + 占位调度器 + 节点状态机"三个独立模块。

三、技术本质:二叉树 + 排队滑落 + 状态机

二叉树节点负责把"每点两子位"的约束固化进数据结构;占位调度器负责排队与滑落寻位;状态机负责节点从待激活到成团到出局再到重排的转移。三者解耦,逻辑才清楚。

节点结构:每点固定两子位。 把约束写进类,越界挂接点直接报错而非静默成功。

# 二叉关系网节点:每个点位至多 2 个子位(左区/右区)
class Node:
    def __init__(self, uid, sponsor=None):
        self.uid = uid
        self.sponsor = sponsor      # 推荐人 uid
        self.left = None            # 左区子位
        self.right = None           # 右区子位
        self.status = "active"      # active / out(出局) / requeued(重排)
        self.team_size = 0          # 冗余:子树活跃点位计数

    def free_zone(self):
        """返回首个空闲区名,满则返回 None(触发滑落)"""
        if self.left is None:  return "left"
        if self.right is None: return "right"
        return None

占位调度:先挂推荐人,双区满则滑落。 有推荐人先直推左右区,满了再 BFS 找下级首个空闲约定区;无推荐人则全网随机占位。

# 占位:推荐人优先,双区满则向下滑落(仅填约定区)
def place(root, new_uid, sponsor_uid, slide_zone="left"):
    sponsor = find_node(root, sponsor_uid)
    if sponsor is None:
        return random_place(root, new_uid)        # 无推荐人:全网随机占位
    zone = sponsor.free_zone()
    if zone:                                      # 直推优先:左/右区有空直接挂
        setattr(sponsor, zone, Node(new_uid, sponsor.uid))
        return {"parent": sponsor.uid, "zone": zone, "bonus": "refer"}
    slot = find_empty_slot(sponsor, slide_zone)   # 双区满 → 滑落寻位
    if slot is None:
        return random_place(root, new_uid)
    setattr(slot, slide_zone, Node(new_uid, slot.uid))
    return {"parent": slot.uid, "zone": slide_zone, "bonus": "slide"}  # slot 上级拿滑落奖

滑落寻位:广度优先,从上到下、从左到右。 只填约定区,确保滑落确定可复现。

# 滑落寻位:BFS 从上到下、从左到右,只填指定区
from collections import deque
def find_empty_slot(subtree, zone="left"):
    q = deque([subtree])
    while q:
        cur = q.popleft()
        if getattr(cur, zone) is None:
            return cur                      # 找到首个空闲约定区
        if cur.left:  q.append(cur.left)
        if cur.right: q.append(cur.right)
    return None

成团判定:子树满固定规模即出局。 用冗余计数避免每次全树遍历,规模阈值可配置(常见七人团)。

# 成团判定:子树活跃点位达阈值即视为成团
TEAM_SIZE = 7
def count_active(node):
    if node is None: return 0
    return 1 + count_active(node.left) + count_active(node.right)

def check_team(node):
    node.team_size = count_active(node)     # 落地时改冗余字段增量维护
    return node.team_size >= TEAM_SIZE

状态机:出局与重排的转移必须收敛。 事件驱动,防止重复出局与无限循环占位。

# 状态机:active → team → out → requeued(下帮上重排)
def transition(node, event):
    if node.status == "active" and event == "team_full":
        node.status = "team"           # 成团
    elif node.status == "team" and event == "settle":
        node.status = "out"            # 出局,结算成团点位收益
    elif node.status == "out" and event == "requeue":
        node.status = "requeued"       # 下帮上、左帮右重新占位
    else:
        raise ValueError(f"非法转移: {node.status} --{event}-->")
    return node.status

循环奖励:推荐收益按单序交替。 首单 20%、次单 80%,之后按单序 20%/80% 交替,是这套模式常见的发放节奏。

# 推荐收益:首单 20%、次单 80%,按单序交替发放
def referral_reward(order_seq, amount):
    """order_seq 从 1 起;奇序 20%,偶序 80%"""
    rate = 0.20 if order_seq % 2 == 1 else 0.80
    return round(amount * rate, 2)

# 例:金额 1000 时,第1单 200、次单 800、第三单 200、第四单 800…
print([referral_reward(i, 1000) for i in range(1, 5)])

引擎配置。 把容量、滑落区、成团规模、奖励节奏外置,规则不硬编码进业务。

{
  "engine": "mode_279",
  "zones_per_node": 2,
  "slide_zone": "left",
  "team_size": 7,
  "referral_rates": [0.20, 0.80],
  "slot_bonus": 50,
  "team_bonus": 100,
  "placement": "sponsor_first_then_slide"
}

四、数据支撑,标出处

社交电商与私域经营已是可观市场,关系网类玩法才有落地土壤。据网经社《2023 中国私域电商市场数据报告》,当年私域电商市场规模约 5.8 万亿元、用户约 4.5 亿。另据 CNNIC 第 56 次《中国互联网络发展状况统计报告》,截至 2025 年 6 月网民规模 11.23 亿、互联网普及率 79.7%。不同机构口径有差异,数字宜看作趋势参考而非精确结论。

二二复制加自动滑落,是社交电商里常见的组织形态,优势在于关系网浅、占位确定、成团易判定。行业里也有循环复购跑出规模的公开运营复盘(某商城用相近机制 8 个月做到 300 万活跃会员),说明这类结构在拉新与复购上的确有效。需要说明:本文第三节的成团规模、奖励比例、滑落区等来自行业常见配置示例,用于把机制讲实,并非任一平台的标准参数,实际取值由运营与合规共同决定。

五、二二复制与自由多叉树对比

维度二二复制(二叉约束)自由多叉树
组织深度收敛快易失控
滑落确定性强(规则明确)弱
成团判定简单(满 N 即团)复杂
合规压力关系网浅易做深
系统复杂度中(需调度器)低但难控

工程上,二二复制用结构约束换来了可判定性:成团就是"满 7 个",滑落就是"BFS 首个空位",逻辑可测试、可复现。自由多叉树写起来省事,但后期占位和结算全靠业务兜,账目极易错乱。

六、关键组件矩阵

组件职责优势劣势
关系网存储二叉树持久化结构清晰深链查询开销
占位调度排队 + 滑落公平确定需并发控制
滑落引擎寻位算法可复现规则分支多
成团判定满员检测自动触发需计数优化
状态机转移管理防重复出局事件需穷举
收益结算奖励发放透明须幂等

六个组件里,占位调度和收益结算容易被低估。前者决定两个人会不会抢同一个空位,后者决定同一次成团会不会发两次奖——两者都必须在事务与锁的边界内解决。

七、落地步骤与代码

占位要原子。占位动作包含"读推荐人双区状态、读下级空位、写入新节点"三步,高并发注册若不加约束,会出现两人同时看到同一个空位、各写一次,二叉树被悄悄破坏。做法是在推荐人维度加分布式锁,或把"寻找空位 + 写入"合成单条数据库条件更新(仅当目标区为 NULL 时才写入),让数据库确保原子。

滑落要幂等。一次注册只应占位一次,重试不能重复挂节点、重复发奖。用"注册单号 + 状态机"约束:同一单只能从"待占位"转到"已占位"一次,占位与收益发放放在同一事务内。

成团计数要增量。每次成团都 count_active 全树遍历,深树会拖垮性能。落地时用冗余字段 team_size,在每次占位时沿祖先链 +1,出局重排时回滚,读判定直接取值。

关系网深度要收敛。二二复制天然浅,但滑落可能把人推到很深的叶子。设定上限深度阈值,超深时回退到全网随机占位,避免链过长导致查询与重排成本爆炸。

八、边界与风险

泼一点冷水,工程上要想清楚几件事。

并发占位竞态。双区同占、滑落同位是头号 bug,必须用锁或条件更新兜住,否则关系网静默损坏,后续成团与结算全错。

滑落规则歧义。只填某区还是双区都可填、是从上到下还是按收益优先,规则一句话定不清,代码就会分叉。规则必须写成配置(第三节的 slide_zone),全员按同一份执行。

成团计数性能。深树全量遍历在高峰会卡,冗余计数能解,但要处理"占位与计数回滚"的一致性,重排时别忘了把祖先链计数减回去。

出局循环依赖。出局后"下帮上、左帮右"重排,如果规则没写好,可能出现 A 补 B、B 又补 A 的环,或者无限占位。状态机(第三节 transition)要把"重排"设为终态事件,触发后必须落定,不允许再被二次滑落。

合规边界。关系网深度收敛、奖励收敛在直推与滑落两级,不向下做无限层级计酬,是这类模式能稳健运行的前提,与前面几篇讲过的合规要求一致。具体边界以法务意见为准,技术侧只确保结构不越界。

数据一致性。占位、成团、发奖三者必须同事务:占位成功但发奖失败要整体回滚,否则漏奖或双奖都会出现。把状态机作为统一写入口,能从架构上挡住大部分错账。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/luoanan8899/article/details/167471387

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--