星期六, 九月 30, 2006

OpenLDAP报告

OpenLdap-2.3.24.tgz
install
su -l root
#tar -cvfz openldap-2.3.24.tgz
#cd openldap-2.3.24
#./configure
#make depend
#make
#make test
#make install
配置文件在目录/usr/local/etc/openldap/,ldapadd,ldapdelete,ldapmodify,ldapmodrdn, ldappasswd,ldapsearch 在目录/usr/local/bin,运行时数据库在/usr/local/var/openldap-ldbm
start...
#/usr/local/libexec/slapd
编辑/etc/profile,加入路径PATH="$PATH:/usr/X11R6/bin:/usr/local/bin:/usr/local/libexec
start test
#ps -ef | grep -i slapd | grep -v grep
#netstat -an | grep 389

星期三, 九月 27, 2006

javap反汇编器

javap反汇编器
  javap命令反汇编一个java字节代码文件, 返回有关可变部分和成员函数的信息,其命令行如下:
   C:\>javap options classname additionalClasses
  javap的标准输出是公有变量和类的成员函数。javap反汇编器的命令行选项如下表:

选项 功能
-h 此选项将建立能够放入C头文件中的信息
-p 此选项将使javap输出私有和公有的成员函数和变量
-c 此选项将使javap为各成员函数输出实际已编译过的字节代码
-classpath path 此选项将使得javap在路径path中寻找Java类
-v 输出所有的信息
-verify 运行校验器以验证并显示出调试信息
-version 输出javap的版本信息

一道编译题

int x = 4;
x+=x-=x-x--;
java:output 8 The King of Coding
jvm指令执行的顺序
public class b extends java.lang.Object{
public b();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return

public static void main(java.lang.String[]);
Code:
0: iconst_4 // 常量4压栈
1: istore_1 // 出栈, 并赋值给第一个变量, 也就是x
2: iload_1 // x压栈
3: iload_1 // x压栈
4: iload_1 // x压栈
5: iload_1 // x压栈
6: dup // 赋值栈顶元素, 并压栈
7: iconst_1 // 常量1压栈
8: isub // nexttop - top, 也就是(4-1), 并将结果(3)压栈
9: istore_1 // 3出栈, 赋值给x
10: isub // nexttop - top, 也就是(4-4), 并将结果(0)压栈
11: isub // nexttop - top, 也就是(4-0), 并将结果(4)压栈
12: dup // 赋值栈顶元素, 并压栈
13: istore_1 // 4出栈, 复制给x
14: iadd // nexttop + top, 也就是(4+4), 并将结果(8)压栈
15: istore_1 // 8出栈, 复制给x, 所以结果是8
16: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
19: iload_1
20: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
23: return
}
C++ Assemble Instruction
8: int x=4;
00401058 mov dword ptr [ebp-4],4
9: x+=x-=x-x--;
0040105F mov eax,dword ptr [ebp-4]
00401062 sub eax,dword ptr [ebp-4]
00401065 mov ecx,dword ptr [ebp-4]
00401068 sub ecx,eax
0040106A mov dword ptr [ebp-4],ecx
0040106D mov edx,dword ptr [ebp-4]
00401070 add edx,dword ptr [ebp-4]
00401073 mov dword ptr [ebp-4],edx
00401076 mov eax,dword ptr [ebp-4]
00401079 sub eax,1
0040107C mov dword ptr [ebp-4],eax
phenixsen's explanation
这是因为操作数的求值顺序不同而引起的问题,在《java解惑》的Puzzle 7: Swap Meat里也提到了这个问题:

It is guaranteed not to work in Java. The Java language specification says that operands of operators are evaluated from left to right [JLS 15.7]. To evaluate the expression x ^= expr, the value of x is sampled before expr is evaluated, and the exclusive OR of these two values is assigned to the variable x [JLS 15.26.2].

也就是说对于 ^= , +=, -= 这样的操作符,操作数是在右部表达式求值之前就确定的,所以实际上,我们可以把 x += expr, 写成是 x = x + expr, 更清楚一点就是 temp = x, x = temp + expr. 也就是说无论expr对x做了什么更改, 参与+运算的这个x的值是之前就确定的, 根据这样的方法, 可以把 x+=x-=x - x-- 写成:

temp1 = x; // temp1 = 4;
temp2 = x; // temp2 = 4;
temp3 = x; // temp3 = 4;
temp4 = x--; // temp4 = 4 , x = 3;
temp5 = temp3 - temp4; // temp5 = 0;
x = temp2 - temp5 // x = 4;
x = temp1 + x; // x = 8;

而在C/C++中, 操作数的求值顺序是没有规定的, 一般来说, c/c++在求值 x += expr这样的表达式时, 作为操作数的x的值是在计算完expr的值之后才进行抽取(sample)的, 这时候, expr对x的改变就会起作用了, 这样, x += expr 可以被写成是 temp1 = expr, temp2 = x, x = temp1 + temp2. 而 x += x -= x - x-- 的求值就是:
这里还要涉及到一个后缀++和--操作的问题,在C++里面,表达式里的这个++和--操作是在最后面来做的,而在java里面是在值被用到之前来做的。所以这里的
x+=x-=x-x--实际上的运算过程应该是:
x = 4; //x = 4;
temp1 = x; // temp1 = 4;
temp2 = x - temp1 // temp2 = 0;
temp3 = x - temp2; // temp3 = 4;
x = temp3; // x = 4;
temp5 = x + temp3; // temp5 = 8;
x = temp5; // x = 8;
x--; // x = 7;

可以验证一下这个结论,比如下面的程序:
int x = 4;
int j = (x++) + (x++);
在java里面,j最后是9, 而在c里面,j最后是8;

就是这样.

星期二, 九月 26, 2006

小崔的advice

(1)蛮力穷举法,可以说可以解决所有的问题,不过对于组合数很大的问题时间性能不是很好甚至不能忍受。例子:全排列的生成、n选m组合的生成(这两个的 蛮力法都可以利用多重嵌套循环形成,层次很壮观),8皇后问题(对应成8数全排列),12城tsp问题(对应成12数排列),a的n次方计算就老老实实连 乘n次a,顺序查找元素等都是蛮力穷举的例子。
(2)分治法,就是把1个大问题分成2个小问题,2个小问题还可以再分,直到问题规模小的可以简单解决。处理每个小问题,把处理结果汇总处理, 最后得到整个大问题的解。一般而言,分治法都要用到递归。例子:算n个数的和,可以算前一半n/2的和,后一半n/2的和,最后相加即得总和;凸包问题, 可以把最左边点和最右边点连线,右上边点集的凸包(叫做上包)和下面点集的凸包(叫做下包),最后把上包和下包合围起来就是整个凸包。点集的最小点对问 题,可以以一条线为界,分成左右两个集合,分别求最小点对,最后在合起来处理。分治法对多个处理器或处理机的并行计算特别适用。
(3)减治法,就是处理过程中问题规模不断减小的方法。最常见的就是折半查找,每次都把n/2个元素删去;减治法一半分为减1法,减常数法,减 可变规模法。减1法典型的就是插入排序,还有计算a的n次方,可以计算a的n-1次方,再变成计算a的n-2次方等等。想查找二叉树的查找都利用了减治的 思想。
(4)变治法,就是对问题进行变相,变化,利用已有的解决方案来解决生疏的问题,重点在于对原来的生疏问题进行转化,转变,使他变成一个已有好的解法的熟悉问题。
(5)时空权衡,考虑时间和空间的相互转化,有时利用空间换时间,有时利用时间换空间,常用的就是 计数排序(多利用了一个计数数组),散列法,B树。
(6)动态规划,也是时空权衡的一种,把可重复的问题的解保存在一个表里面。例子包括 计算二项式系数,最有二叉查找树,背包问题和记忆功能。
(7)贪婪算法,就是每一步都从可选方案中选择对该步最有利的方案,直到问题解决。贪婪法有可能得不到问题的最优解,不过得到的解一般都很接近问题的最优解。它的优点就是效率高,时间复杂性相对有那些得到最优解的算法快很多。常用的例子:
最小生成树的prim算法,kruskal算法,最短路径的dijkstra算法,解决tsp问题。
(8)回溯法
(9)分支限界法 (8)(9)很类似,回溯法基于深度优先搜索,而分支限界一般基于宽度优先搜索。

学了数据结构和算法,对一些思想大概了解,但还需要亲自实现实现,否则就只能侃侃而谈。
(1)数组,串的逆序生成,串匹配。
(2)链表的遍历,添加元素,删除元素。
(3)栈的实现。
(4)队列的实现。
(5)树的存储,建立,遍历,元素查找,平衡二叉树的添加、删除元素。
(6)图的2种存储方法和图算法的实现。
(7)常见查找方法的实现,最基本的顺序查找,折半查找。
(8)常见排序方法的实现,最基本的插入排序,冒泡排序,选择排序,技术排序,归并排序,堆排序,快速排序,希尔排序。
不妨先把上面的弄熟,再慢慢利用stl的标准容器和算法,当然追求迅速编程也可直接stl。
弄熟上面的是我们必须的,我也在努力。

(1)找零钱问题 (贪婪,最优解,编程应该很快).
(2)很快编一个 二分查找的程序.
(3)很快编一个 快速排序的程序.
(4)很快便一个 归并排序的程序.
(5)大数乘法 (分治法)
(6)利用(2)作为函数,实现 大数阶乘(纯属编程练习)
(7)二叉树的遍历(先序,后序,中序) (利用递归吧,递归练习,建立树后应该很快).
(8)平面最近点对问题(分治法,递归,学会分析问题)
(9)最小生成树,最短路径,拓扑排序(最基本的图论问题,贪婪算法)
(10)连续的背包问题(贪婪) 离散的0/1背包问题 (对子集树进行回溯)
(11)C(n,m)的计算(动态规划的最基本的例子)
(12)TSP问题(对排列树进行回溯)

推荐两本书: 算法设计与分析 潘彦 (译)
计算机算法设计与分析 王晓东 (其实很不错).

Study Plan

  • The Introduction to Algorithms
  • 算法设计与分析
  • 数据结构与算法分析
  • Java in a Nutshell
  • Understanding th linux Kernel
  • The Linux Kernel Developpment
  • C Primer
  • C++ Primer
  • Effective C++
  • Ajax In Action
  • Portal Related...
  • ......
  • topcoder,acm.pku,acm.zju

星期四, 九月 21, 2006

对话Google工程师

Google Engineer--王超,ACMer,Computer Science,ZJU Bachelor Of Science .

  1. Google的工程师很健谈,Google拥有一个很好的氛围,适合刚毕业的学生,公司很尊重学生的喜好和兴趣。
  2. Google重视数据结构和算法,尤其对ACMer很感兴趣。Google要求有一个很好的算法基础和GPA,学生要做好学生的本分。不要求你掌握了时髦的技术,不要求你做过很多工程项目,在Google这些永远不值一提。
  3. 。。。

对话Google

9.19号,作为为交大Google Camp筹备开营的一名Camper,亲身组织并见证了对话Google,对话Kaifu Lee。这里的“对话”是广义的,不仅仅是聆听与交流,更重要的是和Google的文化碰撞,或许Google会给我们一个启示。
Google是一个(人才和金钱富有)财富富有的公司,对用户一向很慷慨,对自身的宣传也自然是毫不含糊。这次开营活动宣传Google将之委托给广告公司,而我们的开销将不能超越预算,活动策划的相当盛大了,弥漫着Google特色的文化活动。下午是嘉年华游戏活动,这里有对学生免费供应的饮料和小吃,有富有情趣的6个游戏活动,参与即有奖加上Google特色的奖品,使我们的游戏异常火爆。我负责的Google Logo Quest我想应该是最有趣的节目了,男女皆宜,Google Camp T-Shirt的诱惑也很大。
晚上在宪梓堂的开营仪式暨李开复报告会也是广受各类Fans(Google fans or Lee's fans,...etc)的追捧,火爆异常,要命的是我们发出的入场券超过了宪梓堂的容量。我是负责照相的,基本上在宪梓堂窜来窜去。活动伊始是策划已久的“六人行”表演,六个人持有“Google”的不同字母和关键词,发挥自己的想象与创造编写自己的剧本,表演自己的话剧。开复的演讲水平真的很高,主题是“21世纪需要的7种人才”。作为一个演讲家,他能够举出身边的例子来说服我们,没有空洞的内容,也有作为学长和一个成功的计算机科学家对学习和职业规划的建议。他建议我们不要去追求一些时髦的语言,如果没有实在的项目就去开源社区去练习,这一点我颇赞同,我知道去年的一位XJTU Googler就是一个Open Souccer。有一点我不敢苟同的是Google的产品基本上不依赖市场调查,公司很尊重一些奇思异想,有一个idea然后有这些天才去开发,在通过用户的使用裁决产品的可用度。我觉得这样会忽视一些用户体验和用户习惯,虽然他们具有成功的人机界面设计的产品。
比较失望的是没有能够得到Kaifu Lee的签名,还有和kaifu的合影,只是用自己比较烂的视角拍下了一些照片,很暗,没有打开闪光灯。但这个夜晚无疑是成功的。

Google Camp

  • 9.19 四大发明广场 嘉年华游戏秀

  • 9.19 宪梓堂 Google Camp开营Kaifu lee演讲


星期一, 九月 18, 2006

数据挖掘中关联规则中求频繁项集的aprior算法[cser]


#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int SUPPORT=2;//最小支持度

//从各个事务的项集中得到数据库的所有单个项并对单项排序
vector<char> unique_item(const vector<vector<char> > & vvchar )
{
vector<char> cvec;
for(int i=0;i<vvchar.size();++i)
{
for(int j=0;j<vvchar[i].size();++j)
{
//找不到说明前面没有重复的单项
if(find(cvec.begin(),cvec.end(),vvchar[i][j])==cvec.end())
{
cvec.push_back(vvchar[i][j]);
}
}
}
sort(cvec.begin(),cvec.end());
return cvec;
}

//算出项集中每个项(包括单项)在总的事务集合中出现的次数(支持度)
vector<int> count_itemcollection(const vector<vector<char> > & vvchar,
const vector<vector<char> > & transction)
{
vector<int> ivec;
int count=0;
for(int i=0;i<vvchar.size();++i)//对每一个项集
{
for(int j=0;j<transction.size();++j)
{
for(int k=0;k<vvchar[i].size();++k)
{
//如果一个项在当前事务中找不到,其它的项也就不用再在当前事务中找
//直接在下一个事务中找
if(find(transction[j].begin(),transction[j].end(),vvchar[i][k])==transction[j].end())
{
break;
}
}

//当前项集的所有项都在当前事务中出现,计数加1
if(k==vvchar[i].size())
{
count++;
}
}
ivec.push_back(count);
count=0;
}
return ivec;
}

//从剪枝后的候选项选出频繁项集
vector<vector<char> > choose_freq(vector<vector<char> > & candidate_cut,
const vector<vector<char> > & transaction)
{
vector<vector<char> > freq;
vector<int> count=count_itemcollection(candidate_cut,transaction);
for(int i=0;i<count.size();++i)
{
if(count[i]>=SUPPORT)
{
freq.push_back(candidate_cut[i]);
}
}
return freq;
}

//把前一代的频繁项集连接生成下一代的候选项集
vector<vector<char> > connect_freq(const vector<vector<char> > & freq1,
const vector<vector<char> > & freq2)
{
vector<vector<char> > candidate;
for(int i=0;i<freq1.size();++i)
{
for(int j=0;j<freq2.size();++j)
{
for(int k=0;k<freq1[i].size()-1;++k)
{
if(freq1[i][k]!=freq2[j][k])
{
break;
}
}
//第一个项集的前n-1位都等于第二个项集的前n-1位
if (k==freq1[i].size()-1)
{
//同时,第一个项集的最后一项小于第二个项集的最后一项
if(freq1[i][k]<freq2[j][k])
{
vector<char> cvec;
//把第一个项集的全部项移入候选项
for(int m=0;m<freq1[i].size();++m)
{
cvec.push_back(freq1[i][m]);
}
//把第二个项集的最后一个项移入候选项
cvec.push_back(freq2[j][freq2[j].size()-1]);
//把候选项加入候选项集中
candidate.push_back(cvec);
}
}
}
}
return candidate;
}
void main()
{
//从事务文件中把各个事务写到vvchar中
ifstream input=ifstream("transction.txt");
vector< vector<char> > transaction;
if (input==0) //文件打开失败
{
cout<<"存放事务的文件transction不存在,请先手工建立"<<endl;
}
else
{
while(input)
{
string str;
getline(input,str,'\n'); //得到一行事务项集
if(str!="")//最后有一空行,所以在此用if消除
{
vector<char> cvec;
for(int i=0;i<str.size();++i)
{
cvec.push_back(str[i]);
}
transaction.push_back(cvec);
}
}
}
//对各个事务项集进行排序
for(int i=0;i<transaction.size();++i)
{
sort(transaction[i].begin(),transaction[i].end());
}
//取得各个单项并对单项排序
vector<char> cvec =unique_item(transaction);
vector<vector< vector<char> > >freq_results;//保存最后的频繁项集结果
vector< vector<char> > candidate;//各个代的候选项集
//候选项集开始初始化为单项集合
for(int j=0;j<cvec.size();++j)
{
vector<char> cvec_tmp;
cvec_tmp.push_back(cvec[j]);
candidate.push_back(cvec_tmp);
}
//开始迭代求频繁项集,直到候选项集为空为止
while(candidate.size()>0)
{
vector<vector<char> > freq_tmp=choose_freq(candidate,transaction);
freq_results.push_back(freq_tmp);//这一代的频繁项集加入结果集合中
candidate=connect_freq(freq_tmp,freq_tmp);
}
//输出所有的频繁项集
for(int l=0;l<freq_results.size();++l)
{
cout<<"含"<<l+1<<"个元素的频繁项集为:"<<endl;
for(int m=0;m<freq_results[l].size();++m)
{
for(int n=0;n<freq_results[l][m].size();++n)
{
cout<<freq_results[l][m][n]<<" ";
}
cout<<endl;
}
}
}

星期日, 九月 17, 2006

年轻的冲动

年轻,做什么事都不会去想结果。结果是到处碰壁,整天的郁闷。这个世界太复杂,真的不知道如何去适应。但你必须得适应,必须学会成长,只有你主动去适应和改变~。
年轻的成本很低,也很高昂。

星期六, 九月 16, 2006

RSS(真正简单聚合)

什么是RSS:
(Really Simple Syndication)是一种描述和同步网站内容的格式,是目前使用最广泛的XML应用,是站点用来和其他站点之间共享内容的一种简易方式(也叫聚合内容)。RSS可以是以下三种解释:(1)Really Simple Syndication;(2)RDF (Resource Description Framework) Site Summary;(3)Rich Site Summary,但其实这三个解释都是指同一种Syndication的技术。
实现RSS信息聚合
js code


/*定义建立装载XML数据的函数*/
function loadXML()
{
CreateXMLHttpRequest();
if(!xmlhttp)
{
document.getElementById("msg").innerHTML="对不起,服务器有故障,不能传送数据!";
return false;
}
else
{
xmlhttp.onreadystatechange=readXML;
URL="http://tbs.xjtu.edu.cn/feed.asp";
xmlhttp.open("post",URL,true);
xmlhttp.send(null);
}
}
/*定义建立解析XML数据的函数---------------------------------------------------------------开始*/
function readXML()
{
if(xmlhttp.readyState==4)
{
if(xmlhttp.status==200)
{
document.getElementById("msg").style.display="none";
//document.getElementById("msg").innerHTML="数据装载完毕!";
document.getElementById("data").innerHTML="";
var xmlDoc=xmlhttp.responseXML;
items=xmlDoc.getElementsByTagName("item");
for(i=0;i;<items.length;i++) urldata="'items[i].getElementsByTagName(" titledata="'items[i].getElementsByTagName(" descriptiondata="'items[i].getElementsByTagName(" datachild="'document.createElement(" datatext="document.createTextNode(titleData);" contenttext="document.createTextNode(descriptionData);" urlchild="'document.createElement(" contentchild="'document.createElement(" innerhtml="Loading...")'";
}}

星期三, 九月 13, 2006

回归梦想的轨迹


研究生生活算是已经三周了,自己却从未去认真地上过自习。或在看电子书,或在BBS上灌水,或在Gtalk,QQ上聊天,代码也很少写,心中总有犯罪的愧疚感。看看厚厚的红宝书只背了一个List,在实验室看不到一页就克制不住自己的堕落的欲望了。今天终于去上自来的第二次自习,居然忘了带笔,最后还是在寝室看了1个小时书。
发现不逼自己是不行的了。希望以后逐渐自觉去上自习看书,可能也有很多局限的因素,想看的书太贵,只有电子版。而计划中的笔记本到现在还没买(强烈谴责恶意欠我薪水者),希望快点好起来。计划中数据结构和算法是要优先考虑的,Java,C++,Linux的一系列经典的书籍。
其余的生活不知道怎么走,给老师做的事不大感兴趣,毕竟只是一些机械简单的劳动。Google Camp和IBM Club倒是有一些兴趣,去丰富一下自己的经历。。。