模板 1:通用数据结构模板 (Python)
这是最基础、最核心的模板,适用于大多数编程语言,它通常是一个由 (元素, 权重) 对组成的列表。
数据结构定义
# 类型别名,增加代码可读性
WeightedItem = tuple[any, float | int] # 元素可以是任何类型,权重是整数或浮点数
class WeightList:
def __init__(self):
"""初始化一个空的权重列表"""
self.items: list[WeightedItem] = []
def add(self, item: any, weight: float | int):
"""添加一个元素及其权重"""
if weight <= 0:
raise ValueError("权重必须大于0")
self.items.append((item, weight))
def remove(self, item: any):
"""移除一个元素(如果存在)"""
self.items = [(i, w) for i, w in self.items if i != item]
def get_total_weight(self) -> float | int:
"""计算所有权重之和"""
return sum(weight for _, weight in self.items)
def __len__(self) -> int:
"""返回元素的数量"""
return len(self.items)
def __str__(self) -> str:
"""返回列表的字符串表示"""
return str(self.items)
使用示例
# 创建一个权重列表
wl = WeightList()
wl.add("苹果", 10)
wl.add("香蕉", 5)
wl.add("橙子", 3)
# 打印列表和总权重
print(f"权重列表: {wl}")
print(f"总权重: {wl.get_total_weight()}") # 输出: 18
# 移除一个元素
wl.remove("香蕉")
print(f"移除香蕉后: {wl}")
print(f"新的总权重: {wl.get_total_weight()}") # 输出: 13
模板 2:带随机选择功能的模板 (Python)
这是“权重列表”最常见的应用场景之一,用于根据权重进行随机抽样。
数据结构定义
在模板1的基础上,增加随机选择功能。
import random
class WeightedRandomSelector(WeightList):
def __init__(self):
"""初始化权重随机选择器"""
super().__init__()
self._total_weight = 0 # 缓存总权重,提高效率
def add(self, item: any, weight: float | int):
"""添加元素并更新总权重缓存"""
super().add(item, weight)
self._total_weight += weight
def remove(self, item: any):
"""移除元素并更新总权重缓存"""
# 需要先找到要移除的权重
item_to_remove = next((i for i, w in self.items if i == item), None)
if item_to_remove:
_, weight_to_remove = next((i, w) for i, w in self.items if i == item)
super().remove(item)
self._total_weight -= weight_to_remove
def get_total_weight(self) -> float | int:
"""返回缓存的或计算的总权重"""
return self._total_weight
def choose_one(self) -> any:
"""
根据权重随机选择一个元素。
这是核心算法,使用轮盘赌选择法。
"""
if not self.items:
raise ValueError("权重列表为空,无法选择")
# 1. 生成一个 [0, total_weight) 范围内的随机数
point = random.uniform(0, self._total_weight)
# 2. 遍历列表,累加权重,直到累加值大于随机数
current_weight = 0
for item, weight in self.items:
current_weight += weight
if point < current_weight:
return item
# 理论上不会执行到这里,但为了健壮性
return self.items[-1][0]
def choose_n(self, n: int) -> list[any]:
"""随机选择 n 个元素(可重复)"""
return [self.choose_one() for _ in range(n)]
使用示例
# 创建一个抽奖箱
lottery_box = WeightedRandomSelector()
lottery_box.add("一等奖", 1)
lottery_box.add("二等奖", 5)
lottery_box.add("三等奖", 10)
lottery_box.add("谢谢参与", 84)
print(f"抽奖箱内容: {lottery_box}")
print(f"总权重 (总概率): {lottery_box.get_total_weight()}")
# 模拟抽奖100次
results = lottery_box.choose_n(100)
print(f"抽奖100次结果统计:")
print(f"一等奖: {results.count('一等奖')} 次")
print(f"二等奖: {results.count('二等奖')} 次")
print(f"三等奖: {results.count('三等奖')} 次")
print(f"谢谢参与: {results.count('谢谢参与')} 次")
输出结果会非常接近权重比例,例如一等奖大约出现1次,二等奖5次,三等奖10次。
模板 3:Excel / Google Sheets 实现模板
在电子表格中实现权重列表非常直观,常用于随机抽样、加权平均等计算。
结构设计
| A | B | C | D | |
|---|---|---|---|---|
| 1 | 项目/选项 | 权重 | 随机数 (辅助列) | 随机选择结果 |
| 2 | 苹果 | 10 | =RAND() |
=IF(D2=MIN($D$2:$D$5), A2, "") |
| 3 | 香蕉 | 5 | =RAND() |
=IF(D3=MIN($D$2:$D$5), A3, "") |
| 4 | 橙子 | 3 | =RAND() |
=IF(D4=MIN($D$2:$D$5), A4, "") |
| 5 | 葡萄 | 2 | =RAND() |
=IF(D5=MIN($D$2:$D$5), A5, "") |
使用方法
- 输入数据:在 A 列和 B 列输入你的项目和对应的权重。
- 生成随机数:在 C2 单元格输入公式
=RAND(),然后向下拖动填充柄,这个函数会为每一行生成一个 0 到 1 之间的随机数。 - 随机选择:
- 简单随机选择:
=VLOOKUP(MIN($C$2:$C$5), $A$2:$B$5, 1, FALSE)这个公式会找到随机数最小值对应的项目。 - 按权重随机选择:这是一个更复杂但更公平的方法,需要用到辅助列和
MATCH/INDEX组合,一个经典的技巧是,权重越高的项目,其随机数应该越小,上面的 D 列公式就是一种实现方式:它找到随机数最小的那一行,并返回对应的项目,每次按F9刷新,都会进行一次新的随机选择。
- 简单随机选择:
模板 4:HTML / JavaScript 前端实现模板
在网页中,权重列表常用于实现“轮盘抽奖”、“广告随机展示”等功能。
HTML 结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">权重列表抽奖</title>
</head>
<body>
<h1>点击按钮进行抽奖</h1>
<button id="drawButton">抽奖</button>
<p id="result"></p>
<script src="weighted_list.js"></script>
</body>
</html>
JavaScript 实现 (weighted_list.js)
class WeightedList {
constructor() {
this.items = [];
this.totalWeight = 0;
}
add(item, weight) {
if (weight <= 0) {
throw new Error("权重必须大于0");
}
this.items.push({ item, weight });
this.totalWeight += weight;
}
chooseOne() {
if (this.items.length === 0) {
throw new Error("权重列表为空");
}
// 生成一个 [0, totalWeight) 范围内的随机数
const point = Math.random() * this.totalWeight;
let currentWeight = 0;
for (const entry of this.items) {
currentWeight += entry.weight;
if (point < currentWeight) {
return entry.item;
}
}
// 理论上不会执行到这里
return this.items[this.items.length - 1].item;
}
}
// --- 使用示例 ---
document.addEventListener('DOMContentLoaded', () => {
const prizeList = new WeightedList();
prizeList.add("一等奖 (iPhone)", 1);
prizeList.add("二等奖 (iPad)", 5);
prizeList.add("三等奖 (AirPods)", 10);
prizeList.add("谢谢参与 (优惠券)", 84);
const drawButton = document.getElementById('drawButton');
const resultElement = document.getElementById('result');
drawButton.addEventListener('click', () => {
const prize = prizeList.chooseOne();
resultElement.textContent = `恭喜您获得: ${prize}!`;
});
});
| 场景 | 核心数据结构 | 关键操作/算法 | 适用工具/语言 |
|---|---|---|---|
| 通用数据存储 | (元素, 权重) 元组列表 |
增加、删除、求和 | Python, Java, C++, Go 等 |
| 随机抽样/抽奖 | (元素, 权重) 元组列表 |
轮盘赌算法 | Python, JavaScript, Excel |
| 加权平均/计算 | (数值, 权重) 元组列表 |
Σ(数值 * 权重) / Σ(权重) |
Excel, Python, R, MATLAB |
| 路径查找/AI | (节点/动作, 概率) 元组列表 |
归一化、概率分布采样 | Python (NumPy), C++, TensorFlow/PyTorch |
选择哪个模板取决于您的具体需求,如果您只是想存储带权重的数据,模板1足够了,如果您需要根据权重进行随机选择,模板2和模板4是最佳选择,如果您在进行数据分析,模板3的Excel方法非常高效。
