Oct 22

灵魂守恒定律 不指定

felix021 @ 2010-10-22 23:54 [IT » 程序设计] 评论(2) , 引用(0) , 阅读(8550) | Via 本站原创
一切都是从,那道蚂蚁题,开始的
那题中的蚂蚁有20只,爬在长的木棒一根
左边蚂蚁10只向右爬
右边蚂蚁10只向左爬
蚂蚁爬的速度都相同
一碰头各自原速调头
然后就问,这些个蚂蚁,要碰多少次头才会从木棒上都掉下去

一说起这个问题,可能很多人有看过编程之美4.7 蚂蚁爬杆的问题:有一根27厘米长的细长木杆,在第3厘米、7厘米、11厘米、17厘米、23厘米这五个位置 处各有一只蚂蚁。木杆很细,不能同时通过2只蚂蚁。开始时候,蚂蚁的头朝左还是朝右是任意的,他们只会朝前走或者掉头,但是不会后退。当任意2只蚂蚁碰头后时,2只蚂蚁会同时掉转头朝反方向走。架设蚂蚁每秒钟可以走一厘米的距离。编写程序,求所有蚂蚁都离开木杆的最短时间和最长时间。

留一些空间不剧透,有兴趣的同学可以先想想然后再往下看。
Sep 30
看了下百度百科对UTF-8的说明,随手写的,基本能用。

比较诡异的是本来UTF8getchar想用strncpy的,但是这个函数有坑....

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define alloc(type, size) ((type *)malloc(sizeof(type) * size))

struct UTF8char
{
    unsigned short length;
    char data[7];
};

unsigned UTF8getcharlen(const char *s)
{
    unsigned char t = (unsigned char) s[0];
    if (t < 0x80) //0xxx xxxx
        return 1;
    else if (t < 0xe0) //110x xxxx
        return 2;
    else if (t < 0xf0) //1110 xxxx
        return 3;
    else if (t < 0xf8) //1111 0xxx
        return 4;
    else if (t < 0xfc) //1111 10xx
        return 5;
    else if (t < 0xfe) //1111 110x
        return 6;
    else //0xff
        return 1;
}

int UTF8getchar(UTF8char *c, const char *s)
{
    int i;
    c->length = UTF8getcharlen(s);
    for (i = 0; i < c->length && s[i] != 0; i++)
        c->data[i] = s[i];
    c->data[i] = 0;
    return (i == c->length);
}

int UTF8cmp(const UTF8char *c, const char *s)
{
    return strncmp(c->data, s, c->length);
}

int main()
{
    char linebuf[4096];
    UTF8char c;

    scanf("%s", linebuf);

    int reti = UTF8getchar(&c, linebuf);
    assert(reti != 0);

    printf("%d %s\n", c.length, c.data);
    return 0;
}
Aug 21

程序员的浪漫 不指定

felix021 @ 2010-8-21 18:11 [IT » 程序设计] 评论(1) , 引用(0) , 阅读(7409) | Via 本站原创
dim arr(3)
arr(1)=-12590
arr(2)=-20306
arr(3)=-15133
str = ""
for i = 1 to 3
    str = str & chr(arr(i))
next
CreateObject("SAPI.SpVoice").Speak str
Aug 21

sdbm hash for PHP 不指定

felix021 @ 2010-8-21 01:59 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(5221) | Via 本站原创
上一篇提到了,使用sdbmhash来生成64bit摘要。这个算法,是需要用在PHP里头的,但是PHP在设计的时候有点囧,用于表示任意变量的 zval 这个struct里头,有一个union是用于存放不同数据类型的,而该union中用于表示整型的变量,就只有一个long。于是很杯具地:

1. 32bit OS下面的php只支持32bit整数
2. 不支持无符号整型

那个抑郁啊,于是只好用php的bcmath这个大整数库来实现上一篇的sdbmhash算法:
function sdbmhash($str)
{
    $mul = "65599"; // (1 << 6) + (1 << 16) - 1
    $mod = "18446744073709551616"; // 1 << 64

    $hash = "0";
    for ($i = 0; $i < strlen($str); ++$i)
    {
        $hash = bcmod(bcmul($hash, $mul), $mod);
        $hash = bcmod(bcadd($hash, ord($str{$i})), $mod);
    }
    return $hash;
}

大整数库是用字符串来模拟的,没有对位移的直接支持。于是刚开始的时候用 bcmul($hash, 1<<6) 之类来替代C实现中的位移;然后果断发现自己SB了,直接乘65599更合适。

当然了,由于是用字符串来模拟的,可以想象这段代码效率是很低的。但是有多低呢?在我的Ubuntu虚拟机上测试了一下,1w次对18个字符的hash需要大约2.4s,也就是说一次调用大约需要0.2~0.3ms。宿主机是windows(AMD M320, 2.1GHz),php的效率更低,大约花了3~4s。在同样的时间里,纯C实现,可以进行相同的运算10,000,000+次,效率比大约是PHP:C = 1:1000。

由于0.2~0.3ms这个数量级比较大了,于是决定把它写成一个PHP扩展。参照百度文库的这篇教程 http://wenku.baidu.com/view/044da6f8941ea76e58fa04b1.html 比较快就上手了。

最终实现的效率比是大约1:100。看来PHP的扩展开销还是很大啊。

记得前年曾经和@Sandy讨论过ASP、PHP、JSP的效率,他认为ASP和PHP在同一个数量级,和JSP差距很大(而我当初则认为PHP和JSP差距不大)。这个数据很好地证明了这一点。

最后,附上这个PHP扩展。
下载文件 (已下载 1554 次)
Aug 21
前两天在找个摘要算法,要求很简单,冲突少,生成64bit摘要;安全性可以忽略。MD5/SHA-1是好算法,但是它们生成的摘要是128/160bit的。Qining最初提出了个算法,将MD5的128bit分成4个32bit,d[0..3],然后通过以下公式获得64bit摘要:
引用
concat(d[0] XOR d[2], d[1] XOR d[3])
看起来挺有模有样的,但是用0..100,000去测试,发现了3个碰撞,毕竟没有数学理论的支持,胡搞还是不行的。另外再尝试了下,把MD5的前64bit拿出来,效果倒是好,前100,000没有碰撞。只是这种做法毕竟不让人放心,于是到网上搜了一下,发现不少人有此需求,但是没有现成的算法,挺无奈的。还好,有个人一语道破天机:用个字符串hash算法就行了。

于是翻出以前的一篇日志字符串的Hash,从里头把sdbm哈希函数搞出来,测试了一下(跑了好几分钟呢),效果很赞,一亿以内的整数都没有问题,代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <assert.h>
using namespace std;

typedef unsigned long long ull;

ull sdbmhash(const char *s){
    ull hash = 0;
    while (*s){
        hash = (hash << 6) + (hash << 16) - hash + *s++;
    }
    return hash;
}

int main()
{
    const unsigned N = 100000000;
    ull *all = new(nothrow) ull[N];
    assert(all != NULL);
    unsigned i = 0;
    char tmp[100];
    for (i = 1; i <= N; ++i)
    {
        snprintf(tmp, 100, "%09u", i);
        all[i] = sdbmhash(tmp);
        if (i % (N / 20) == 0) printf("i = %u\n", i);
    }
    sort(all, all + N);
    ull * end = unique(all, all + N);
    printf("%u\n", all + N - end);
    delete[] all;
    return 0;
}
Jul 29

在VC6.0下用GDI+画图 不指定

felix021 @ 2010-7-29 00:50 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(5501) | Via 本站原创
1. 下载gdi+的sdk,安装。当然,可以简化一点,从这里[ http://download.csdn.net/down/1645798/huohuo1120 ]下载gdiplus所需文件包,解压并导入到vc6(将include和lib目录加入vc6的配置中)

2. 在VC6中创建一个Win32 Application,选择“一个简单的Win32程序”。假设项目名是main

3. 在StdAfx.h中加入
#include <winbase.h>
#define UNICODE
#include <comdef.h>
#ifndef ULONG_PTR
#define ULONG_PTR unsigned long*
#include <GdiPlus.h>
using namespace Gdiplus;
#endif

4. 在main.cpp的WinMain前面生命全局的两个GDI变量
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR          gdiplusToken;

5. 在程序退出之前的地方加上
GdiplusShutdown(gdiplusToken);

6. 画图

6.1 创建一个Bitmap对象
Bitmap *pBitmap = new Bitmap(width, height, PixelFormat24bppRGB);

6.2 从Bitmap中获取Graphics对象
Graphics *g = Graphics::FromImage(pBitmap);

6.3 使用各种东西的组合来搞g,比如Pen, Brush, Region, Rect, PointF, Font……
Pen pen_black(Color(255, 0, 0, 0), 3);
g->DrawLine(&pen_black, 0, 0, 100, 100);
更具体的说明和各种例子可以在这里找到:GDI+ SDK参考(翻译版本) http://download.csdn.net/source/642128

7. 保存文件,这个比较麻烦
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
  UINT num= 0, size= 0;

  ImageCodecInfo* pImageCodecInfo= NULL;
  GetImageEncodersSize(&num, &size);
  if(size== 0)
    return -1;
  pImageCodecInfo= (ImageCodecInfo*)(malloc(size));
  if(pImageCodecInfo== NULL)
    return -1;

  GetImageEncoders(num, size, pImageCodecInfo);
  for(UINT j=0; j< num; ++j)
  {
    if(wcscmp(pImageCodecInfo[j].MimeType, format)== 0)
    {
      *pClsid= pImageCodecInfo[j].Clsid;
      free(pImageCodecInfo);
      return j;
    }
  }
  free(pImageCodecInfo);
  return -1;
}

......

CLSID encoder;
GetEncoderClsid(L"image/png", &encoder); // L"image/jpeg", ...
pb->Save(L"result.png", &encoder, NULL);
Jul 21

把字符串变成文件流 不指定

felix021 @ 2010-7-21 23:15 [IT » 程序设计] 评论(2) , 引用(0) , 阅读(8147) | Via 本站原创
0. int fd[2];
1. pipe(fd) 打开一个管道
2. fork或者pthread
3. 往fd[0]写字符串
4. 从fd[1]读取,或者可以fdopen(fd[1]),获得一个文件指针,读取文件。
Jun 28
对字符指针数组使用qsort排序时,strcmp强制类型转换后不能直接用于qsort, 需要进一步的纠结的。包装……
p.s. 对于字符串数组char a[100][100]; 就可以用strcmp。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef int (*cmp_func)(const void *, const void *);

int strcmp_for_qsort(const void *a, const void *b)
{
    char *x = *(char **)a, *y = *(char **)b;
    return strcmp(x, y);
}

void quicksort(void *p, int num, unsigned size, cmp_func cmp)
{
    int i, j;
    char *pos, *t = (char *) malloc(size);
    if (t == NULL) exit(1);
    for (i = 0; i < num; i++)
    {
        for (j = 0, pos = (char *)p; j < num - 1; j++, pos += size)
        {
            if (cmp(pos, pos + size) > 0)
            {
                memcpy(t, pos, size);
                memcpy(pos, pos + size, size);
                memcpy(pos + size, t, size);
            }
        }
    }
    free(t);
}

int main()
{
    char *pos[5] = {"a", "c", "e", "b", "d"};
    //qsort(pos, 5, sizeof(pos[0]), strcmp_for_qsort); // in stdlib
    quicksort(pos, 5, sizeof(pos[0]), strcmp_for_qsort); //fake
    for (int i = 0; i < 5; i++)
        puts(pos[i]);
    return 0;
}
分页: 7/23 第一页 上页 2 3 4 5 6 7 8 9 10 11 下页 最后页 [ 显示模式: 摘要 | 列表 ]