2009年11月04日

 http://hi.baidu.com/%D0%C4%D3%EA%D0%C4%C2%B7/blog/item/0937ee07a42d65c87b89479d.html

 

   BoundsChecker是一个Run-Time错误检测工具,它主要定位程序在运行时期发生的各种错误。              

BoundsChecker能检测的错误包括:

     1)指针操作和内存、资源泄露错误,比如:内存泄露;资源泄露;对指针变量的错误操作。
     2)内存操作方面的错误,比如:内存读、写溢出;使用未初始化的内存。平台 n.U3U B C _3S社区&资讯平台!z&v k.U M [8S([
     3)API函数使用错误。

    使用BoundsChecker对程序的运行时错误进行检测,有两种使用模式可供选择。一种模式叫做ActiveCheck,一种模式叫做FinalCheck。下面分别进行介绍。
    1)ActiveCheck是BoundsChecker提供的一种方便、快捷的错误检测模式,它能检测的错误种类有限,只包括:内存泄露错误、资源泄露错误、API函数使用错误。
U `)R4p+~0要想使用ActiveCheck模式来检测程序的运行时错误,只需在VC++集成开发环境中打开BoundsChecker功能,然后从调试状态运行程序即可。此时ActiveCheck会在后台自动运行,随时检测程序是否发生了错误。下面说一下具体的使用步骤。
    首先,在VC++集成开发环境中打开你要对其进行测试的程序,同时保证项目处于Debug编译状态下。

     其 次,确保VC++集成开发环境中[BoundsChecker/Integrated Debugging]菜单项和[BoundsChecker/Report Errors and Events]菜单项处于被选中的状态。只有这两项被选中,BoundsChecker才会在程序运行过程中发挥作用。

 最后,在VC++集成开发环境中选择[Build/ Start Debug/Go]菜单命令,在Debug状态下运行程序,ActiveCheck也在后台开始运行了。
     2)FinalCheck具有BoundsChecker提供的所有检错功能。 FinalCheck 是ActiveCheck的超集,它除了能够检测出ActiveCheck能够检测出的错误,还能发现很多 ActiveCheck 不能检测到的错误,包括:指针操作错误、内存操作溢出、使用未初始化的内存等等,并且,对于ActiveCheck能检测出的错误,FinalCheck 能够给出关于错误更详细的信息。所以,我们可以把FinalCheck认为是ActiveCheck的功能增强版。我们付出的代价是:程序的运行速度会变 慢,有时甚至会变的很慢。

要 想在FinalCheck 模式下测试程序,不能使用VC++集成开发环境提供的编译连接器来构造程序,而必须要使用BoundsChecker提供的编译连接器来编译连接程序。当 BoundsChecker的编译连接器编译连接程序时,会向程序中插装一些错误检测代码,这也就是FinalCheck能够比ActiveCheck找 到更多错误的原因。
下面就介绍一下如何在FinalCheck模式下对程序进行测试:
     1)在VC++集成开发环境中打开你所要测试的项目。

     2)由于要使用BoundsChecker的编译连接器重新编译连接程序,所以我们为BoundsChecker独自构造一个文件夹。在VC++集成开发环境中,具体操作方法是:

A)点击[ Build/Configurations...]菜单命令。

B)在弹出的对话框中点击 Add 按钮。在Configuration 编辑框中添入你为BoundsChecker创建的文件夹的名称,这个名称是任意的,比如我们取名为BoundChecker。
    

C)在 Copy settings from组合框中选中XXX—Win32 Debug项,然后点击OK按钮,接着点击Close按钮。
现在,我们已经为FinalCheck构造好了一个文件夹。

    3) 点击[Build/Set Active Configuration…] 菜单命令,选中你刚才为BoundsChecker建的文件夹,然后点击OK按钮。这样BoundsChecker编译连接程序时生成的中间文件、可执行程序,都会被放到该文件夹下。

    4)选择[BoundsChecker/Rebuild All with BoundsChecker] 菜单命令,对程序重新进行编译连接,也就是在这时,BoundsChecker向被测程序的代码中加入了错误检测码。编译连接完成后, BoundsChecker会在你为BoundsChecker构造的文件夹中生成可执行文件。
      在FinalCheck模式下对程序进行检测的准备工作都已经做好,这时可以启动程序开始测试了,作步骤与在ActiveChecker模式下没什么区别。具体步骤如下:

  • 确保VC++集成开发环境中[BoundsChecker/ Integrated Debugging]菜单项和[BoundsChecker/Report Errors and Events]菜单项处于选中状态。
  • 点击[ Build\Start Debug]菜单,选中“Go” 菜单项。程序开始在Debug状态下运行。
  • 按照你制定好的测试用例,对程序进行操作。
    m8\6V l `"`0
  • 当BoundsChecker 检测到了错误时,会弹出窗口向你汇报,你可以当时就进行处理,也可以等到你的操作全部完成,退出程序之后再对列出的这些错误进行分析。这完全取决于你是否 选中了[BoundsChecker/Report Errors Immediately] 菜单项。
  • 退出程序后,BoundsChecker会给出错误检测结果列表。该错误列表与ActiveChecker给出的错误列表的查看方法完全一样。只不过这个列表中所报告的信息会更多、更详细一些。

     好 了,BoundsChecker在FinalCheck模式下的使用也介绍完了。ActiveChecker、FinalCheck这两种模式,比较而言 各有长短。ActiveChecker使用方便,只需在Debug状态下直接运行程序即可,并且程序的运行速度较快,但检测的错误种类有限; FinalCheck模式下,需要使用BoundsChecker的编译连接器重新编译连接生成可执行程序,并且程序的运行速度比较慢,但检测的错误种 类、提供的错误相关信息要多于ActiveChecker。所以,何时使用何种模式,应根据当时的具体情况而定。

2009年10月25日

zz from http://hi.baidu.com/taotling/blog/item/5c3c5f36f4dda2390a55a990.html

清楚明白,速成。。。

范式:
数据库规范化(Normalization)所采用的规范模式.

首先来看一张订单(表1-1):
供应商号: 234560   
供应商名: XXXXXX
============================================
商品号 商品名 数量 单价(元) 合计(元)
200   A   1000 2.00   2000.00
201   B   600   1.00   600.00
202   C   2000 10.00   20000.00
203   D   5000 20.00   100000.00
204   E   100   5.00   500.00

1. 非关系数据库表
如何通过这个订单来设计一个关系数据库的相关表?
一种最简单的办法就是将所有数据存放在一个表中,并用订单号和商品号做主键(Primary Key),
其中同一商品可以有不同的供应商
如下(表1-2:Order表):
   订单号 商品号 商品名 商品描述 单价 供应商号 供应商名 供应商电话
   000001 200   A   …….. 2.00 234560   XXXXXX   ……….
     201   B   …….. 1.00 234560   XXXXXX   ……….
     202   C   …….. 10.00 234560   XXXXXX   ……….
     203   D   …….. 20.00 234560   XXXXXX   ……….
     204   E   …….. 5.00 234560   XXXXXX   ……….
   ——————————————————————————-
   000002 200   A   …….. 2.00 234561   YYYYYY   ……….
     201   B   …….. 1.00 234561   YYYYYY   ……….
     202   C   …….. 10.00 234561   YYYYYY   ……….
     204   E   …….. 5.00 234561   YYYYYY   ……….
   ——————————————————————————-
   000003 202   C   …….. 10.00 234560   XXXXXX   ……….
     203   D   …….. 20.00 234560   XXXXXX   ……….
     204   E   …….. 5.00 234560   XXXXXX   ……….

2. 满足1NF的关系数据库表(消除重复组)
但上面的这个表不是一个关系数据库表,因为所有的关系数据库表中的每一行必须有主键,
并且这个主键要满足实体完整性(Entity Integrity),实体完整性就是主键不能包含空值(NULL),
并且主键必须能够惟一地标识任一行.根据实体完整性,上表显然不是一个关系数据库的表,
因为在这个表中有些行的主键中的订单号是空.
另外,上表中的000001订单下的
     203   D   …….. 20.00 234560   XXXXXX
     204   E   …….. 5.00 234560   XXXXXX
与000003订单下的
     203   D   …….. 20.00 234560   XXXXXX
     204   E   …….. 5.00 234560   XXXXXX
完全一样,这叫重复组(Repeating Groups),关系数据库表中不能含有重复组.
对上表进行修改,使之实现实体完整,即将相应的订单号补上(表1-3:Order表):
   订单号 商品号 商品名 商品描述 单价 供应商号 供应商名 供应商电话
   000001 200   A   …….. 2.00 234560   XXXXXX   ……….
   000001 201   B   …….. 1.00 234560   XXXXXX   ……….
   000001 202   C   …….. 10.00 234560   XXXXXX   ……….
   000001 203   D   …….. 20.00 234560   XXXXXX   ……….
   000001 204   E   …….. 5.00 234560   XXXXXX   ……….
   ——————————————————————————-
   000002 200   A   …….. 2.00 234561   YYYYYY   ……….
   000002 201   B   …….. 1.00 234561   YYYYYY   ……….
   000002 202   C   …….. 10.00 234561   YYYYYY   ……….
   000002 204   E   …….. 5.00 234561   YYYYYY   ……….
   ——————————————————————————-
   000003 202   C   …….. 10.00 234560   XXXXXX   ……….
   000003 203   D   …….. 20.00 234560   XXXXXX   ……….
   000003 204   E   …….. 5.00 234560   XXXXXX   ……….
上表现在成为一个关系数据库表,这个表满足1NF,即:
   (1) 所有的属性(列)都已定义
   (2) 没有任何重复组,即每行和每列的交汇处可以而且只能包含一个值,而不能包含一组值.
   (3) 所有属性(列)都依赖于主键.

3. 满足2NF的关系数据库表(消除重复组和部分依赖)
但是,上表在实际应用中是存在诸多问题的,比如说供应商XXXXXX的商品A要被分批100次订购,
那么将会在这个表中有100个订单,而关于此商品A的记录会有100行,如:
   订单号 商品号 商品名 商品描述 单价 供应商号 供应商名 供应商电话
   000001 200   A   …….. 2.00 234560   XXXXXX   ……….
   …… …   .   …….. …. …….   ……   ……….
   000002 200   A   …….. 2.00 234560   XXXXXX   ……….
   000003 200   A   …….. 2.00 234560   XXXXXX   ……….
   …   …   …   …    …   …    …    …
   00000n 200   A   …….. 2.00 234560   XXXXXX   ……….
这将使得出现输入错误的可能性大为增加,从而产生相同的商品在同一表中不同的行中记录的
相关信息不一样的错误,即所谓有数据不一致.数据不一致性是由于相同数据的重复存放,
即冗余造成的.数据冗余不但会造成数据不一致,还会使系统的维护更加困难,也会对系统的效率产生冲击.
为了减少这种情况下的数据的冗余需要消除部分依赖.
在表(1-3)中可以看出,我们只要知道某一商品的商品号,就能知道该商品的全部信息,
即商品的其他部分信息只依赖于商品号,也就是说在表1-3的:
   订单号 商品号 商品名 商品描述 单价 供应商号 供应商名 供应商电话
这些字段中,
   商品名 商品描述 单价
这些字段均依赖于
   商品号
字段,
因为"商品号"在表(1-3)中是主键的一部分,
所以"商品名 商品描述 单价"对于"商品号"的这种依赖关系,通常称为部分依赖.
即:部分依赖(Partial Dependency)是指只依赖于部分主键的依赖关系.
我们可以将存在部分依赖关系的列拿出来新生成一个新的表Product,
而原来的Order表中去掉了一些列,形成一个新的Order表,
在Product表中,商品号将作为其主键,同时商品号在新的Order表中将作为外键,
以实现对商品的相关信息的关联.
现在最初的(1-3:Order)表被拆分为两个新的表Order和Product,
它们之间通过商品号来进行连接:
Order表:
   订单号 商品号 供应商号 供应商名 供应商电话 …
Product表:
   商品号 商品名 商品描述 单价 …
现在,一个商品的信息只需要在Product表中存放一次,
而Product表中只有商品号在Order表中可重复存放多次,
这比起最初的Order表(1-3:Order)来说,"商品名 商品描述 单价"这些字段的数据冗余已大大减少.

我们可以看到,在1NF的规范下,我们消除了重复组,
在2NF的规范下,我们消除了部分依赖,
原来的Order表已被拆分为两个表:
   Order表:
    订单号 商品号 供应商号 供应商名 供应商电话 …
   与Product表:
    商品号 商品名 商品描述 单价 …
它们都满足于2NF的条件:
(1) 该表为1NF(无重复组)
(2) 该表不包含部分依赖(存在部分依赖的列已被提出形成另一个表)

4. 满足3NF的关系数据库表
现在我们再来看看满足2NF的Order表:
Order表:
   订单号 商品号 供应商号 供应商名 供应商电话 …
如果供应商的电话现在有了改变,那么在Order的所有有关这个供应商的"供应商电话"的信息将要
被修改,这种工作量是很大的.
再来看看"供应商号 供应商名 供应商电话"之间的依赖关系,
一般来说,我们只要知道了某一供应商的供应商号,就能知道该供应商的全部信息,
即,"供应商名 供应商电话"只依赖于"供应商号",但在这里,"供应商号"并不是主键的组成部分,
所以这种依赖不属于部分依赖,而叫做"传递依赖(Transitive Dependency)",
传递依赖是指一个或多个属性(列)依赖于非主键的属性(列).

现在我们把存在着传递依赖的相关列拿出来,重新生成一个叫Supplier的表,
而把"供应商号"作为Supplier表的主键,同时把供应商号保留在新的Order表中作为外键,
这样,最被的Order表到现在就被拆分为三个表:
   Order表:
     订单号 商品号 供应商号
   Supplier表:
     供应商号 供应商名 供应商电话 …
   Product表:
     商品号 商品名 商品描述 单价 …
这样的三个表,都同时满足于关系数据库表的3NF,即:
(1) 该表满足2NF(无重复组,无部分依赖)
(2) 该表不包含传递依赖(存在传递依赖的列已被提出形成另一个表)

5. 满足BCNF的关系数据库表
BCNF是鲍依斯-科得范式Boyce-Codd Normal Form的简写,
在3NF的基础上,要求表中的所有字段只依赖于关键字段.
在关键字段是组合关键字段的情况下,如:
   假设仓库管理关系表为StorehouseManage(仓库ID, 存储物品ID, 管理员ID, 数量),
   且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品。
   这个数据库表中存在如下依赖关系:
    (仓库ID, 存储物品ID) → (管理员ID, 数量) ["管理员ID, 数量"依赖于组合关键字段(仓库ID, 存储物品ID)]
    (管理员ID, 存储物品ID) → (仓库ID, 数量)   ["仓库ID, 数量"依赖于组合关键字段(管理员ID, 存储物品ID)]
   所以,(仓库ID, 存储物品ID)和(管理员ID, 存储物品ID)都是StorehouseManage的候选关键字,
   表中的唯一非关键字段为数量,这个表是符合第三范式的。
   但是,由于存在如下决定关系:
    (仓库ID) → (管理员ID) ["管理员ID"依赖于"仓库ID"]
    (管理员ID) → (仓库ID) ["仓库ID"依赖于"管理员ID"]
   即存在关键字段决定关键字段的情况,所以其不符合BCNF范式。它会出现如下异常情况:
   (1) 删除异常:
    当仓库被清空后,所有"存储物品ID"和"数量"信息被删除的同时,
    "仓库ID"和"管理员ID"信息也被删除了。
 
   (2) 插入异常:
    当仓库没有存储任何物品时,无法给仓库分配管理员。
  
   (3) 更新异常:
    如果仓库换了管理员,则表中所有行的管理员ID都要修改。
 
   把仓库管理关系表分解为二个关系表:
    仓库管理表:
     StorehouseManage(仓库ID, 管理员ID);
    仓库表:
     Storehouse(仓库ID, 存储物品ID, 数量)。
   即满足BCNF范式.

总结:
规范化是一个过程,该过程决定把哪些属性(列)放在哪些实体(表)中.
规范化可以帮助我们设计好的表结构,因为规范化减少了数据的冗余,
这使得系统更容易维护而且系统效率也会更高.

所谓的关系型数据库的逻辑设计就是数据库的表结构设计.
在关系数据库中,只有表中存有数据.

规范化只减少了数据的冗余而并没有消除冗余.
为了使相关的表连接起来,在规范化过程中不得不引入控制冗余(外键),
不过这种控制冗余与1NF和2NF表的数据冗余相比,
已经少得微不足道了.

2009年10月04日

给定连续的自然数序列1,2,3,…n,按字典序将其打印出来。n的取值范围是[1, 10,000,000,000]
实现函数:void print(int num);
如: print(120),则输出

1
10
100
101
102

109
11
110
111
112

119
12
120
13
..
19
2
20
21

29
3

4

9
90
91

99

————————-code————————–

//int 应该为 long

void display_cur(int cur_num, int num)

{

 

   int i;

   for (i = 0;i<= 9;i++)

   {

      int tmp_num = cur_num * 10 + i;

      if (tmp_num <= num)

      {

        cout<<tmp_num<<endl;

        display_cur(tmp_num, num);

      }

      else

      {

        break;

      }

   }

}

void display(int num)

{

   for (int i = 1;i<= 9;i++)

   {

      cout<<i<<endl;

      display_cur(i, num);

   }

}

 

void display1(int num)

{

   int cur_num = 1;

 

   cout<<cur_num<<endl;

   while (1)

   {

 

      cur_num = cur_num * 10;

      if (cur_num<=num)

      {

        cout<<cur_num<<endl;

      }

      else

      {

        cur_num /= 10;

        while ((cur_num % 10) == 9 || cur_num + 1 > num)

        {

           cur_num /= 10;

        }

        if (cur_num == 0)

        {

           break;

        }

        cur_num ++;

        cout<<cur_num<<endl;

      }

 

   }

}

void main()

{

   /*cout<<sizeof(a)<<endl;*/

   display1(112);

}

大家踊跃参加,活动非常热烈。下面文章来自读者ZelluX:

 求二进制中1的个数。对于一个字节(8bit)的变量,求其二进制表示中"1"的个数,要求算法的执行效率尽可能的高。

先来看看样章上给出的几个算法:

解法一,每次除二,看是否为奇数,是的话就累计加一,最后这个结果就是二进制表示中1的个数。

解法二,同样用到一个循环,只是里面的操作用位移操作简化了。

   1:  int Count(int v)  
   2:  {  
   3:      int num = 0;
   4:      while (v) {  
   5:          num += v & 0×01;  
   6:          v >>= 1;  
   7:      }  
   8:      return num;  
   9:  }

解法三,用到一个巧妙的与操作,v & (v -1 )每次能消去二进制表示中最后一位1,利用这个技巧可以减少一定的循环次数。

解法四,查表法,因为只有数据8bit,直接建一张表,包含各个数中1的个数,然后查表就行。复杂度O(1)。

   1:  int countTable[256] = { 0, 1, 1, 2, 1, …, 7, 7, 8 };  
   2:     
   3:  int Count(int v) {  
   4:      return countTable[v];  
   5:  }
  
好了,这就是样章上给出的四种方案,下面谈谈我的看法。

首先是对算法的衡量上,复杂度真的是唯一的标准吗?尤其对于这种数据规模给定,而且很小的情况下,复杂度其实是个比较次要的因素。

查表法的复杂度为O(1),我用解法一,循环八次固定,复杂度也是O(1)。至于数据规模变大,变成32位整型,那查表法自然也不合适了。

其次,我觉得既然是这样一个很小的操作,衡量的尺度也必然要小,CPU时钟周期可以作为一个参考。

解法一里有若干次整数加法,若干次整数除法(一般的编译器都能把它优化成位移),还有几个循环分支判断,几个奇偶性判断(这个比较耗时间,根据CSAPP上的数据,一般一个branch penalty得耗掉14个左右的cycle),加起来大概几十个cycle吧。

再看解法四,查表法看似一次地址计算就能解决,但实际上这里用到一个访存操作,而且第一次访存的时候很有可能那个数组不在cache里,这样一个cache miss导致的后果可能就是耗去几十甚至上百个cycle(因为要访问内存)。所以对于这种“小操作”,这个算法的性能其实是很差的。

这里我再推荐几个解决这个问题的算法,以32位无符号整型为例。

   1:  int Count(unsigned x) {  
   2:     x = x – ((x >> 1) & 0×55555555);   
   3:     x = (x & 0×33333333) + ((x >> 2) & 0×33333333);   
   4:     x = (x + (x >> 4)) & 0×0F0F0F0F;   
   5:     x = x + (x >> 8);   
   6:     x = x + (x >> 16);   
   7:     return x & 0×0000003F;   
   8:  }
  
这里用的是二分法,两两一组相加,之后四个四个一组相加,接着八个八个,最后就得到各位之和了。

还有一个更巧妙的HAKMEM算法

   1:  int Count(unsigned x) {
   2:     unsigned n;   
   3:     
   4:     n = (x >> 1) & 033333333333;   
   5:     x = x – n;  
   6:     n = (n >> 1) & 033333333333;  
   7:     x = x – n;   
   8:     x = (x + (x >> 3)) & 030707070707;  
   9:     x = modu(x, 63); 
   10:     return x;  
   11:  }
  
首先是将二进制各位三个一组,求出每组中1的个数,然后相邻两组归并,得到六个一组的1的个数,最后很巧妙的用除63取余得到了结果。

因为2^6 = 64,也就是说 x_0 + x_1 * 64 + x_2 * 64 * 64 = x_0 + x_1 + x_2 (mod 63),这里的等号表示同余。

这个程序只需要十条左右指令,而且不访存,速度很快。

由此可见,衡量一个算法实际效果不单要看复杂度,还要结合其他情况具体分析。

关于后面的两道扩展问题,问题一是问32位整型如何处理,这个上面已经讲了。

问题二是给定两个整数A和B,问A和B有多少位是不同的。

这个问题其实就是数1问题多了一个步骤,只要先算出A和B的异或结果,然后求这个值中1的个数就行了。

总体看来这本书还是很不错的,比较喜欢里面针对一个问题提出不同算法并不断改进的风格。这里提出一点个人的理解,望大家指正 ;-)

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/bvbook/archive/2008/04/15/2292823.aspx

#include <stack>

 

struct TreeNode

{

   int value;

   TreeNode * left;

   TreeNode * right;

};

 

void FreeTree(TreeNode * pNode)

{

   if (pNode == NULL)

   {

      return;

   }

 

   FreeTree(pNode->left);

   FreeTree(pNode->right);

   delete pNode;

   pNode = NULL;

}

 

void DisplayTree(TreeNode * pNode,int level)

{

   if (pNode == NULL)

   {

      return;

   }

 

   int i = 0;

   while ((i++)<level)

   {

      cout<<"\t";

   }

   cout<<pNode->value<<endl;

   DisplayTree(pNode->left,level+1);

   DisplayTree(pNode->right,level+1);

}

 

struct TreeNodeHelp

{

   TreeNode * pNode;

   int flag;

};

 

typedef std::stack<TreeNodeHelp> tStack;

 

void tranvers1(TreeNode * pRoot)

{

   if (pRoot == NULL)

   {

      return;

   }

 

   tStack s;

   TreeNodeHelp sNode;

   sNode.pNode = pRoot;

   sNode.flag = 1;

   s.push(sNode);

 

   while (!s.empty())

   {

      TreeNodeHelp sTopNode = s.top();

      s.pop();

      if (sTopNode.pNode == NULL)

      {

        continue;

      }

 

      if (sTopNode.flag == 1)

      {

        sTopNode.flag = 2;

        s.push(sTopNode);

        sTopNode.flag = 1;

        sTopNode.pNode = sTopNode.pNode->left;

        s.push(sTopNode);

      }

      else if (sTopNode.flag == 2)

      {

        sTopNode.flag = 3;

        s.push(sTopNode);

        sTopNode.flag = 1;

        sTopNode.pNode = sTopNode.pNode->right;

        s.push(sTopNode);

      }

      else

      {

        cout<<sTopNode.pNode->value<<endl;

      }

   }

}

void main()

{

   /*cout<<sizeof(a)<<endl;*/

 

   TreeNode tNode[10];

 

   for (int i = 0; i < 10; i++)

   {

      tNode[i].left = NULL;

      tNode[i].right = NULL;

      tNode[i].value = i+1;

   }

 

   tNode[0].left = &(tNode[1]);

   tNode[0].right = &(tNode[2]);

   tNode[1].left = &(tNode[3]);

   tNode[1].right = &(tNode[4]);

   tNode[2].left = &(tNode[5]);

   tNode[2].right = &(tNode[6]);

   tNode[4].left = &(tNode[7]);

   tNode[4].right = &(tNode[8]);

   tNode[6].left = &(tNode[9]);

 

   DisplayTree(&(tNode[0]),0);

 

   tranvers1(tNode);

}

struct Node

{

   int value;

   Node * next;

};

 

struct Head

{

   Node * next;

};

 

void ReverseList(Head * phead)

{

   if (phead == NULL || phead->next == NULL)

   {

      return;

   }

 

   Node * prev = NULL;

   Node * cur  = phead->next;

   Node * next;

  

   while(cur != NULL)

   {

      next = cur->next;

      cur->next = prev;

      prev = cur;

      cur = next;

   }

 

   phead->next = prev;

}

 

Node* ReverseListRecurHelp(Node * pNode, Node *& pHead)

{

   if (pNode == NULL || pNode->next == NULL)

   {

      pHead = pNode;

      return pNode;

   }

 

   Node * prev = ReverseListRecurHelp(pNode->next,pHead);

   prev->next = pNode;

   return pNode;

}

 

void ReverseListRecur(Head * pHead)

{

   if (pHead == NULL || pHead->next == NULL)

   {

      return;

   }

 

   Node * pTail = ReverseListRecurHelp(pHead->next, pHead->next);

   pTail->next = NULL;

}

 

void DisplayRecur(Node * pNode)

{

   if (pNode->next == NULL)

   {

      cout<<pNode->value<<endl;

   }

   else

   {

      cout<<pNode->value<<endl;

      DisplayRecur(pNode->next);

   }

}

void DisplayList(Head * phead)

{

   if (phead == NULL || phead->next == NULL)

   {

      return;

   }

 

   DisplayRecur(phead->next);

}

void FreeListRecur(Node * pNode)

{

   if (pNode == NULL)

   {

      return;

   }

   if (pNode->next == NULL)

   {

      delete pNode;

      pNode = NULL;

   }

   else

   {

      FreeListRecur(pNode->next);

      delete pNode;

      pNode = NULL;

   }

}

 

void FreeList(Head * pHead)

{

   if (pHead == NULL || pHead->next == NULL)

   {

      return;

   }

   FreeListRecur(pHead->next);

}

 

void main()

{

   /*cout<<sizeof(a)<<endl;*/

 

   int i ;

   Node * prev = NULL;

   Head * pHead = new Head;

 

   for (i = 0;i<10;i++)

   {

      Node * pNode = new Node;

      pNode->value = i;

      pNode->next = prev;

      prev = pNode;

   }

   pHead->next = prev;

 

   DisplayList(pHead);

 

   ReverseList(pHead);

 

   DisplayList(pHead);

 

   ReverseListRecur(pHead);

 

   DisplayList(pHead);

 

   FreeList(pHead);

}

2009年10月03日

写月一首

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

似送残霜灯明暗

如洒碎玉水知凉

中元独登照千里

半照游子半照乡

——————————————

自写一首

——————————————-

骐骥空作乐

骈死槽枥间

男儿如有志

驽马可万里

——————————————-

2009年08月31日

 

Backpackers 背包旅行
背包旅行变成一种时尚,有人把它当成了炫耀的资本,更奇怪的是,在国外背包客都是穷人,参

加旅行团的是有钱人;在中国则正好相反。

Bohemia 波希米亚风

人们常常把"一切看上去疯疯癫癫的打扮"称为波希米亚风。在中国,波希米亚这个概念被无限放大,就连房地产商都在叫卖"波希米亚建筑风格",令人汗颜。

Bordeaux 法国葡萄酒(波尔多 )

在国外,只有少数人可以享受葡萄酒的刺激,而大多数的人只能喝啤酒。在国内,有着无数的文人墨客赞美葡萄洒的雍容华贵。

Broadway 百老汇

因而情节极其简单,场面极其华丽,表演非常夸张,假唱无所不在,在纽约或伦敦取得成功后,便开始全球走穴,大赚其钱,这一点又和《同一首歌》何其相像。

Che Guevara 切·格瓦拉
以贩卖纪念品为生的切·格瓦拉和那个理想主义的战斗者切·格瓦拉未必是同一个人,前者是流

行旗帜,后者是精神导师。

Chivas 芝华士
在国外,威士忌被认为是一种老头子酒,很难想象,会有大学生的毕业派对选择威士忌。

Christmas、Valentine"s day 圣诞节,情人节
圣诞节到底是什么?是圣洁?信仰?欢乐?家庭?爱?毫无疑问,首先是消费。

Cigar 雪茄:是享受,不是做秀
这些中国人眼里的奢侈品,不过是另一个社会主义国家的重要创汇产品罢了。

Credit card 信用卡
中国人支付着全世界最高的信用卡贷款利息(年利率高达18%),却浑然不知危险正在来临。

中国人更热衷于消费文凭 EMBA
比起西方人,中国人更热衷于消费文凭,这背后包含着中国几千年来对教育的热
爱,对学而优则仕的推崇。

Evian 依云水 (一种产自法国的矿泉水,中国是50元一瓶.新加坡6-7新币一瓶)

当被问道"喝点什么"的时候,很多人习惯淡淡地说一句:"我只要依云水。"声音里有掩饰不住的优越感。

Golf 高尔夫

高尔夫既不是贵族运动,也不是平民运动,它是一种健康运动,是一种礼仪,一种素质和一种审美、生活准则。

Haagen-Dazs 哈根达斯

中国被当成奢侈品的哈根达斯在其发源地美国是个极普通的品牌,就如同和路雪之于中国,主要在超市和自动售货机售卖,很少有专门店。

IKEA 宜家

以其DIY的设计风格及昂贵的售价,一时成为小资理想的高端家居品牌。而美国人的评论是"cheapIKEA",他们买家具就像买衣服,好看就买,买来就用,腻了就换。

Lisa Ono 小野丽莎

她不是爵士女伶中最大牌的,但无疑是最具群众基础的,她是小众爵士圈里的"大众歌手",是一道献给大众的"心灵鸡汤"。

Marketplace 大卖场

便宜、甩卖、方便、快捷,大卖场以这样的面目出现在我们面前。我们相信了,但实际上我们感受到了吗?

NM 纳米
纳米是高科技,你不懂科学,就只能相信科学的无所不能。

Olympics 奥运
奥运精神叫做"友谊第一,比赛第二"。但现在,已经被叫卖声淹没了。

无处不在的Paris 巴黎

巴黎到底是什么东西?是艺术,是享受生活,是阳光普照的下午,是优雅的生活模板,其实在我们这里,依然是消费。

Pasta 意粉
意粉于西方人之意义,如同方便面之于东方人。

Resort 度假酒店

一个入住了三亚希尔顿酒店的人,第一感觉是"奢华到令人窒息",而不是度假酒店应有的"轻松和舒适"。

Sex Toy 情趣玩具
情趣玩具是十恶不赦、放荡与色情的淫具吗?在西方,没有人会在意你是否在用
它,有时有人反而会因此认为你是个很注重品质的人。

中国人崇尚Skyscraper 摩天大楼
中国人崇尚摩天大楼,很多时候是因为面子问题。越来越多的外国人感觉到,摩天大楼并不经济。

Snooker 斯诺克

在英国,斯诺克是一项需要西装革履打领结的绅士运动,但在中国,从上世纪80年代至今,是光着膀子在街边打台球。斯诺克的中国特色。

SPA
中国大街小巷里的SPA已经没有等级之分了,云南悦榕庄酒店里的高级水疗被称作SPA,巷子口五

金店旁边的美容院也挂个"SPA"的牌子。好像只要躺在漂着花瓣的木制澡盆里,谁都成了杨贵妃。

SOHO
全称Small Office Home Office,指小型家庭办公室,也指在家里办公的自由职业者。他们没有固定的工作,没有稳定的收入。

Starbucks 星巴客 :卖咖啡到卖情调

星巴客在美国是很物美价廉的大众饮料,算是咖啡中的快餐,但移民到了中国,却成了时尚、优雅情调的元素之一。

Surburbs 郊区生活

家在郊区的好处是,新鲜空气,远离喧闹,但是想在中国过郊区生活,还请做好以下准备:交通、购物,医疗设施等。

The World is Flat《世界是平的》

中国的企业家们也不厌其烦地提起《世界是平的》,何以一本书会受到如此多商界领袖人物的推荐和欣赏?"因为他说出了那些具有影响力的人不能或不便说出的’心里话’。

USA美国

百威啤酒在美国的宣传一直是将百威作为美国男性工人创造的英雄产品,将产品与美国工人的形象及美国传统美德统一在一起。但是在中国,百威是都市泡吧族的最爱,他们大多刚刚从格子间里出来,连西装都来不及换。

Vitamin 维生素

美国人热衷的维E,500粒一瓶价格不到10美元,算下来一天只要人民币1角6分钱,便宜得像白送。虽然国内药房里也有几十元一瓶的维生素,但人们推崇的始终是平均每瓶在300元以上的国外品牌

Whiskey in Green Tea 威士忌兑绿茶

苏格兰人发明了威士忌,中国人发明了威士忌兑绿茶。一位苏格兰记者报道说:"威士忌酒商做梦也没想到,他们的酒会被人这么饮用。"

Yoga 瑜珈

70%的印度人练瑜珈,却很少人去瑜珈馆,因为这是他们日常生活的一部分。我们以为可以用钱来消费健康追随时尚.

2009年08月30日

今天怀着比较激动的心情,参加了在知春路盈都大厦的beBeyond求职免费讲座,以前一直觉得这类求职讲座挺2的,没什么信息,无非是宣传自己公司的培训,类似于考研班性质。结果发现这次还是有些收获和启示的。撰此短文以记之。

找工作的三个过程:认识自我,认识工作,坚持和信念。

首先,讲认识自我,找工作绝不是说谁来学校招聘了就扔个简历给ta,至于成败利钝,听天由命吧。这一点的主要的意思是认清自己的优势在那里。而优势不光来自于大学4年,研究生3年;人生活在这世上的几十年,都是你的性格上的优势积累的过程。从这几十年的积累来看你自己的性格和优势,会更加准确的把握自己适合哪种类型的工作。这里一个发掘自我的trick就是历数自己从小到大认为比较得意的一些事情,从这些事情中提炼出自己性格方面的优势。例如:虽然平时成绩不是很优秀,但是大考中会有比较好的发挥,这说明你抗压能力比较好,心理调节的能力比较强。如果通过自己的努力成功的协调了某个事情,那么可以在其中发掘自己沟通方面的闪光点。hr面试绝不是想跟你对简历,而是想知道简历之外的故事,简历只是一个基础。有了这些思考,相信可以在跟hr的沟通中有更多的话可以说。

其次,讲认识工作,也就是认识工作本身的性质,对于人的能力的要求,主要看自己是不是匹配。包括行业、公司、职位等。什么样的工作适合什么样的人,所以对自己适合的工作投简历准备,成功率会更高,自己工作了也会更happy。这个就是主要要多做一些了解,了解不同的行业、公司、职位的情况和要求。

最后,讲坚持和信念,成功有时候就在于再坚持那么一小下。一个同学,经过自我发觉,觉得自己有很好的抗拒无聊的工作的能力,适合于做审计类的工作,就去参加pwc的面试,在群面中就被pass掉了,但是在收回小身份牌的时候,他坚持要求hr将小身份牌送给他留作纪念,经过跟hr的长时间argue,虽然没有成功,但是给hr留下了很深刻的印象,在下次的霸王面中,终于还是起到了作用。另外一个同学,在hr电话他面试失败的时候,跟hr长聊了一个多小时,虽然这样很不人道,但是还是争取到了一个offer。还有的同学霸王面了40多次。我们应该从这些坚持中有所体悟。

其实,找工作面试就是一个推销自己的过程,跟卖东西也没什么区别,无非是说明这东西多么好,多么适合你的需求。千言万语汇成一句话:我就是你们想要的。

另附一个简单的时间表:

知名外企:  9月中旬 —- 10月底
一般外企私企:  10月初  —- 年底
国企:  11月份 —- 来年3月份
公务员: 11月份 —- 来年

2009年07月13日

作为长者和学者的季羡林先生

钱文忠 2007年7月

我有幸从十八岁考入北京大学东方语言文学系梵文巴利文专业起,就一直追随季羡林先生,在季羡林先生门下求学。因此,我和季羡林先生有着远比一般人多的接触,远比一般人深的了解。这是我个人生命史上最为珍贵的一页。

出生于一九一一年的季羡林先生今天已经是九十六岁高龄了,在我考进北京大学的一九八四年,季羡林先生也已经是七十三岁,年过古稀了。撇开季羡林先生的崇高的社会和学术成就、名誉、地位不说,就单论年龄,他也已经是燕园一老了。大家称呼他,更多的是“季老”,而不是象门生弟子那样称呼“先生”了。

这是一位什么样的长者呢?对比自己年长的人——当时冯友兰、朱光潜、王力、陈岱孙等比季老高一辈的人,我进北大时还都健在,季老是非常尊敬的。1990年的1月31日,先生命我随侍到燕南园向冯友兰、朱光潜、陈岱孙三老贺年。路上结着薄冰,天气是非常的寒冷,当时也已经是八十高龄的季先生一路上都以平静而深情的语调,赞说着三位老先生的治学和为人。先到朱光潜先生家,朱先生已经去世,只有朱夫人在,季先生身板笔直,坐在旧沙发的角上,恭恭敬敬地贺年。再到冯友兰先生的三松堂,只有冯先生的女儿宗璞和女婿蔡仲德先生在家,季先生身板笔直,坐在旧沙发的角上,恭恭敬敬地贺年。最后到陈岱孙先生家,陈先生倒是在家的,看到季先生来访,颇为惊喜。季先生依然是身板笔直,坐在旧沙发的角上,恭恭敬敬地贺年。其时正好两卷本《陈岱孙文集》出版,陈先生去内室取出书,题签,起身,半躬着腰,双手把书送给季先生。季先生也是起身,半躬着腰,双手接过,连声说“谢谢,谢谢”。冬天柔和的阳光,照着两位先生的白发——这几幕场景过了十七年了,却一直鲜明地印在我的记忆里。

北大有许多成就卓著的专家学者,在将近二十年前,那时的中年学者,行辈和地位自然还不能和季先生相比。季先生对他们是发自内心的喜爱、尊重,不遗余力地揄扬他们。我在这里讲的都不是季先生在公开场合,比如学术会议之类上的举动,都是私下的言谈,不为外界所知的。

一天,我陪季先生在散步到办公楼附近,恰巧中文系的裘锡圭教授正低着头很慢地走在前面,大概在思考什么问题。季先生也放慢了脚步,低声对我说:“你知道吗?裘先生,古文字专家,专家。”说这些话的时候还翘起大拇指,微微地晃动。

那么,对更为年轻的学者呢?季先生更是不遗余力地奖掖,无论自己多忙,也无论自己手头有多少更重要的工作要做,总是乐于为他们的著作写序,这就是季先生序写得如此之多的原因。不仅如此,季先生还往往会在为某个人写的序言里面列举上一大串年轻人的名字,唯恐人不知道。至于替年轻人看稿子,推荐发表,那简直是家常便饭了。然而,也确实有一些年轻人后来出了这样那样的问题,给季先生带来麻烦,但是,季先生总是以非常宽容的心态来对待他们。也正因为这样,很多年轻人和季先生年龄、地位都相距遥远,但都发自内心地热爱这位长者。

我在这里举两个例子,是关于季先生请年轻人吃饭的。一次是请我吃饭。有一年假期,我没有回上海,躲在北大。一天,我拉上窗帘关紧门,点上蜡烛看书,隐隐约约听到楼道里有悉悉簌簌的声音,一会儿有敲门声。开门一看,原来是季先生不放心我,在助手李铮老师陪同下,特意来叫我去吃饭。这顿饭吃的什么,今天是一点都想不起来了。但是,开门看见季先生站在昏暗的楼道里的情形,却至今犹在目前。那些年,经常在季先生家吃饭,也经常陪同季先生赴宴,但是,这顿饭是很特别的。现在已经是著名历史学家的浙江大学的卢向前教授,但是还在北大读研究生,他应该也有一顿难忘的饭。季先生在研究唐史的时候,曾经托卢先生代为查阅一份敦煌卷子,为了表示感谢,季先生特意在一天中午来到杂乱不堪的学生宿舍,邀请卢先生吃饭。这件事情在北大造成了轰动,传为美谈。

然而,季先生又要求年轻人为他做过什么吗?我相信没有。很偶尔地,季先生会让我们为他查找一些资料,这原本是我们应该做的,况且还是很好的学习机会。可是,就连这样的举手之劳,季先生也绝对都要在文章里、书里写上一笔。有不少媒体问过我,季先生工作那么忙,还发表了那么多的文章,是否有学生代笔的?这不算是一个太离谱的疑问。但是,我可以负责任地讲,我追随季先生那么多年,连替他写个信封的事情都没有过。

上面讲的都是和学术界有关的事情。那么在学术界之外,季先生又有怎么样的长者风范呢?还是举几个例子。季先生穿着极其的朴素,经常会被人看成是学校里的老工人。不止一次,季先生会被来报到的新学生叫住,替他们看行李。季先生每次都原地不动地替他们看守行李,有时候会一看两小时。自然,这些学生两三天以后就会在北大的迎新会上,看见季羡林校长坐在主席台上。

北大有司机班。大家知道,司机可是见多识广的,而且往往并不那么好说话。然而,北大的司机都愿意为季先生服务。为什么呢?季先生每次都会为他们准备一些小礼物,比如当时还比较少见的国外带回来的香烟。可是,这些能够打动司机吗?不能!有几位司机告诉我,他们接送的大人物,几乎都是不怎么和他们说话的,到了家也是自顾自的走了,只有季先生下了车道谢不说,还要站在门口目送车子驶远。这才是令他们非常感动的地方。

季先生自己生活的简朴,在北大是人所皆知的。但是,他的慷慨知道的人就并不很多了。有不少事情是我经手的,因此我知道的就比较多一些。季先生往自己的家乡小学寄钱寄书那是常有的事情。就连在家里工作过而已经离开了的保姆,倘若喜欢读书,季先生都会给予支持。我清楚地记得一张汇款单子上季先生的留言:“这些钱助你读书,都是爬格子所得,都是干净的。”

实际上,对北大的情况稍微有点了解的人大概都知道,在季先生九十岁以前,他在北大郎润湖的寓所的大门,几乎是完全敞开的。张中行先生笔下那幕一位小书店老板抱着一大摞书上门请季先生签名的情况,根本就是经常发生的。

大家可能都不知道,前几年,北大接受了一笔最大的捐赠,就是来自于季羡林先生的。这笔捐赠有多大呢?仅仅是古字画就以百计!季先生在文革前省吃俭用的钱,几乎都用于此。他收藏的最底线是齐白石,这些收藏当中甚至有苏东坡的《御书颂》。光这些,价值就很难计算了。可是,季先生捐出的不仅是字画,还有古砚、印章、善本,还有自己毕生积蓄的稿费。总之,季先生把一切都捐赠出来了。而且,季先生还不停地把近年来的稿费捐赠出来。季先生是已经有了曾孙的,他的后代都过着很普通的生活。请问,这是什么样的胸怀?那些无聊而狂妄地评论季先生的人,又做何感想呢?

我想“季羡林热”的一部分原因,甚至可以说最主要的愿意就在于此,大家都感受到了作为一位长者的季先生的为人风范和人格魅力。要知道这位朴素如老农的长者是留学德国十年的哲学博士,是当时已经为数极少,现在更已是硕果仅存的建国后第一批文科一级教授,是中国第一学府北京大学的文科校长,是全国人大的常委,是一百多个全国性学会的会长、杂志的主编——按照完全可以理解的世俗心态,这里难道不是存在着巨大的不和谐或反差吗?可是,难道不也正是这种所谓的不和谐和反差,反而更加增加了对季先生的崇敬之心吗?

社会上对季先生的崇敬可以从媒体的报道中清晰地显示出来。季先生在素来洋溢着某种清高和狂傲的北大学子那里,也得到了一种亲切的真诚的热爱。北大校园里,学生不少是骑车如飞的,前面倘若有人挡道,那一般都是大按其铃,催促不已的。然而,我却太多次地看到,只要学生知道前面慢慢地走着,挡住了他们的道路的是季先生,他们都会跳下车来,安静地在后面推车而行,不少时候,季先生茫然不知自己身后排起了一条长龙。有一年的大年初一,季先生推开家门,发现门前白皑皑的雪地上,划满了来自北大好几个系所的学生的问候和贺年之词,季先生感动得几乎说不出话来。这在北大竟然形成了一种新的传统。

作为一位年高德劭的长者,季先生赢得了大家的心,这是不争的事实。然而,相比之下,季先生作为学者的一面,却未必被大家所了解。就连北大的绝大部分教师和学生也包括在内,大家主要是通过季先生的上百万字的散文随笔、数百万字的的译作、季先生对宏观文化和社会情势的某些看法来了解季先生作为学者的那一面的。这当然没有错。但是,却实在没有搔到痒处,却实在只是停留在很不完全的表面。尽管季先生的散文随笔真挚感人、脍炙人口,他主要的却绝对不是一位作家;尽管季先生的翻译作品涉及古今中外好几种文字,其中还包括吐火罗语在内的死语言,在文化大革命被迫看守门房、清扫厕所的艰难环境下,更是以一人之力,惊天地泣鬼神地翻译了印度两大史诗之一的《罗摩衍那》,他主要的却绝对不是一个翻译家;尽管季先生的一些宏观理论见解引起了全社会乃至国外的广泛关注和议论,被广为传播报道,他主要的却绝对不是一位理论家或评论家。

对于这样的一种情况,我们究竟应该怎样去看呢?

季先生前一段时间公开表示要辞去诸如“学术泰斗”、“国学大师”和“国宝”之类的“帽子”,引起了全社会的广泛的关注。这固然是季先生一贯的深怀谦虚的表示,但是,也未必就不是反映出了季先生的目光看透了表面的热闹红火,对背后的忘却冷漠多少有所抱憾。

我曾在接受记者采访时说过:“毕竟,季老和我们身边、社区里的某一位慈祥、正直的老人还是有所不同的。”为什么这么说呢?道理其实也并不复杂,季先生作无疑是一个历史人物,自有其历史地位。但是,这个地位的确立,首先因为他是一位杰出的学者,我们应该努力去了解他在学术史、精神史上的创获与贡献。

“学术泰斗”、“国宝”是一个不重在反映专业学术领域的尊称,我们可以先不去讨论。“国学大师”云云,实际上就作为学者的季先生而论,也确实有未达一间的嫌疑。其实,季羡林先生研究的主要领域并不是传统意义上的国学,他不从朝代史、制度史的角度研究历史,不关注严格意义上的经学,也不按照通行的“学术规范”来研究古代文学。通常我们所说的文史哲只能算季先生的“副业”。

那么,季先生的主要领域是什么呢?他的“看家本领”是什么呢?他又是凭借什么样的重要贡献才会在国际学术界拥有如此高的声望和地位呢?

用最简单的方式来说,季先生的主要领域和“看家本领”,乃是以历史语言学和比较语言学的方法研究梵文、巴利文、包括佛教混合梵语在内的多种俗语、吐火罗语,并由此解决印欧语言学和佛教史上的重大的难题。我在新近出版的《季门立雪》的封底,特意标出了这么一段话,我相信季先生也会认可的:“如果说季羡林先生的学术研究有一条贯穿其中的红线,那么,这条红线非印度古代语言研究莫属。无论是对于研究中印关系史、印度历史与文化、东方文化、佛教、比较文学和民间文学、吐火罗文、唐史,还是翻译梵文等语种文学作品,先生在印度古代语言研究领域的工作、成就、造诣,都具有首要的、根本的重要性。”

这是一个极其冷僻的专业领域,很少有人了解。大家对季先生作为学者的一面大有隔膜,是一件丝毫不奇怪的事情。我在这里受场合和时间的限制,也没有可能予以详细的评说,只能尽量用最简单的语言做最简略的介绍,希望对大家了解季先生作为学者的一面有所帮助。

季先生的主要的学术生涯和学术贡献都可以非常清晰的被分成三段。从一九三五年赴德国哥廷根大学留学到一九四五年回国为第一阶段。季先生的留学,抱有一个和当时的流俗截然不同的想法,那就是绝对不利用自己是一个中国人的先天优势,做和中国研究有任何关联的题目。换句话说,季先生对那种在国外靠孔子、庄子、老子把洋人哄得一愣一楞以获得博士学位,而回到国内却又靠黑格尔、康德、尼采把国人唬得一愣一愣以成为名教授的人,是很不以为然的。他决心进入当时国际人文学科的最前沿,在洋人拥有巨大先天优势、深厚传统的印欧语言学领域里大展身手,所谓入其室、操其戈而伐其人。因此,季先生留德期间所学的课程和汉学几乎完全无关,他的主科是印度学,副科是英国语言学和斯拉夫语言学,主要精力放在梵文、巴利文、吠陀文、佛教混合梵文、俗语、吐火罗语、俄语、南斯拉夫语、阿拉伯语等的学习和研究上。季先生留德期间完成和发表在德国最权威刊物上的几篇非常厚重的论文,都以当时印欧语言学领域最前沿的问题为关注点,并且引起了轰动,其影响一直延续到今天。这些论文不仅解决了所要讨论的问题,更重要的是在这些领域都做出了方法论层面的重要贡献:比如,利用语尾变化、特殊的动词形态等语法形式,在几乎没有没有信史资料的情况下解决佛典的年代和来源问题,利用不同语言的平行译本解决还几乎处在破译阶段的吐火罗语的语义问题,甚至还解决了古希腊语里面一个从未得到确切理解的重要语尾的问题!这些都是具有极其重要的学术意义的。季先生本人有《留德十年》,大家可以参看。

一九四五年,季先生放弃了在德国的教职和英国剑桥大学的邀请,离开德国,到一九七八年,长达三十多年的时间,可以看作是季先生学术生涯的第二个阶段。这是三十四岁到六十五岁,学者最珍贵的黄金年龄阶段,这理应是季先生学术生涯最辉煌的阶段。然而,由于众所周知的原因,却是最暗淡无光的苦难的时期。这个阶段勉强还可以一分为二。一九四六年到文革的二十年为前半阶段,受到国内资料和对外联络、政治环境等等的限制,用季先生自己的话来说,只能“有多大碗,吃多少饭”了。季先生无奈地放弃了在德国已经打下极好基础、具有极高起点的本行研究,被迫转而将主要精力投入到中印交流史、佛教史研究以及翻译工作上。至于从一九六六年以后可以看作是后半阶段,季先生几乎被迫害至死,好几次被打得只能自己爬回家,好几次动了自杀的念头,哪里还谈得上什么学术研究。只有在文革的后期,季先生担心自己把梵文给忘了,偷偷地开始翻译《罗摩衍那》,这完全不是季先生的本意,我们只能说这是伤心滴血的辉煌了。季先生的《牛棚杂忆》就是写自己在这后半段的遭遇的,大家都知道,那是一部记录疯狂野蛮时代的杰作。

第三阶段从一九七八年开始,当然到今天也没有结束。季先生恢复了学术研究,在承担常人无法想象的繁重的社会、学术领导工作的同时,真是争分夺秒,以拼命的态度抢回失去的时光。在这个阶段,季先生有机会接触国外的最新材料,于是接续在留德期间奠基的研究,不断地发现、补充新材料,进一步论证推衍自己的判断和结论。第二阶段无奈地开始的中印文化交流史、佛教史的研究,也在这个阶段绽放出奇光异彩,厚厚的一部《糖史》就是证明之一。季先生还毅然接受了一个巨大的挑战,研究、翻译、考证了新疆发现的、篇幅最大的吐火罗语文献《弥勒会见记》,这项研究难度之大、成就之高,震撼了国际学术界。大家别忘了,这时候的季先生已经是七、八十岁的高龄了,且不说他肩上担负着多少重要的工作,就以这样的高龄承担这样的研究任务这一点而言,就已经足以让我这样的后生小辈叹为观止了。更重要的是,我们绝对不能忘记,一直到今天,季先生还是中国唯一一个可以释读吐火罗语本身的学者,也就是说,如此高龄的季先生在为捍卫吐火罗语发现地中国的学术荣誉而孤身奋战!这怎么能够不让我这样的门生弟子、后生晚辈汗颜呢?

我上面的介绍远远不足以涵盖季先生作为学者的成就。好在我写了《季门立雪》,里面有相对而言比较全面的介绍。

我们还必须牢记,在这第三阶段,季先生的大量精力还投入到包括敦煌学、吐鲁番学、比较文学等等新的学术领域和学术组织的开创、建立、完善上了。我在前面提到过,季先生曾经一身担任了一百多个学术领导职务,为新时期中国学术的繁荣发展呕心沥血、竭尽全力,做出了别人无法替代也很难相比的巨大贡献。季先生赢得中国学术界的广泛尊敬,难道不是理所当然的吗?我们难道不应该对季先生抱有一份感激之情吗?

我曾经说过这样的话,季先生最大的魅力,就是仿佛无法用堂皇的语言来言说他的魅力。我这么说,也许会令很多人感到失望。但是用在季先生身上的形容词,最合适的大概还是纯粹和平淡。季先生当然不是神,也不是圣人。但是,作为一个从各种运动中走出来的知识分子,最难能可贵的是,他保持了人生的清白坦荡,任何人无法对这一点有任何指责和争论。该守望、该坚持的东西,季先生一样也没有放弃。

在那个年代,季先生这样的人原本是一个群体现象,而到了现在,季先生和他那样的人成了孤零零的个体现象了。这是值得我们深思的。

一个对他人、对社会满怀着爱和责任感的老人,在一个普遍以自我为中心的年代里“走俏”了;一个象土地般朴素、真诚,从来不追名逐利的老人,在一个讲究包装、炒作、媚俗的年代里“走俏”了,这就是我说“看不懂”的原因。

但是,我清楚地知道,坚定地相信,我们的时代正需要这样的世纪老人,在季先生的身上寄托了善良的人们太多的精神梦想。对季先生的这种珍惜和尊崇,当然让我这个弟子感到快乐,但同时也让我陷入到一种茫然和悲哀之中:难道我们不应该看到,在这股热的背后隐藏着在精神、道德和人文情怀方面的贫乏和苍白么?

季先生已经到了天高云淡的境界。我在想,老人家若是知道了我今天的这些讲演,会说什么呢?老人的心里会怎么想呢?我不知道,但是,我觉得季先生也许会象巴金老人这样说:“从现在起,我是为你们而活。”