头文件:
#pragma once
#include <vector>
#include <windows.h>
class Weight
{
public:
template< typename T >
static int GetWeightIndex( const T *pSrcWeight, size_t Size )
{
if( 0 == pSrcWeight || 0 == Size )
{
return ~0;
}
std::vector< T > Temp;
Temp.assign( pSrcWeight, pSrcWeight + Size );
return GetWeightIndex( Temp );
}
template< typename T >
static int GetWeightIndex( const std::vector< T > &SrcWeight )
{
if( SrcWeight.empty() )
{
return ~0;
}
struct WeightRegion
{
T mLeftWeight;
T mRightWeight;
};
std::vector< WeightRegion > Weights;
Weights.resize( SrcWeight.size() );
WeightRegion Temp = {};
for( size_t i = 0; i < SrcWeight.size(); ++i )
{
const T &Source = SrcWeight[ i ];
WeightRegion &Target = Weights[ i ];
Temp.mLeftWeight = Temp.mRightWeight + 1;
Temp.mRightWeight += Source;
memcpy_s( &Target, sizeof( Target ), &Temp, sizeof( Temp ) );
}
const T RandomPos = 1 + rand() % Temp.mRightWeight;
for( size_t i = 0; i < Weights.size(); ++i )
{
const WeightRegion &Source = Weights[ i ];
if( RandomPos < Source.mLeftWeight || RandomPos > Source.mRightWeight )
{
continue;
}
return i;
}
return ~0;
}
template< typename T >
static int GetWeightIndexTypeX( const T *pSrcData, size_t Size, size_t WeightOffset )
{
if( 0 == pSrcData || 0 == Size )
{
return ~0;
}
std::vector< int > Temp;
Temp.resize( Size );
for( size_t i = 0; i < Size; ++i )
{
memcpy_s( &Temp[ i ], sizeof( Temp[ i ] ), ( char* )( pSrcData + i ) + WeightOffset, sizeof( int ) );
}
return GetWeightIndex( Temp );
}
};
测试:
#include "Weight.h"
#include <time.h>
int main()
{
srand( time( NULL ) );
//比如抽奖系统5个奖品每个奖品的概率权重不同
//如果用rand() % xxx 的方式太繁琐而且太麻烦和容易出错
//如果策划经常改对于程序员来说简直是噩梦...
//我们不如封装一下避免使用rand() % xxx的方式
struct LotteryAward
{
int mLotteryID; //奖品ID
int mWeight; //奖品权重
};
const LotteryAward Awards[] =
{
0,10,
1,22,
2,33,
3,65,
4,41,
};
//
//方式一
//提取出权重
std::vector< int > Weights;
Weights.resize( 5 );
for( size_t i = 0; i < 5; ++i )
{
Weights[ i ] = Awards[ i ].mWeight;
}
//抽奖
printf( "方式一抽奖:\n" );
for( int i = 0; i < 10; ++i )
{
const size_t Index = Weight::GetWeightIndex( Weights );
printf( "第%d次抽奖 抽中奖品:%d\n", i + 1, Awards[ Index ].mLotteryID );
}
//
//方式二
//外部可以避免提取出权重,但是需要提供权重在结构中的自身对齐偏移量
//求权重自身对齐偏移量
const int WeightOffset = ( int )&( ( LotteryAward* )0 )->mWeight;
printf( "方式二抽奖:\n" );
for( int i = 0; i < 10; ++i )
{
const size_t Index = Weight::GetWeightIndexTypeX( Awards, 5, WeightOffset );
printf( "第%d次抽奖 抽中奖品:%d\n", i + 1, Awards[ Index ].mLotteryID );
}
//多次抽奖效率较慢,解决办法将循环封装到内部提供
//类似static bool GetWeightIndex( const T *pSrcWeight, size_t Size, size_t LotteryTimes, std::vector< size_t > &Out );
//或static bool GetWeightIndexTypeX( const T *pSrcData, size_t Size, size_t WeightOffset, size_t LotteryTimes, std::vector< size_t > &Out );
//将所有索引以数组的形式输出,在外部维护这个数组用完再调用输出
return 0;
}
输出: