05高19班九周年聚会回忆录

春风疑不到天涯,二月山城未见花。这个,,其实山城还是有些梅花。

大年初四,一群05高19班的童鞋以及童鞋家属们风风火火的热闹了一把,探讨了诸如“雅玉十号”等历史性问题。

整个聚会历时1,2,3,4,,,好多个小时。具体就如下图所示啦,没有来的,接女朋友接男朋友迟到的,中途神秘消失一圈又回来的,以及早退的(本大秘书长第二天要送大学姐回娘家,错过了最后一个活动不算),个人看一哈错过了哪些,记账到下盘儿的十周年。错过一项罚一(到时候再说)。

图片1

回忆录就要有一个回忆的样子,其实整个过程是这样的:

寒假某日,收到班长短信。

IMG_8736

老板:“对啦,就是我啦!”

说九周年了,让组织一下聚会,顺便为十周年准备准备。

我想行啊,说来也有好久没见他们了,说干就干,讨论了一下时间、地点等问题,就开始宣传通知。

一路耍到KTV的时候,数了一哈,手头还剩下几十张大家交妮毛主席,想着啷个才能花出去。这里有大猫儿这个金牌vip,也花不了多少钱。

IMG_8753

大猫儿:“嘿嘿,大家好,对了对了,这个说的就是我了。”

老赖:“大猫儿上次穿起制服就来了,牛逼得很”

搭了一句话,又忙着低头思考他的长城去了,后天得给大红包,先补充补充弹药!

IMG_8746

有了!不是正好带了相机迈,把照片洗出来给每个人都快递一份儿,再整个相册,要是还剩得有,再用他们自己的照片弄一个喀嚓鱼创意杯,肯定就差不多了。

“达尔,把你的地址写一哈,隔天儿我照片洗出来了给你快递过来”

IMG_8830_0

“不干,你龟儿要给我邮递耗儿药”

“爬,耗儿药闹得住你不嘛,快点儿”

“Okay,,,Okay,,。咦?!老子的剪刀手涅?啷个照脱了”

IMG_8790_2

“遭耗儿啃老!”

“。。。”

“好,让我过去找陶小叉”

才几年不见,肥了岂止一圈儿两圈儿,当初的校草现在简直不堪入目,/乐一个, /乐一个。

IMG_8838

“你在说老子迈,还不是一样帅,懂不懂欣赏。”

“爬!”

“过来我跟你说,刚才我去重百看辣妹儿,越来越多老,还没看安逸斗喊我回来,不是说今天儿女生也要来迈?”

“勒里,须须来得最早,你看别个都生了娃儿了,身材还楞个好,而且皮肤比生之前还要好了样。”

IMG_8748_2

周小熊:“豆是豆是,我都发现了,我算了一哈,勒是生娃儿的时候体会激素达到了一种平衡,导致了吧啦吧啦吧啦…&%&……%@!(#@!*&x!$,,”

IMG_8737

“算个牙刷儿算,豆你算得出来,我们不是有医生迈,喊医生来分析一哈嘛”

IMG_8879

韩镇长:“不要看我,旁边的申大医生”

张飞:“来,把我跟申大医生放一起”

IMG_8785

雅玉十号:“咦?现在进入合照阶段了哇,不是说先介绍个人的迈?”

“勒张照片我实在不晓得啷个裁剪啊,就当张飞也一起show过了,先把你的整上来嘛”

“销魂一点儿的”

“Okay”

IMG_8856

“这张可以嘛?”

“不错不错,只是有点不过瘾儿,还有没得?”

“肯定有撒,勒里,还有一张”

IMG_8858

猪源:“也,聂不住,你勒两张有点儿张狂哟,小眼镜儿,看勒里,看勒里”

咔嚓咔嚓。。。

IMG_8832

肚皮:“哈哈哈,猪源你龟儿个面瘫,好鸡公傻,胡ka,我也,老子来得最早,还没有漏过脸,来一张特写。”

“好,马上,我找一哈,都有”

猪源:“莫要慌,莫要慌,不跟他龟儿单独照,我要跟我儿子合影一张!”

肚皮:“滚,是跟你爸爸合影”

“。。。他两个妮辈分,我是从高中到现在都还没搞清楚”

达尔:“扯不撑,扯不撑!不管勒些,猪源后天结婚,听他的,让他们两父子合影。哎呀,干脆我也来插一脚”

猪源:“对头,来,达尔,我们一个扯他龟儿一只猪耳朵!”

IMG_8836

王大血:“你们不要只晓得照男妮嘛,你看别个爱里芬好孤单”

IMG_8789

爱丽芬:“爬嘛你,你才孤单,来忧郁一个撒,王大血”

王大血:“好歹是从小遭勒到大的,每天必遭一勒,忧郁豆忧郁”

IMG_8851

罗大肛:“也,表演有点儿到位哟大血管!我也来抖一个撒。”

IMG_8751

张飞:“万般带不走,只有喝杯酒!来来来,下面进入合照环节,乾杯!”

IMG_8819

肚皮:“你龟儿慌啷个嘛,还有家属没有出镜撒,黑,黑”

IMG_8750

达尔:“对头对头,先来照一哈我们家婷婷儿”

IMG_8793

“婷婷儿,看勒里”

不理,继续吃,继续吃,,,,,,

达尔巴:“。。。算老算老,让她先吃点儿”

大猫儿:“来,我也跟我媳妇儿合照一张”

IMG_8844

聂不住:“该我们老,该我们老。来媳妇儿,把酒端起,我跟你讲吧啦吧啦吧啦吧啦,,,,,”

IMG_8806

“。。。你们倒是都看镜头撒”

IMG_8744

张飞:“哟,你女朋友呢?在干撒子”

original_0B65_0a8a000060b1118c

“等风来”

“好了好了好了,下面正式进入合照环节,你们个人耍哈,我给你们照。”

“唱歌滴,看这边看这边,猪源儿,把小白掰过来”

MIMG_8876

“张飞你又成功抢镜了撒,批娃娃。”

肚皮:“他龟儿国外旋了一圈儿,是楞个滴,话筒拿来哟,下一首是我和大猫儿的”

IMG_8839

陶小叉:“来,须须,等他们切唱歌,我来给你指导一哈麻将”

IMG_8758

罗大肛:“也,你只怕不对哟,也来指导一哈儿我撒”

IMG_8773

王大血:“指导你,,,呵儿,呵儿,你看他那样子像是会指导我们的迈,呵儿,呵儿”

IMG_8775

众人:“哈哈哈,,,就是就是,你还不了解他?”

IMG_8827

老板:“赞同赞同赞同,我来带头鼓个掌”

老赖:“是勒个道理”

神经:“。。。。”

IMG_8855

王大血:“来嘛,为同感干一杯”

老板:“来嘛来嘛,酒端倒,碰了我还要跟大猫儿一起唱歌”

IMG_8818

大猫儿:“这首歌送给大家,来,照一个”

老赖:“快,把这个动作抓下来”

猪源:“老子后天结婚,抓一哈给伍佰,各自抓”

须须:“哎呀,挤到我了,茄子~~~~~~~~”

IMG_8861

小白:“来,新年快乐”

IMG_8872

周小雄:“再唱两首换地方老哦,你看这里都一个躺起老”

IMG_8847

肚皮:“最后让大血管跟神经合唱一首嘛,换地方了”

聂不住:“作数”

陶小叉:“。。。你看他们两个都坐好了”

IMG_8820

达尔:“狗日滴你们看大血管好happy,合照了合照了,照完了换地方,哟,还有几个人呐??”

IMG_8852

“合照了合照了,那几个失踪半个小时,先不管,来来来都来”

MIMG_1503

后面由于相机没电了,照片到此为止,换大排档继续龙门阵摆起!一群人,江边边儿。大风起兮云飞扬,安得猛士兮喝趴四方!!!

后记:

洗完1000+张照片,人手一个相册,发现聚会基金即将告罄,看来这次没办法弄惠普喀嚓鱼了,留等下一次。

IMG_1504

2014.2.6 @ 重庆

SHELL 脚本从文件中按行读取数据

今天遇到一个问题:

需要给Shell脚本传递参数,一般来说,我们采用

$ ./test.sh para1 para2 para3 para4

这种方式,然后在shell中使用$1, $2, $3, $4 即可获取传入的参数。

但由于这次需要传递的参数实在太多,大约100K个(通过文件给出,每行即为一个参数),所以得变通一下。Google以后,发现通过awk命令可以实现,具体如下:

[shell]

#! /bin/bash

for x in ` awk ‘{print $0}’ number_sub.txt `
{
echo $x
}

[/shell]

接下来就可以做想做的工作了,解决。

Linux系统启动过程

面试的时候被问到Linux启动过程,没有答得很好。回来收集了一些资料,发现有一篇博客写得不错,不过是英文的。特翻译过来供广大小伙伴们参考:)

原文: http://www.thegeekstuff.com/2011/02/linux-boot-process/

———————————————————- 我是背景 ——————————————————–

通常,我们按下开机键,几秒钟后,我们就能看到Linux的登录界面。

但是你有没有想过,在屏幕的背后,这一切是怎么发生的呢?

下面会为大家分六个阶段简述一下一个典型的Linux操作系统的启动过程。

linux-boot-process

1. BIOS

  • BIOS,即 Basic Input/Output System BIOS,基本输入输出系统。
  • 对系统做完整性检查,即计算机硬件能否满足运行的基本条件。如果硬件出现问题,主板会发出不同含义的蜂鸣,启动中止,比如内存卡没有插好。
  • 查找,加载以及执行引导装载程序。
  • 它会在软盘、光盘或者硬盘驱动器等上查找引导装载程序。你也可以在BIOS启动过程中按F12或者F2(一般来说是这两个键)来改变这个顺序。比如重装系统的时候,你在BIOS阶段按F12,然后选择从U盘启动。
  • 一旦引导装载程序被找到并且加载到了内存中,BIOS就将计算机的控制权交给它了。
  • 简单来说,BIOS阶段就是加载并执行MBR

2. MBR

  • MBR,即Master Boot Record. MBR, 主引导记录。
  • 位于启动盘的第一扇区,一般为 /dev/hda或者/dev/sda
  • MBR 共有512位,由三个部分组成,1)第1-446位,主引导加载程序信息 2)接下来64位存放分区表 3)最后两位用来存储MBR有效标记
  • 它包含了GRUB的信息(或者在一些老系统上的LILO信息)
  • 简单来说,MBR阶段就是加载并执行GRUB

3. GRUB

    • GRUB,即Grand Unified Bootloader,启动管理器。
    • 如果你在操作系统分区中装了好几个内核,通过GRUB,你就可以选择启动哪一个。
    • GRUB会展示一个初始化的界面,等待你的选择,如果过了等待时间,它就会加载在grub配置文件中指定的默认内核镜像。
    • GRUB能够识别文件系统(在老Linux系统上的LILO并不能识别文件系统)。
    • Grub 配置文件在 /boot/grub/grub.conf (/etc/grub.conf 只是一个链接)。下面是一个CentOS中的grub.conf文件信息
#boot=/dev/sda
default=0
timeout=5
splashimage=(hd0,0)/boot/grub/splash.xpm.gz
hiddenmenu
title CentOS (2.6.18-194.el5PAE)
          root (hd0,0)
          kernel /boot/vmlinuz-2.6.18-194.el5PAE ro root=LABEL=/
          initrd /boot/initrd-2.6.18-194.el5PAE.img
  • 正如你从上面所看到的那样,它包含了内核以及initrd镜像的信息,initrd中含有内核所需的一些基本模块驱动。
  • 简单来说,GRUB阶段就是加载并执行内核以及initrd镜像。

4. Kernel

  • 挂载根文件系统,这个已经在grub.conf文件中”root=”指出。
  • 运行/sbin/init 程序来初始化系统环境
  • 由于/sbin/init 是第一个被Linux内核所执行的程序,它的进程ID号为1。可以通过命令“ps -ef | grep init”看到。
  • initrd,即 Initial RAM Disk,是用内存模拟的磁盘,一个临时文件系统。
  • 在真正的根文件系统被挂载之前,initrd被内核作为一个临时的文件系统,其中含有内核所需的一些基本模块驱动,内核启动时展开该initrd来加载相应的驱动,在该驱动的补充之下从而挂载上根分区;

5. Init

  • 根据/etc/inittab 文件来设定LInux的运行级别。
  • Linux的运行等级设定如下:
    • 0 – halt,关机
    • 1 – Single user mode,单用户模式
    • 2 – Multiuser, without NFS,无网络支持的多用户模式
    • 3 – Full multiuser mode,有网络支持的多用户模式
    • 4 – unused,保留,未使用
    • 5 – X11,有网络支持有X-Window支持的多用户模式
    • 6 – reboot,重新启动
  • Init程序根据/etc/inittab指定的默认运行等级来加载适当的程序。
  • 执行命令‘grep initdefault /etc/inittab’可以看到系统默认的运行等级
  • 如果你想给自己找点儿麻烦,你可以把默认运行等级设置为0或者6,鉴于你已经知道了0和6代表什么,我估计你不会那样干:)
  • 通常你会设置默认运行等级为3或者5

6. Runlevel programs

  • 当Linux系统启动以来以后,你会看到有很多服务也跟着运行起来了。比如你可能会看到“starting sendmail …. OK”。这些就是设置运行等级以后会对应加载的程序了。
  • 系统会根据你设置的系统运行等级来运行下面某一个目录中的所有程序。
    • Run level 0 – /etc/rc.d/rc0.d/
    • Run level 1 – /etc/rc.d/rc1.d/
    • Run level 2 – /etc/rc.d/rc2.d/
    • Run level 3 – /etc/rc.d/rc3.d/
    • Run level 4 – /etc/rc.d/rc4.d/
    • Run level 5 – /etc/rc.d/rc5.d/
    • Run level 6 – /etc/rc.d/rc6.d/
  • 请注意,这里面也包含直接指向/etc目录下的符号链接。也就是说,/etc/rc0.d 是指向/etc/rc.d/rc0.d的链接。
  • 在 /etc/rc.d/rc*.d/ 这些目录下面,你可以看到很多名字以S或者K开头的程序
  • 以S开头的程序是在启动过程中使用的,S代表startup。
  • 以K开头的程序是在关闭过程中使用的,K代表kill。
  • 这里还有数字出现在S或者K的后面,它们代表了程序的执行顺序。
  • 比如说,S12syslog 是用来启动syslog deamon,他的启动顺序是12,S80sendmail是用来启动sendmail daemon,他的启动顺序是80。那么显然syslog会先于sendmail启动。

好了,就是这些,这就是在Linux启动过程中所发生的事情。

C++面试题集合

只熟悉C,对C++不甚了解啊,但是面试又基本只有C++和Java的。于是乎,整理一下自己遇到的C++面试/笔试题吧

———————————————–我是背景———————————————————————

题目一:一个C++空类建立以后,会产生哪些成员函数?

分析:当时我就只想到了构造和析构函数啊。答案是6个。

[cpp]
class Empty
{
public:
Empty(); // 缺省构造函数
Empty( const Empty&); // 拷贝构造函数
~Empty(); // 析构函数
Empty& operator=( const Empty&); // 赋值运算符
Empty* operator&(); // 取址运算符
const Empty* operator&() const; // 取址运算符 const
};
[/cpp]

但并不一定是6个,如果编译器发现我们只是申明了Empty,并没有发现创建Empty的实例,那么编译器是什么函数都不会生成的。

所有这些只有当被需要才会产生。比如,
Empty e;
编译器就会根据上面的实例,给类Empty生成构造函数和析构函数。
当使用
Empty  e2(e);
编译器就会生成类Empty的拷贝构造函数。
Empty   e3;
e3 = e;
编译器生成赋值运算符函数
Empty    &ee = e;
编译器生成取地址运算符函数。

经过我们的分析可以这样理解:对于一个没有实例化的空类,编译器是不会给它
生成任何函数的,当实例化一个空类后,编译器会根据需要生成相应的函数。这条理论同样
适合非空类(只声明变量,而不声明函数)。

———————————————————————————————————————————–

题目二:STL中,vector与list的区别?

分析:其实基本就是 数组 与 双向链表 的区别,所以就很显然啦。

vector能够很好的支持随机访问,即有下标操作[],但如果要插入或者删除一个数则需要较多次数的移动元素。

list能够很好的支持插入、删除操作,但由于没有下标操作[],所以查找一个元素的时候比较耗时。

———————————————————————————————————————————–

题目三:内联函数、宏的区别?

分析:

由于内联函数首先它是一个函数,所以可以从宏与普通函数的对比入手,先引用一下别人的总结。

(1)、宏只做简单的字符串替换,函数是参数传递,所以必然有参数类型检查(支持各种类型,而不是只有字符串)以及类型转换。
(2)、宏不经计算而直接替换参数,函数调用则是将参数表达式求值再传递给形参。
(3)、宏在编译前(即预编译阶段)进行,先替换再编译。而函数是编译后,在执行时才调用的。宏占编译时间,而函数占执行时间。
(4)、宏参数不占空间,因为只做字符串替换,而函数调用时参数传递是变量之间的传递,形参作为局部变量占内存空间。
(5)、函数调用需要保留现场,然后转入调用函数执行,执行完毕再返回主调函数,这些耗费在宏中是没有的。

使用宏和内联函数都可以节省在函数调用方面的时间和空间开销。二者都是为了提高效率,但是却有着显著的区别:

(1)、内联函数首先是函数,函数的许多性质都适用于内联函数(如内联函数可以重载)。
(2)、在使用时,宏只做简单的文本替换。内联函数可以进行参数类型检查,且具有返回值(也能被强制转换为可转换的合适类型)。
(3)、内联函数可以作为某个类的成员函数,这样可以使用类的保护成员和私有成员。而当一个表达式涉及到类保护成员或私有成员时,宏就不能实现了(无法将this指针放在合适位置)。

———————————————————————————————————————————–

题目四:实现一个算法,删除字符串重复字符

分析:当时笔试面试已经搞了一下午,头晕眼花,第一次还写错了。回来整理了一下,其实很简单。

用两个指针p, q遍历待处理的字符串str,p负责记录有效位,q负责往前扫描。初始化q指向p的下一个字符。

(1) 如果p的字符和q的字符不等,那么由p记录下来,p与q均往前移动一个字符

(2) 如果p的字符和q的字符相等,那么p不动,q往前移动一个字符

代码如下

[cpp]
// the input str must terminated by ‘\0’
char* str_rm_dup(char *str)
{
char *p = str;
char *q = p;

// if str is NULL, then return
if(!p)
return NULL;

/*
* Assign q to the next address of p.
* Before that, we use *q++, not *++q to check whether *p == ‘\0’ in the first loop,
* because if the str is an empty string, str[0] will be ‘\0’.
*/
while(*q++)
if(*p != *q)
*++p = *q;

return str;
}

int main()
{
char a[] = "aabbbccdeeeeee";
printf("%s\n", str_rm_dup(a)); // abcde
return 0;
}
[/cpp]

———————————————————————————————————————————–

题目五:要求写一个没有错误的二分

分析:主要就是注意两点

(1) 整数相加溢出,比如4位机器上,a和b都等于7,即0111,那么相加就悲剧了。

(2) 防止无限循环

代码如下

[cpp]

/*
* Find the index of v if it is in the array of interval [a, b), -1 if not.
* @para a, the first location of the NOT DESC array
* @para l, the lowest index of the interval to be searched
* @para h, the highest index of the interval to be searched
* @para v, the candicate value
* @return index of v, or -1 if not found
*/
int bs(int *a, int l, int h, int v)
{
int m;
while(l < h)
{
m = (unsigned)l + (unsigned)h >> 1; // avoid the overflow of integer
if(a[m] == v)
return m;
if(a[m] < v)
l = m + 1;
else
h = m;
}
return -1;
}

[/cpp]

———————————————————————————————————————————–

题目六:深拷贝、浅拷贝区别?

分析:我的理解就是,浅拷贝只简单赋值,深拷贝是在需要的时候申请新的内存空间。假设我们有一个简单类A,代码如下所示:

[cpp]
class A
{
public:
A(char *s) : str(s) {}
void display()
{
cout << str << endl;
}
public:
char *str;
};
[/cpp]

然后我们写一个简单的main函数来调用它,如下

[cpp]
int main(void)
{
char name[] = "David";

A a(name);
A b = a;

a.display();
b.display();

b.str[0]=’P’;

a.display();
b.display();

return 0;
}
[/cpp]

结果为

QQ图片20131031155933

这是由于我们在类A中并没有去实现拷贝构造函数,编译器则帮我们实现了一个默认的,默认的构造函数则是简单的变量赋值,所以对象a和b的str成员变量其实指向的是同一块儿内存。所以改了一个,另外一个也会跟着改变。

下面我们修改一下类A,代码如下

[cpp]
class A
{
public:
A(char *s) : str(s) {}
void display()
{
cout << str << endl;
}
A(const A &another)
{
str = (char*)malloc(sizeof(char) * (strlen(another.str) + 1));
strcpy(str, another.str);
}
public:
char *str;
};
[/cpp]

然后看运行结果

QQ图片20131031160544

这次对象a和b的str由于指向的不是同一块儿内存地址,所以改了b的str对a不会造成影响。

还有一个区别是,貌似在消除对象a或者b的时候,如果是浅拷贝,会删除两次str所指的内存空间,会造成不可预料的结果。但是我跑程序暂时还未出现崩溃。

———————————————————————————————————————————–

编程之美3.3 计算字符串的相似度 (编辑距离)

Part 1: 题目描述

许多程序会大量使用字符串。对于不同的字符串,我们希望能够有办法判断其相似程序。我们定义一套操作方法来把两个不相同的字符串变得相同,具体的操作方法为:

1.修改一个字符(如把“a”替换为“b”);

2.增加一个字符(如把“abdd”变为“aebdd”);

3.删除一个字符(如把“travelling”变为“traveling”);

比如,对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加/减少一个“g”的方式来达到目的。上面的两种方案,都仅需要一 次 。把这个操作所需要的次数定义为两个字符串的距离,而相似度等于“距离+1”的倒数。也就是说,“abcdefg”和“abcdef”的距离为1,相似度 为1/2=0.5。

给定任意两个字符串,你是否能写出一个算法来计算它们的相似度呢?

Part 2:分析

书中给出的解法是通过递归来做的。其实有更快更简便的方法——动态规划。

此题其实就是算法中的求“最短编辑距离”。

编辑距离定义:计算两个字符串的距离,完全相同的字符串距离为0,可以通过修改一个字符、增加一个字符或删除一个字符三种方式来使两个字符串相同,但这些方式会使得距离加1。

假设现在有两个字符串A和B

A:David

B:Taisy

用二维数组d[i][j]表示A中取前i个字符到B中取前j个字符的最短编辑距离。比如d[2][1]就代表从”Da”到”T”的最短编辑距离。这里为2(即把D换成T,去掉A 或者去掉D,把a换成T)。

首先我们作出初始化d[0][j] = j(字符串A子串长度为0,字符串B子串有多少个字符,就作多少次增加操作;于是同理,作删除操作,可得d[i][0] = i)

其中d[i][j]只有3个来源:

1). 来自d[i – i][j – 1],即 “A的前i-1个字符组成的子串” 到 “B的前j-1个字符组成的子串” 的编辑距离,此时如果A[i] = B[j],则最短编辑距离不变,否则最短编辑距离加1(即把A[i]变为B[j] ),所以d[i][j] = d[i – 1][j – 1] + (A[i] == B[j] ?  0 : 1)

2). 来自d[i – 1][j],即 “A的前i-1个字符组成的子串” 到 “B的前j个字符组成的子串” 的编辑距离。此时删除在A的第i个位置上的字符即可,所以d[i][j] = d[i – 1][j] + 1

3). 来自d[i][j – 1], 即 “A的前i个字符组成的子串” 到 “B的前j-1个字符组成的子串” 的编辑距离。此时在A的子串后面添加一个字符B[j]即可,所以d[i][j] = d[i][j – 1] + 1

于是状态转移方程就写出来啦。

d[i][j] = min (d[i – 1][j – 1] + (A[i] == B[j] ?  0 : 1) ,  d[i – 1][j] + 1 ,  d[i][j – 1] + 1)

 

Part 3: 实现代码。

测试代码如下:

[cpp]
#include
#include

using std::cout;
using std::endl;

int min(int a, int b, int c)
{
int small = a;
if(b < small)
small = b;
if(c < small)
small = c;
return small;
}

int main()
{
char s[] = "David_and_Sophia"; // the last character is ‘\0’
char d[] = "Dadiudiu_and_Xiaodiugirl"; // the last character is ‘\0’

int len_s = strlen(s); // 16
int len_d = strlen(d); // 24
int dist[len_s + 1][len_d + 1];

cout << len_s << endl;
cout << len_d << endl;

for(int i = 0; i <= len_s; i++)
dist[i][0] = i;
for(int i = 0; i <= len_d; i++)
dist[0][i] = i;

for(int i = 1; i <= len_s; i++)
for(int j = 1; j <= len_d; j++)
dist[i][j] = min((dist[i – 1][j] + 1), dist[i][j – 1] + 1, dist[i – 1][j – 1] + (s[i – 1] == d[j – 1] ? 0 : 1));

cout << dist[len_s][len_d] << endl;

return 0;
}
[/cpp]

POJ上有对应的题目, POJ 3356,很类似。链接如下,顺带解题参考代码:
http://poj.org/problem?id=3356

AC的代码:

[cpp]
/*
* Author: David
* Date: 2013-9-4 23:27:11
* Brief: edit distance, DP
* Link: http://poj.org/problem?id=3356
*
* POJ info:
* Problem: 3356 User: davidloves
* Memory: 4632K Time: 16MS
* Language: G++ Result: Accepted
*/

#include

#define SIZE 1001

using std::cin;
using std::cout;
using std::endl;

int min(int a, int b, int c)
{
int small = a;
if(small > b)
small = b;
if(small > c)
small = c;
return small;
}

int main()
{
char x[SIZE];
char y[SIZE];
int len_x, len_y;

while((cin >> len_x >> x >> len_y >> y))
{
int dist[len_x + 1][len_y + 1];

for(int i = 0; i <= len_x; i++)
dist[i][0] = i;
for(int j = 0; j <= len_y; j++)
dist[0][j] = j;

for(int i = 1; i <= len_x; i++)
for(int j = 0; j <= len_y; j++)
dist[i][j] = min((dist[i – 1][j] + 1), dist[i][j – 1] + 1, dist[i – 1][j – 1] + (x[i – 1] == y[j – 1] ? 0 : 1));
cout << dist[len_x][len_y] << endl;
}

return 0;
}
[/cpp]

Enjoy!

Ubuntu下Lucene环境搭配

最近想着用一下lucene,就过来简单的写一写,后续还会有。

网上有很多lucene学习资料,例如,lucene源码解析,大家可以去搜一下。这里只是简单介绍怎样搭建lucene所需的环境。

lucene是Apache开源基金会其中一个开源全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。是用Java实现的,所以要想运行lucene就需要搭建JDK环境。

Ubuntu中有自带一个openjdk功能貌似不是很强大,所以果断sun jdk走起~

下面就介绍sun jdk在ubuntu中的安装。其实安装过程是很简单的,错误都是出在环境变量的设置上。

1. 到oracle官网下载linux版本jdk:http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

我的ubuntu是32位的~

下载的包,名字如下:jdk-7u25-linux-i586.tar.gz

2. 下载完么,就要解压安装,首先在/usr/lib下建一个文件夹名为jvm。然后将压缩包解压至jvm,安装就算完成了~(就是喜欢linux这种不用点来点去的安装,还没有进度条让你抓狂~吼吼~)命令如下:

sudo mkdir -p /usr/lib/jvm/
sudo tar zxvf ~/Downloads/jdk-7u25-linux-i586.tar.gz -C /usr/lib/jvm

jdk1.7.0_25就是我们要用的~

3. 然后就是设置jdk的环境变量,终于来到容易出错的地方了。

网上有很多设置环境变量的方法,让我们来总结一下有哪几种,不过要提醒大家,修改需谨慎有可能什么命令都用不了了呢。最好复制一份出来改。。

3.1 修改/etc/profile文件:

事实证明用这个方法修改之后会对所有的用户生效,如果修改错了,所有的用户在图形界面下都进不去。。

用以下命令修改:

vim /etc/profile

在profile文件中使用:/CLASSPATH命令找到环境变量设置的地方,其实文件就一页那么点,只是想练习一下快捷键。

修改CLASSPATH如下:

 29 JAVA_HOME=/usr/lib/jvm/jdk1.7.0_25
 30 PATH=$JAVA_HOME/bin:$PATH
 31 CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
 32 export JAVA_HOME
 33 export PATH
 34 export CLASSPATH

效果如下图:

  • 要注意一个跟windows设置十分不一样的地方,就是CLASSPATH是以“:”冒号来分割的,冒号啊,不要习惯性写成分号~~~

修改之后使用:wq!命令保存退出,不过当然要进行某种操作来让修改生效,这时候就需要source命令了,命令如下:

soure /etc/profile

这就哦拉~我只是说环境变量哦拉~

ERROR,ERROR:

当然如果你不小心改错了的话,ls命令用不了了吧,再想改改profile,什么vi,vim的用不了了吧。那么恭喜你,你悲剧了一小会。不过不要捉急,vi命令和ls命令在/bin里,系统会提示你的,所以进入到/etc下,使用/bin/vi profile打开profile去掉刚才的修改,再source一下就还原了,是不是又正常了呢。。。

不过假设你在改错之后,重启了一下电脑或者想要切换一下用户,恭喜你,你要悲剧一段时间了,因为你登不进去了。。这时,可以在命令行下解决,操作如下:(神奇的linux~)

    1. shift+ctrl+alt+F1进入命令行模式 
    2. 使用root身份登录
    3. cd /etc进入/etc目录
    4.使用/bin/vi profile命令打开profile进行修改
    5.:wq!保存退出
    6.重新登录,问题解决~~

3.2 修改.bashrc文件:

这个与profile的不同之处在于,在所需要的用户目录下修改之后只对该用户有效,也就是出错不会对其他用户造成影响。使用命令如下:

vim /home/username/.bashrc
或者直接 vim ~/.bashrc

打开bashrc文件,在文件末尾找到export,添加以下内容:

106 set JAVA_HOME=/usr/lib/jvm/jdk1.7.0_25
107 export JAVA_HOME
108 set JRE_HOME=${JAVA_HOME}/jre
109 export JRE_HOME
110 set PATH = ${JAVA_HOME}/bin:$PATH
111 export PATH
112 set CLASSPATH =.:${JAVA_HOME}/lib:${JRE_HOME}/lib
113 export CLASSPATH

效果如下图:

然后再使用source ~/.bashrc命令使修改生效

3.3 直接使用shell
用于在Shell下临时使用,换个Shell则无效
export JAVA_HOME=/opt/jdk1.7.0_25
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$PATH

4.  修改ubuntu默认jdk版本

修改完环境变量还不可以一劳永逸啊,同学,ubuntu有个自带的openjdk为默认的jdk版本,我们需要用sun jdk代替它。这时就需要用到update-alternatives命令了,首先介绍一下该命令。

update-alternatives是dpkg的实用工具,用来维护系统命令链接符,通过它可以很方便的从很多功能类似的程序和可选配置中设置系统默认使用哪个命令、哪个软件版本,例如,现在我们系统中同时安装了open jdk和sun jdk两个版本,而我们又希望系统默认使用的是sun jdk,那么通过update-alternatives就可以很方便的实现了。

使用以下命令:

sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.7.0_25/bin/java 1062
sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/jdk1.7.0_25/bin/javac 1062
sudo update-alternatives --install /usr/bin/jar jar /usr/lib/jvm/jdk1.7.0_25/bin/jar 1062
sudo update-alternatives --install /usr/bin/javah javah /usr/lib/jvm/jdk1.7.0_25/bin/javah 1062
sudo update-alternatives --install /usr/bin/javap javap /usr/lib/jvm/jdk1.7.0_25/bin/javap 1062

其中1062 为alternative更改后的优先级,新更改的优先级需要大于当前的,通过update-alternatives –display java 可以查看,openjdk的优先级为1061.

然后可以使用以下命令来查看当前jdk版本:

sudo update-alternatives --config java

如下图所示,在selection number处输入0即可(我的显示如此,可能大家显示的不一样,反正只需要将jdk1.7.0_25作为默认版本的即可):

这时sun jdk成为了默认的jdk版本~

如果大家对update-alternatives的其他命令感兴趣,可以搜 一下相关的资料,在这里我们只使用了以上几个命令。

呐,做人呢要开心,现在我们就可以开心一下了,java -version一下吧~

bingo~

报告长官,jdk环境搭建完毕,请下一轮指示~

好的,小的们下面进行大会下一项,lucene安装与设置

二、Lucene的安装与配置

小的们,要用linux啊,安装过程如此简单,妈妈再也不用担心我的学习了~,再也不用对着进度条仰天长叹了~

1. 去Apache下载lucene-4.4.0.tgz: http://www.apache.org/dyn/closer.cgi/lucene/java/4.4.0

2. 解压到/usr/local/src(路径按照自己的习惯来设)下的lucene-4.4.0/中,这就算安装完了ho~

3. 下面要设置一下lucene的环境变量才能用呢。

打开lucene-4.4.0/docs/下的index.html,点击Getting Started中的Lucene demo, its usage, and sources

根据其中的Setting your CLASSPATH提示可知,需要将以下jar包放入路径中:

lucene-core-4.4.0.jar可在lucene-4.4.0/core中找到
lucene-demo-4.4.0.jar可在lucene-4.4.0/demo中找到
lucene-queryparser-4.4.0.jar可在lucene-4.4.0/queryparser中找到
lucene-analyzers-common-4.4.0.jar可在lucene-4.4.0/analysis/commen中找到
我把他们通通放到了lucene-4.4.0/目录中,这样在设置环境变量时就不用打那么多的字了

在这里我们通过修改/etc/profile来设置

将CLASSPATH修改如下图:

然后source /etc/profile使修改生效。

老大,现在可以测试一下lucene是否搭建成功了~

4. 测试:

根据上面文档中Indexing Files的描述以及实际情况,使用以下命令来测试:

java org.apache.lucene.demo.IndexFiles -docs /home/sophia/Documents -index /usr/local/src/lucene-4.4.0/index

其中-docs指定了要索引的文档的位置,-index指定了索引的存放位置。

回车就可以看到如下的效果~:

Selection_021

而index文件中的内容如下:

Selection_022

说明,我们的lucene搭建成功~

再来简单测试一下lucene的搜索功能吧~

使用以下命令:

 java org.apache.lucene.demo.SearchFiles

然后在enter query中输入要搜索的内容,就可以得到包含搜索内容的文档。

hoho~~大王,今天任务已完成,简单的lucene搭建到此结束,接下来的日子,我们就要找一些相关的资料,研究一下lucene是怎样进行搜索的,以及代码实现。敬请期待~

C语言新手入门——从下载IDE开始

c_book

最近,高三的弟弟马上要去大学了。于是乎,打算教一教他C语言。

让我们从下载IDE( Integrated Develop Environment,即集成开发环境)开始。

Step Zero:买书

首先你需要的是一本完美的书,能够随时在你身边指引你的书。

《C程序设计语言》——if not you, then who?

本书原著即为C语言的设计者之一Dennis M.Ritchie和著名计算机科学家Brian W.Kernighan合著的一本介绍C语言的权威经典著作。我想,没有人比他更了解自己的设计。

摒弃你们的“谭浩强”吧~不是说谭先生不好,只是还不够。

Step One:下载最smart的IDE——CodeBlocks

1. 下载

地址:http://www.codeblocks.org/downloads/26

win7系统,选择这个版本就好了codeblocks-12.11mingw-setup.exe,可以从两个站点下载,一般是从这里Sourceforge这里下,如图

QQ图片20130726151625

点击连接以后,会跳到Sourceforge网站,等几秒钟就开始自动下载。

2. 安装

QQ图片20130726152132

点击Next,如上图。

QQ图片20130726152239

点击I Agree, 如上图。

QQ图片20130726152405

这一步是装运行所必须的各种软件,不用修改,默认点击Next就行。如上图。

QQ图片20130726152637

这一步是选择安装路径,可以点击“Browse”然后在弹出的地方选择,或者直接在“Destination Folder”下面的输入框里填写。不建议安装在C盘,工具软件安装在其他盘比较好。比如我就是安装在E盘的Tools文件夹下。然后点击Install进行安装即可。如上图。

如果安装途中出现以下错误,请以管理员身份重新执行安装步骤。即右键“codeblocks-12.11mingw-setup.exe”安装文件,然后选择以管理员身份运行。

QQ图片20130726152954

安装完成后,会问你是否现在运行Codeblocks,如下图。

QQ图片20130726153122

可爱的Codeblocks就出来啦!!!!

3. 编写第一个程序之前的小配置

QQ图片20130726153813

初次启动CodeBlocks的时候,会让你选择是否所有的 C和C++文件都以CodeBlocks打开,如图红色方框所示。点击它,然后点击OK。

现在我们需要新建一个项目,如下图所示。点击界面中间的”Create a new project”

QQ图片20130726154318

在弹出的窗口里选择“Console application“,即控制台程序,如下图所示。

QQ图片20130726154410

点击go,跳到下一个页面。选择使用的语言,这里选C。如下图所示。

QQ图片20130726154736

点击Next以后进入下一个页面。

在”Project title“,即项目名称这里填写项目的名称,这里我们用填入”Test“举例。填好以后,下面的Project fileName以及Resulting fileName会自动帮你填好。

然后就是选择你代码所在的目录,即”Folder to create project in“,可以直接输入文件夹目录(如我的就是放在E盘的Code文件夹下的C文件夹下),也可以点击”…“选择目录。如下图所示。

QQ图片20130726155008

填好以后点击Next,进入下一页。

QQ图片20130726155443

这里是选择编译器(暂时不需要去理解这是什么)以及其他设置。保持默认就好,点击Finish完成项目的配置。

进入开发界面HOHO!!!!

QQ图片20130726155817

双击左边Workspace下的的Sources,即可看到main.c文件,这就是你的源代码文件了,双击main.c,则会在右边的窗口显示出该文件的内容。如下图所示

QQ图片20130726160243

4. 编写人生中的第一个程序

红色框框里的就是啦,假设我现在稍微改一改它,

把printf(“Hello world!\n”);里引号的内容换掉,换成 方脑壳!!!!!!!,即

printf(“方脑壳!!!!!!!\n”);

然后我们要怎么运行这个程序呢?

首先,程序需要编译。因为代码是人写的,写的是一些英文字母,计算机不认识英文字母,它只认0和1,而编译器就是用来干这活儿的,编译器会把人写的代码,”翻译“成计算机能识别的0和1的组合。

那么,CodeBlocks如何编译代码?如下图,点击Build按钮即可。

QQ图片20130726160829

然后会在下方显示编译的结果,可以看到这句话”0 errors, 0 warnings (0 minutes, 0 seconds)“,即表示编译过程没有警告也没有错误。也就是编译器告诉你”我已经成功把你写的代码翻译成0和1的组合了,你可以运行它了“。

然后就是如何运行?

QQ图片20130726161407

如上图所示,点击build旁边的单个绿色箭头,你就会发现系统弹出了一个窗口。而这个窗口的内容就是,看图吧

QQ图片20130726161457

至此,如何新建、编写、编译、运行一个项目以及查看结果讲述完毕,不懂留言。

Step Final:一些建议

学习程序就得发扬”东搞搞,西搞搞“的精神。一般情况下,你是整不坏你的电脑的。所以说,大家多改改这里,改改那里,然后编译运行一下看有什么有趣儿的事情发生。

比如printf里为啥要有双引号啊,我不要行不行?行啊,你去掉以后,再编译,看看结果是什么。

为什么printf以后要有一个分号,我用句号结束行不行?行啊,你改以后,再编译,看看结果是什么。

为什么。。。。

为什么。。。。。

搞就是啊!大不了再改回来。大大不了重新新建一个项目。大大大不了重新安装ColdeBlocks。大大大大大不了重装系统(要是能到这份儿上,,,你已经不得了了)

运行完你的第一个程序以后,试一试把下面这段代码考过去,编译运行一下。

[cpp]
#include <stdio.h>
#include <stdlib.h>

int main()
{
printf("方脑壳!!!!!!!\n");

int a;
int b;
int sum;

printf("请输入两个不大不小的数,正负皆可,用空格隔开吧,回车隔开也可以\n");
scanf("%d%d", &a, &b);
sum = a + b;
printf("其实,计算器的原理就是这么简单,a + b = %d\n", sum);

return 0;
}

[/cpp]

至于有很多语句你现在看不懂,很正常,跟着那本书走吧。不久就会明白的。记住一点,try more and try more and try more……

That‘s all,

Enjoy!