技术手记

买了套金山词霸2009专业版

今天发布的, 看了看牛津版和专业版对我而言没区别, 那些牛津词典我也用不着, 我只要能有计算机和电子词汇就可以了, 刚好我不知道啥时候注册的一个金山词霸通行证居然还能用, so, 在线买了一套, 只是大部分词典还需要去下载, 比实体店买的还是便宜了 50, 下词典么… 找个时间全 down 下来好了 

电脑上软件正版化计划继续中, 下一步, 考虑买套 Office2007 学生与家庭版, 199 米, 卓越, 当当等地均有卖的, 已经购买的有卡巴斯基 2009, 金山词霸 2009, 通过微软学生计划拿到了 Visual Studio 2008 Pro 的授权 
然后电脑上还有以下盗版软件等待去除 UltraEdit(貌似我就是拿来看二进制文件的, 不打算用了, 替代品应该还是挺多的), ACDSee(拿 Picasa 来替代), FireWorks(我用到的功能完全可以用 Picasa 替代), WinRAR(用 7zip 来替代) 
目前还不得不用盗版的有 FlashFXP(这个, 可以不用么? 貌似可以的, 直接浏览器上吧, 要上传的除了 BBS 其他都可以 SecureCRT 搞定的, 或者免费的 FTP 软件也还是有吧?), SecureCRT(这个, 用 PuTTy 太郁闷了, 还是继续盗版吧, 我就是在 b 公司学会用这个的)

通过 DreamSpark 申请正版微软软件(欢迎分享, 拒绝商业目的使用)

微软全球范围内对学生的一个优惠, 可以免费使用以下收费软件
Visual Studio 2008 Professional Edition
Windows Server 2008 Standard Edition
SQL Server 2008 Developer
Expression Studio 2008
XNA Game Studio 2.0
XNA Creators Club Online
IT ACADEMY STUDENT PASS
Visual Studio 2005 Professional Edition

本来免费的那些 Express 版当然也可以直接免费下载和使用, 下面是获取方法, 请各位同学申请到序列号后严格遵守许可协议, 只是自己学习研究使用, 不要散播, 特别是不要用于商业目的, 曾经有人在 taobao 上叫卖序列号, 现在那个学校的所有邮箱都被封杀了

以下是申请 DreamSpark 的流程, 建议全部在 IE 中完成, 并通过校园网使用俱乐部代理或直接在实验室网络进行, 不然网页显示或者相应认证可能会有问题, 直接用宿舍网很多页面慢的刷不开, 电信的会提示 IP 范围不对

1. 去 http://mail.whu.edu.cn 注册个武大的邮箱, 曾经有外面的可以免费注册的, 但是已经被封杀了, 别的学校同学请用自己学校的 edu.cn 结尾的邮箱
2. 登录 http://www.msuniversity.edu.cn, 在导航栏上选 “软件下载”, 或选子菜单中的 “DreamSpark微软学生软件资源”, 点页面最下面的 “点击进入”, 右边的介绍链接都无效
3. 在新页面中选 “此处” 开始注册和验证, 注册过程略
4. 注册完成后, 选进行学生身份验证, 发一封邮件到邮箱, 同意许可后进入激活页面
5. 复制邮箱里很长的一个验证码去激活, 会得到确认消息, 然后去 “进入下载”
6. 现在看到的页面就是收费软件的下载页面了, 速度能上 1.5M, 在迅雷上或者哪里随便下一个也一样, 软件介质没问题, 我们只是要正版授权而已
7. 在自己需要的产品中选 “申请 Product Key 激活软件”, 新页面中选 “Sign in”
8. 用自己的 Live ID 登录, 就是平时登录 WLM(MSN) 用的那个, 如果没有, 去注册个, 或者去把前面那个 mail.whu.edu.cn 的邮箱注册成 Live Passport, 在 www.live.cn 完成即可, 很快, 那个那个图片验证码很有点 xxoo, 我换了几个才找到个认识的
9. 接下来出来的地图上选 Asia, 右边下拉框选 China, 然后选 China-CERNET, 点 “Select and Continue”
10. 弹出来的对话框输 mail.whu.edu.cn 的邮箱名, 就是 4 里用的那个邮箱, 密码是步骤 5 里面那个巨长的验证码, 直接拷贝粘贴
11. 自此完成验证过程, 回到 6, 或者重新回到 2 登录进入 http://www.msuniversity.edu.cn/m_Directdownload/download.aspx, 点 “申请 Product Key 激活软件”, 出来页面中勾选同意许可协议, 最下面会出来一个 “Get Key” 的按钮, 点之获取我们需要的序列号

完成, 如果通过验证后, 第 7 步后会直接跳到 11, 就是说 8, 9, 10 都是只用做一次的

终于看到了 Chrome 的鬼脸

不过依然没看到崩溃的那个笑脸

看到鬼脸的方法(不知道别人那是不是可以):
g.cn/music 下随便打开一首歌试听, 在试听的标签(如果是独立窗口, 左上角按钮使其为标签, 此步骤不一定必须) 中开启 JavaScript 控制台, 地址栏右边那个按钮 > 开发人员 里找, 等一会, 就有鬼脸了

Google Chrome 的不爽和疑似 bugs

我向来是个喜欢找毛病的人, 所以, 原谅我的欢呼一起加入挑刺行列吧, 这样才能使 Chrome 更好

1. 不能用 Google Toolbar
直接导致上 Gmail/Reader/Calendar 等服务要手动输网址了, 也没法实时看到是否有新邮件/新订阅等, 本来为随处使用方便而保持在 Google Bookmarks 上的收藏, 现在似乎也算废了
某个评测上说可以加按钮, 不过我还没找到方法, 会了的人请告诉我下, 按钮应该是跟在 Toolbar 上加按钮那样, 如果是桌面快捷方式, 那还是算了

2. 标题栏无法显示
过分简洁的后果, 只有标签栏, 标题栏就显示不全了, 遇到一些恶心的网站标题都用网站前缀, 打开页面多了就分不清了, 不但非得鼠标移上去一个一个看, 当前这个也不知道是什么

3. 太靠上的标签栏
不知道有多少人跟我一样习惯把 QQ 自动缩在屏幕上边靠右, 切换标签栏时经常鼠标扫过去 QQ 就出来了 :( 上边靠左的估计更明显

4. Flash 显示问题?
在 g.cn/music 随便打开一个歌, 弹出来的窗口终于有完整的标题栏, 但是下面那个 Flash 广告呢? 广告都没了 Google 赚什么钱, 怎么跟 Top100 分成? (做广告做出来的职业病, sorry)

5. 好玩的网银
一开始就没指望能用, 不过很神奇的是建行的三个输入框都能输入, 并且输密码时还跳软键盘出来了


欢迎大家继续, 有人说跟 Norton 冲突, 会不停崩溃, 不过好像我还没崩溃过一次, 很想看看那个笑脸呢, about:internets 那个彩蛋不好玩, 就是 Windows 屏保

快排qsort的用法详解 (两年前的原创)

发信人: snoopy (阿排/好好玩ICPC~), 信区: ACM_ICPC
标 题: 快排qsort的用法详解
发信站: 珞珈山水BBS站 (Sat Apr 29 21:02:35 2006), 转信

很多人问这个东西.我以前也看了好久,今天翻到以前学快排的时候写的练习code,基本上
能覆盖绝大部分用法了.

里面有很多地方没判断相等的情况,按道理来说相等情况下应该返回0的,这个请看代码的
时候注意.我尽量保证代码不出错了.

下面的这些说明和问题都是个人原创,没查什么资料,所以不保证其完全正确性,在此表示个
人不对出现的问题负任何责任,大家WA了或者干吗的不要怪我,不过至少目前来说我用起来
是没问题的 :)

/*—————————————————————————-*/

** 关于快排函数的一些说明 **

qsort,包含在stdlib.h头文件里,函数一共四个参数,没返回值.一个典型的qsort的写法如下

qsort(s,n,sizeof(s[0]),cmp);

其中第一个参数是参与排序的数组名(或者也可以理解成开始排序的地址,因为可以写&s[i]
这样的表达式,这个问题下面有说明); 第二个参数是参与排序的元素个数; 第三个三数是
单个元素的大小,推荐使用sizeof(s[0])这样的表达式,下面也有说明 :) ;第四个参数就是
很多人觉得非常困惑的比较函数啦,关于这个函数,还要说的比较麻烦…

我们来讨论cmp这个比较函数(写成cmp是我的个人喜好,你可以随便写成什么,比如qcmp什么
的).典型的cmp的定义是

int cmp(const void *a,const void *b);

返回值必须是int,两个参数的类型必须都是const void *,那个a,b是我随便写的,个人喜好.
假设是对int排序的话,如果是升序,那么就是如果a比b大返回一个正值,小则负值,相等返回
0,其他的依次类推,后面有例子来说明对不同的类型如何进行排序.

在函数体内要对a,b进行强制类型转换后才能得到正确的返回值,不同的类型有不同的处理
方法.具体情况请参考后面的例子.

/*—————————————————————————-*/

** 关于快排的一些小问题 **

1.快排是不稳定的,这个不稳定一个表现在其使用的时间是不确定的,最好情况(O(n))和最
坏情况(O(n^2))差距太大,我们一般说的O(nlog(n))都是指的是其平均时间.

2.快排是不稳定的,这个不稳定表现在如果相同的比较元素,可能顺序不一样,假设我们有
这样一个序列,3,3,3,但是这三个3是有区别的,我们标记为3a,3b,3c,快排后的结果不一定
就是3a,3b,3c这样的排列,所以在某些特定场合我们要用结构体来使其稳定(No.6的例子就
是说明这个问题的)

3.快排的比较函数的两个参数必须都是const void *的,这个要特别注意,写a和b只是我的
个人喜好,写成cmp也只是我的个人喜好.推荐在cmp里面重新定义两个指针来强制类型转换,
特别是在对结构体进行排序的时候

4.快排qsort的第三个参数,那个sizeof,推荐是使用sizeof(s[0])这样,特别是对结构体,
往往自己定义2*sizeof(int)这样的会出问题,用sizeof(s[0)既方便又保险

5.如果要对数组进行部分排序,比如对一个s[n]的数组排列其从s[i]开始的m个元素,只需要
在第一个和第二个参数上进行一些修改:qsort(&s[i],m,sizeof(s[i]),cmp);

/*—————————————————————————-*/

** 标程,举例说明 **

No.1.手工实现QuickSort

#include <stdio.h>

int a[100],n,temp;

void QuickSort(int h,int t)
{
     if(h>=t) return;
     int mid=(h+t)/2,i=h,j=t,x;
     x=a[mid];
     while(1)
     {
         while(a[i]<x) i++;
         while(a[j]>x) j--;
         if(i>=j) break;
         temp=a[i];
         a[i]=a[j];
         a[j]=temp;
     }
     a[mid]=a[j];
     a[j]=x;
     QuickSort(h,j-1);
     QuickSort(j+1,t);
     return;
}

int main()
{
     int i;
     scanf("%d",&n);
     for(i=0;i<n;i++) scanf("%d",&a[i]);
     QuickSort(0,n-1);
     for(i=0;i<n;i++) printf("%d ",a[i]);

     return(0);
}

No.2.最常见的,对int数组排序

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

int s[10000],n,i;

int cmp(const void *a, const void *b)
{
     return(*(int *)a-*(int *)b);
}

int main()
{
     scanf("%d",&n);
     for(i=0;i<n;i++) scanf("%d",&s[i]);
    
     qsort(s,n,sizeof(s[0]),cmp);
    
     for(i=0;i<n;i++) printf("%d ",s[i]);
    
     return(0);
}

No.3.对double型数组排序,原理同int

这里做个注释,本来是因为要判断如果a==b返回0的,但是严格来说,两个double数是不可能相等的,只能说fabs(a-b)<1e-20之类的这样来判断,所以这里只返回了1和-1 [code lang="c"]#include <stdio.h> #include <stdlib.h> double s[1000]; int i,n; int cmp(const void * a, const void * b) { return((*(double*)a-*(double*)b>0)?1:-1); } int main() { scanf("%d",&n); for(i=0;i<n;i++) scanf("%lf",&s[i]); qsort(s,n,sizeof(s[0]),cmp); for(i=0;i<n;i++) printf("%lf ",s[i]); return(0); } [/code] No.4.对一个字符数组排序.原理同int [code lang="c"]#include <stdio.h> #include <string.h> #include <stdlib.h> char s[10000],i,n; int cmp(const void *a,const void *b) { return(*(char *)a-*(char *)b); } int main() { scanf("%s",s); n=strlen(s); qsort(s,n,sizeof(s[0]),cmp); printf("%s",s); return(0); }[/code] No.5.对结构体排序 注释一下.很多时候我们都会对结构体排序,比如校赛预选赛的那个樱花,一般这个时候都在 cmp函数里面先强制转换了类型,不要在return里面转,我也说不清为什么,但是这样程序会 更清晰,并且绝对是没错的. 这里同样请注意double返回0的问题 [code lang="c"]#include <stdio.h> #include <stdlib.h> struct node { double date1; int no; } s[100]; int i,n; int cmp(const void *a,const void *b) { struct node *aa=(node *)a; struct node *bb=(node *)b; return(((aa->date1)>(bb->date1))?1:-1); } int main() { scanf("%d",&n); for(i=0;i<n;i++) { s[i].no=i+1; scanf("%lf",&s[i].date1); } qsort(s,n,sizeof(s[0]),cmp); for(i=0;i<n;i++) printf("%d %lfn",s[i].no,s[i].date1); return(0); }[/code] No.6.对结构体排序.加入no来使其稳定(即data值相等的情况下按原来的顺序排) [code lang="c"]#include <stdio.h> #include <stdlib.h> struct node { double date1; int no; } s[100]; int i,n; int cmp(const void *a,const void *b) { struct node *aa=(node *)a; struct node *bb=(node *)b; if(aa->date1!=bb->date1) return(((aa->date1)>(bb->date1))?1:-1); else return((aa->no)-(bb->no)); } int main() { scanf("%d",&n); for(i=0;i<n;i++) { s[i].no=i+1; scanf("%lf",&s[i].date1); } qsort(s,n,sizeof(s[0]),cmp); for(i=0;i<n;i++) printf("%d %lfn",s[i].no,s[i].date1); return(0); } [/code] No.7.对字符串数组的排序(char s[][]型) [code lang="c"]#include <stdio.h> #include <string.h> #include <stdlib.h> char s[100][100]; int i,n; int cmp(const void *a,const void *b) { return(strcmp((char*)a,(char*)b)); } int main() { scanf("%d",&n); for(i=0;i<n;i++) scanf("%s",s[i]); qsort(s,n,sizeof(s[0]),cmp); for(i=0;i<n;i++) printf("%sn",s[i]); return(0); }[/code] No.8.对字符串数组排序(char *s[]型) [code lang="c"]#include <stdio.h> #include <string.h> #include <stdlib.h> char *s[100]; int i,n; int cmp(const void *a,const void *b) { return(strcmp(*(char**)a,*(char**)b)); } int main() { scanf("%d",&n); for(i=0;i<n;i++) { s[i]=(char*)malloc(sizeof(char*)); scanf("%s",s[i]); } qsort(s,n,sizeof(s[0]),cmp); for(i=0;i<n;i++) printf("%sn",s[i]); return(0); }[/code]

彻底被 SUN 打败了

本来预计的是在该死的闹晕会前将整个 BBS 系统从目前的 Solaris 9 + smth1.2 大改版迁移到 Ubuntu 8.04 + KBS2.0, 然后幸福又快乐的回家, 结果在我顽强的将二进制文件进行高低位转换和系统测试几近完成后, 发现原来 Ubuntu 8.04 没有像原来一样发布 for SPARC 的 server 版, 囧一
看了看支持时间的 deadline, 能用的从 6.06 到 7.10, 都还有 for SPARC, 想改用 6.06, 因为支持到 2011-9, 反正系统只要能跑就行了, 其他的东西都是我自己编译的, 接着在 ubuntu 的技术论坛以及水木上的反馈结果彻底让我无语了, 没有任何在同型号机器上安装 Linux 系统成功的. 那个该死的 SUN Fire V880 小型机居然还是个很不错的机器, 国外一年前还说要 40K$+, 我怎么就没看出来呢, x86/x64 架构的 10K$ 的都能用的爽很多好吧, 试过的哥们都是说挂, 连 Debian 都装不上去, 一个是因为 UltraSPARC III 的 CPU 貌似很高端?(900MHz 的 RISC 架构, 貌似性能还不落伍), 再有就是 SUN 奇怪的引导方式, Ubuntu/Debian 的光盘丢进去都没反应
再囧的就是那个诡异的高低位优先的问题, 由于伟大的 SPARC 架构采用了高位优先的方式, 从而 BBS 系统自定义的文件在 fwrite 到硬盘上后, struct 里所有的多字节类型(绝大部分是 int) 顺序与 x86/x64 的顺序不一样了, 而测试机又只能是 x86 的微机, 因为伟大的 SUN 的小型机还是相当值钱的, 弄不到来测试(据说 Linux 没法支持好点的 SUN 的机器也是因为开源社区没钱买来研究 -.-), 所以… 所以… 所有的文件都自己写程序手工转一次, 不过还好, struct 的定义都比较集中, 那么多文件自己看了这么久也有个大概认识, 程序写起来容易, 跑么, 反正是机器跑, 挂那里跑上几个小时就是了, 不就是几十 G 的数据么. 但是后来突然意识到, 这个优先是 CPU 架构决定的而不是操作系统决定的, 就算我成功在 SUN 的小型机上搞定了 Linux, 磁盘上的文件还是可用的, 我就是为了测试而转了半天, 其实都不用这么麻烦
找 SUN 对 SPARC 的支持, 最新的 Solaris 似乎都只有 for x86/x64 的, 难道 SUN 不出小型机了? 还是觉得 Solaris 10 就够了? 这个, 我都不敢去装, 在实验室每次装 Solaris 几乎都是一部血泪史, 并且那个系统让我用的实在太不爽了, 以致我每次被虐待后都会狠狠的告诫周围的人, Solaris 是这个世界上最不爽的操作系统, 没有之一

oh yeah~ 准备提前回家, 享受我的暑假, 老爸老妈看闹晕会, 我刚好占网络学做 Dev

我不想玩校内应用

还烦请大家不要一遍一遍的给我发邀请了, 很多我都是看过, 但是觉得没兴趣后卸载了的

PS. 校内有很多地方做的一点也不厚道, 比如好友买卖, 没安装应用的人为什么也可以被他人买卖并调戏呢? 这是一个需要参与的游戏, 没参与的人强行被拉进去, 有毛病
PS2. 如果大家真的无聊, 帮我看代码转文件吧, SUN 出的欠 SUN 的 Solaris 是这个世界上让人最不爽的操作系统, 没有之一

vimrc 配置文件

这玩意儿可长可短, 但是这些一般还是必须的了, 过了这么久, update 下自己的默认设置. ” 后是注释

set nocompatible " 非 vi 兼容模式
syntax on " 色彩高亮
set number " 显示行数
set ruler " 显示当前位置于右下角
set backspace=2 " 设置 backspace 模式为标准
set showmatch " 显示配对括号
set incsearch " 增量查找
set ai " 自动缩进
set si " 智能缩进
set cindent " C 风格缩进
set tabstop=2 " Tab 宽度
set softtabstop=2 " Tab 宽度
set shiftwidth=2 " Tab 宽度
set expandtab " 输入的 tab(t) 均转换为对应宽度个空格, 在 Makefile 等必须是 t 的文件中会保持是 tab
set nowrap " 不要跨行
set smarttab " 智能 tab
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,sjis,euc-kr,ucs-2le,latin1 "字符编码
set statusline=%F%m%r%h%w [FORMAT=%{&ff}] [TYPE=%Y] [ASCII=%03.3b] [HEX=%02.2B] [POS=%04l,%04v][%p%%] [LEN=%L] " 状态栏格式
set laststatus=2 " 一直显示状态栏
" 插入模式切换
map <F9> :set paste!<BAr>set paste?<CR>

如果需要在 Linux 里将 vim 做默认编辑器, 在 /etc/environment 里加入下面一行
EDITOR="/usr/bin/vim"

终端下进行 Linux 的 IP 设置和 DNS 设置

最近装 Ubuntu-server, 一开始都是设置网络, 也就是这里麻烦点, 只要网络设置好, 其他的都可以 ssh 上去操作, 很方便. 下面的修改均基于本地, 请根据各人的实际情况修改其中参数值

设置 IP
修改 /etc/network/interfaces
配置文件如下

# 自动启动 lo(loopback, 用于 localhost 和 127.0.0.1)
auto lo
iface lo inet loopback</code>

# 自动启动 eth0
auto eth0
# 设置为静态 IP 地址于 eth0 上
iface eth0 inet static
# IP 地址
address 192.168.5.187
# 子网掩码
netmask 255.255.0.0
# 默认网关
gateway 192.168.5.1 

最后用执行 /etc/init.d/networking restart 来重启网络应用设置

设置 DNS
修改 /etc/resolv.conf
配置文件如下

# DNS 1 的地址
nameserver 202.114.112.13
# DNS 2 的地址
nameserver 202.114.64.2

配好了后就可以直接在任何地方登录啦, 装好 Ubuntu 后当然是要更新 source.list, 这样才能安装软件和获取更新

sudo vim /etc/apt/source.list, 编辑前可以先备份下, 删掉里面原来所有的内容后加入我用的 ustc 的源:

deb http://debian.ustc.edu.cn/ubuntu/ hardy main restricted universe multiverse
deb http://debian.ustc.edu.cn/ubuntu/ hardy-backports restricted universe multiverse
deb http://debian.ustc.edu.cn/ubuntu/ hardy-proposed main restricted universe multiverse
deb http://debian.ustc.edu.cn/ubuntu/ hardy-security main restricted universe multiverse
deb http://debian.ustc.edu.cn/ubuntu/ hardy-updates main restricted universe multiverse
deb-src http://debian.ustc.edu.cn/ubuntu/ hardy main restricted universe multiverse
deb-src http://debian.ustc.edu.cn/ubuntu/ hardy-backports main restricted universe multiverse
deb-src http://debian.ustc.edu.cn/ubuntu/ hardy-proposed main restricted universe multiverse
deb-src http://debian.ustc.edu.cn/ubuntu/ hardy-security main restricted universe multiverse
deb-src http://debian.ustc.edu.cn/ubuntu/ hardy-updates main restricted universe multiverse

然后更新系统和安装最基本的软件:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install vim
sudo apt-get install gcc
sudo apt-get install g++
sudo apt-get install subversion