PHP抽奖概率算法


/*
* 不同概率的抽奖原理就是把0到*(比重总数)的区间分块
* 分块的依据是物品占整个的比重,再根据随机数种子来产生0-* 中的某个数
* 判断这个数是落在哪个区间上,区间对应的就是抽到的那个物品。
* 随机数理论上是概率均等的,那么相应的区间所含数的多少就体现了抽奖物品概率的不同。
*/
function get_rand($proArr)
{
$result = array();
foreach ($proArr as $key => $val) {
$arr[$key] = $val['v'];
}
$proSum = array_sum($arr); // 计算总权重
$randNum = mt_rand(1, $proSum);
$d1 = 0;
$d2 = 0;
for ($i=0; $i < count($arr); $i++) { $d2 += $arr[$i]; if($i==0) { $d1 = 0; } else { $d1 += $arr[$i-1]; } if($randNum >= $d1 && $randNum <= $d2) { $result = $proArr[$i]; } } unset ($arr); return $result; } /* * 使用较多的为这个方法 */ function get_rand1($proArr) { $result = array(); foreach ($proArr as $key => $val) {
$arr[$key] = $val['v'];
}
// 概率数组的总概率
$proSum = array_sum($arr);
asort($arr);
// 概率数组循环
foreach ($arr as $k => $v) {
$randNum = mt_rand(1, $proSum);
if ($randNum <= $v) { $result = $proArr[$k]; break; } else { $proSum -= $v; } } return $result; } /* * 奖项数组 * 奖品id,名称,比重 */ $arr = array( array('id'=>1,'name'=>'特等奖','v'=>1),
array('id'=>2,'name'=>'一等奖','v'=>5),
array('id'=>3,'name'=>'二等奖','v'=>10),
array('id'=>4,'name'=>'三等奖','v'=>12),
array('id'=>5,'name'=>'四等奖','v'=>22),
array('id'=>6,'name'=>'没中奖','v'=>50)
);

测试结果(10000次):
get_rand():
count_1:0 count_2:490 count_3:1021 count_4:1172 count_5:2172 count_6:5145
特等奖中奖率全为:0
get_rand1():
count_1:92 count_2:477 count_3:1017 count_4:1195 count_5:2264 count_6:4955
总体感觉 get_rand1() 更准确些……

5分钟快速实现一个哈希表(Clang)

哈希表(Hash table,也叫散列表),是根据键(Key)而直接访问在内存存储位置的数据结构。 也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。 这个映射函数称做散列函数,存放记录的数组称做散列表。 ————维基百科

在一些合理的假设下,在哈希表中的所有操作的时间复杂度可以简单看作O(1) 。它通过计算一个键的哈希值来快速定位键值在哈希表的位置。 实现一个好的哈希表的关键是一个好的哈希算法与一个处理哈希冲突的方法 。常见的简单哈希算法有BKDRHash,APHash,DJBHash,JSHash,RSHash.较复杂有MD5和SHA1之流。哈希算法的好坏直接影响哈希表存取的效率。 而处理哈希冲突的办法有开放寻址法与拉链法。下面示例使用的是拉链法

BKDRHash哈希算法

上述多个哈希算法中 BKDRHash在效率,平衡,均匀分布方面表现突出,并且它的实现也是最容易理解与记忆的。实现如下:

/**  * BKDR hash function in clang * @param key char* 字符串 * @return int hashed value, we will get a int value */int bkdrHash( char *key ){    uint seed = 131;//i can be 13, 131, 1313,131313 etc    uint hash = 0;    while( *key != ‘\n’ && *key != 0 )    {            hash = hash * seed + ( *key++ );    }    return ( hash & 0x7FFFFFFF );}

哈希表(拉链法处理冲突)

示意图:(图片来源:http://blog.csdn.net/v_JULY_v/article/details/6256463)

上图中,左则是一个数组,保存的是每个单向链表的头指针。实际的值就存储在链表中

单向链表中的节点的数据结构与数组定义代码

/** 单向链表的节点的结构体 */typedef struct _htItem{        struct _htItem  *next;        char *key_string;        uint fid;} htItem;/** 取得Key在数组中的映射位置 */uint htIndex( char *key, htItem **ht ){        uint hashedKey = bkdrHash( key );        uint length = (ht[0]->fid-1);        return (uint)hashedKey % length+1;}/** 定义数组 */htItem *item[21]; //为方便后台实现,在定义在数组的时候,我们给多一个长度,第一个数据不存储数据,只存放数组长度,剩余的元素空间

初始化数组元素

/** 有必要对数组元素进行一次0 初始化 */void htInit( htItem **ht, uint length ){         int i;         for( i=0; i<length; i++ ){                 ht[i] = (htItem*)malloc(sizeof(htItem));                  memset( ht[i], 0, sizeof(htItem) );         }         ht[0]->fid = length;}

数据的插入和更新

首先通过哈希函数找到Key对应在数组中的位置,再遍历链表,如果在链表中查到相同的key,就直接把该节点的数据更新,否则malloC一个节点,并把节点放到链表末尾。

/** set hashTable element */uint htSet( char *key, uint fid,  htItem **ht ){         uint i = htIndex( key, ht );         htItem *item = ht[i];         while( item->next )         {                  if( strcmp(key, item->next->key_string) == 0 ){                          item->next->fid = fid;                          return 0;                 }else{                          item = item->next;                 }         }         item->next = (htItem*)malloc(sizeof(htItem));         item->next->fid = fid;         item->next->key_string = key;         return 0;}

获取数据

首先通过哈希函数定位KEY在数组中的位置,再依次对比KEY值,如果命中就返回相应的值,否则返回空值

/** get hashTable elements */htItem* htGet( char *key, htItem **ht ){        uint i = htIndex( key, ht);        htItem *item = ht[i]->next;         htItem *tmp = (htItem*)malloc(sizeof(htItem));         memset(tmp, 0, sizeof(htItem));        while( item )        {                if( strcmp(key, item->key_string) == 0 ){                          printf(“hiting %s\n”, key);                          tmp->fid = item->fid;                          tmp->key_string = item->key_string;                        return tmp;                }                 item = item->next;        }        return;}

删除数据

/** delete one element of hashtable */int htDel(char *key, htItem **ht){        uint i = htIndex(key, ht);        htItem *item = ht[i];        while(item->next){                if(strcmp(key, item->next->key_string) == 0 ){                        htItem *tmp = item->next;                        item->next = tmp->next;                        free(tmp);                        return 0;                }                item = item->next;        }        return -1;}

打印完整hashtable中的元素

void print_hashTable( htItem **ht ){        uint length = ht[0]->fid;        uint i;        htItem *item;        for( i = 1; i < length; i++ )        {                item = ht[i]->next;                while(item)                {                        printf(“%s => %d\n”,item->key_string, item->fid);                        item = item->next;                }        }}

简单几个方法就实现了哈希表的增删查改。

使用示例

/** 定义与初始化 */    htItem *item[101];          htInit(item, 101);                  /** 添加元素 */         htSet(“longmon”,100,item);          htSet(“natalie”, 1000,item);         htSet(“xiaoqiong”,99, item);                  /** 打印 */         print_hashTable(item);                  /** 删除一个元素 */         htDel(“natalie”, item);                  /** 打印 */         print_hashTable(item);                  /** 获取keylongmon的值 */         htItem *tmpitem = htGet(“longmon”, item);                   /** 打印 */         printf(“key: %s => val:%d\n”, tmpitem->key_string, tmpitem->fid);

输出结果

#打印 xiaoqiong => 99natalie => 1000longmon => 100#打印 xiaoqiong => 99longmon => 100#打印 Key: longmon => val: 100

完整代码 https://github.com/longmon/hashTable_in_c

哈希表是PHP内核的基石。

PHP内核中的哈希表是十分重要的数据结构,PHP的大部分的语言特性都是基于哈希表实现的, 例如:变量的作用域、函数表、类的属性、方法等,Zend引擎内部的很多数据都是保存在哈希表中的。而PHP内核中的哈希表处理冲突使用的也是拉链法。

扩展阅读:

centOS和unbutu下安装php-ssh2扩展

centOS和unbutu下安装php-ssh2扩展的方法大致相同,但要繁琐一些。

1.安装支持的库文件

命令:yum install  php-devel php-pear libssh2 libssh2-devel

2.建立ssh2扩展

命令:pecl install -f ssh2

之后会显示安装的日志,需要选择时直接按回车键就好

3.安装成功后,需要修改ssh2.ini

[root@wcc etc]# touch /etc/php.d/ssh2.ini

[root@wcc etc]# echo extension=ssh2.so > /etc/php.d/ssh2.ini

可以用vim打开/etc/php.d/ssh2.ini 确认是否已经包含extension=ssh2.so

4.验证是否安装成功

php -m | grep ssh2

显示ssh2则表示安装成功

centos安装php-soap拓展

php有两个扩展可以实现web service,一个是NuSoap,一个是php 官方的soap扩展,由于soap是官方的,使用的人更多,所以项目中也是用的soap

1、安装soap

#yum install php-soap -y

2、php加载soap扩展
#vi /etc/php.d/soap.ini
extension=”soap.so”
#:wq! #保存退出

3、重新加载php-fpm
#service php-fpm reload
如果是apache 则 #service httpd restart

js 时间戳转为日期格式

什么是Unix时间戳(Unix timestamp): Unix时间戳(Unix timestamp),或称Unix时间(Unix time)、POSIX时间(POSIX time),是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数。Unix时间戳不仅被使用在Unix系统、类Unix系统中,也在许多其他操作系统中被广泛采用。

继续阅读“js 时间戳转为日期格式”