SlideShare uma empresa Scribd logo
1 de 4
Baixar para ler offline
120 程序员
Technology技术
本期的问题是:
对于有 K个元素的数组int a[K]={....};写一个高效算法将
数组内容循环左移 m 位
比如:int a[6] ={1,2,3,4,5,6},循环左移 3 位得到结果
{456123},
要求:
1.不允许另外申请数组空间,但可以申请少许变量;
2.不允许采用每次左移。
这是一个有趣的问题,有朋友给出过一个很简单的解法:
1.将整个数组倒排;
2.将前 k-m 个元素和剩下的 m 个元素分别倒排。
这个算法需要对每个数组元素做两次写操作,具体而言是
2n次堆变量写操作和 n次栈变量写操作(因为倒排时调用交换
算法需要一个中间变量),有没有一种方法,只对数组元素进行
一次写操作就完成移动?
最直观的想法,就是从第一个元素开始,把它一步移动到
最终的目的位置,而该位置原有的元素的值取出,移动到它的
新位置。递归进行这个步骤。
首先,我们在数学上很容易理解,这是一个一一对应的映
射,绝不会在一个位置上出现两次移动。所以不会出现移动的
递归过程中途指向了已经移动过的元素。
那么,这个递归过程唯一的终止条件就是,当前移动的元
素,目的位置是移动过程的起始位置。
有兴趣的朋友不妨在纸上推演一下这个过程,并不复杂。
多试验几种组合,细心的朋友也许会发现,这个递归过程有时
候可以遍历整个数组,有时候则会跳过若干元素。这其中有没
有什么规律?
如果按照元素的索引下标标示元素,0到k-1中的任意元素
i,会移动到什么位置?
如果 i小于 m,它会移动到k-m+i,否则,它的新位置是i-
m。这个过程其实可以统一在一个算式下:
对于任意的 i,它的新位置 i' = ((k - m) + i )%k。
那么,我们可以定义这个循环链:取整数 i0,使得 0=<i0
<m,定义 i1=((k-m)+i0)%k,i2=((k-m) + i1)%k……ix =
((k-m) + ix-1)%k。当 ix=i0 时循环终止。此时有i0 = ix =
((k-m) + ix-1)%k = ……=(x(k-m)+i0)%k。
因为我们知道 0=<i0<m,所以有 0 = x(k-m)%k,也就
是说,x(k-m) = yk,因为我们是遇到第一个x(k-m) = yk就
终止,显然等号左右的值就是 k-m和 k的最小公倍数。根据数
论知识,我们知道,k,m,k-m 这三个数有最大公约数 q,使
得 k=aq,m=bq,k-m=cq,a,b,c三个数两两互质。进而推出
x = a,y = c。也就是说,这个递归过程会经历 a 步。如果 k
和 m互质,a=k,递归过程会遍历整个区间。那么,它可以完成
对整个区间的移动操作。而如果k和 m的最大公约数q>1呢?
在这里有一个现象,任意两个 i,它们的差要么是 0,要么是 k
和 m 的最大公因是 q的整倍数。有兴趣的朋友可以尝试证明一
下。因为我们知道整个过程一共 a 步,k=aq,那么,i到 ix的序
列会形成一个步长为q的等差序列。所以,我们要移动整个0到
k-1区间,应该对 0 到 q-1 的元素应用这个递归算法。
这样的算法只需要一次堆变量写操作,但是因为需要一个
中间变量储存移动的元素,需要2n次栈变量写操作。再加上计
算目的地址,每次移动时所需的计算量略大于两次倒排,但是
在堆变量操作方面提高了效率。
本次大部分合格的参赛作品都采用了冒泡算法,通过两两交
换邻接元素来移动数组。有朋友还在来信中说明冒泡排序是线性
复杂度。这是错误的。冒泡法是o(n2)的,比起前面两种算法,冒
泡的效率太过低下。很多朋友在m大于或小于k/2时采用的不同
的左 /右位移代码,其实只要理清了算法,不必要做此判断。只
有一位ID为njwind 的朋友想到了利用数论知识。虽然他的代码还
达不到实用标准,但是这应该是本次比赛最好的作品了:
#include <stdio.h>
#include <stdlib.h>
#define Len 6
/* 求最大公约数的函数 */
int CommonFactor(int m,int n){
  int tmp;
  if(m<n) {
      tmp = m; m = n; n = tmp;
  }
  tmp = m % n;
移动内存算法
□ 文 / 刘鑫
智慧擂台 >>>
Programmer 121
  while(tmp != 0) {
    m = n;  n = tmp;  tmp = m % n;
  }
  return n;
}
void display(int *pa){
   int i;
   printf("array: ");
   for(i=0;i<Len; i++)   printf("%d ",pa[i]);
   printf("\n");
}
void swap(int *n1, int *n2){
    int tmp;
    tmp = *n1;  *n1 = *n2;  *n2 = tmp;
}
/* *p 数据指针,aLen:数据长度,k:左循环位数 */
void LeftRotation(int *p, int aLen, int k){
   int i,tmp,factor;
   k = k % aLen;
   if ( k == 0) return;
   k = aLen - k;
   factor = CommonFactor(aLen, k);
   if (factor == 1){
     i = 0;
     do{
         i = (i+k)%aLen;
         swap(p, p + i ) ;
     } while(i != 0);
   }
   else{
       for (i = 0;i < factor; i++){
         tmp = i;
         do{
             tmp = (tmp+k)%aLen;
             swap(&p[i], p + tmp ) ;
         } while(tmp != i);
       }
   }
}
int main(int argc, char *argv[]){
  int i,k,a[Len]={1,2,3,4,5,6};
  for(i=0;i<8;i++){
      for( k = 0; k<Len ;k++)  /* 数组赋值 */
         a[k] = k+1;
      k = i;  display(a);
      printf("Len: %d, left rotation: %d\n",Len,k);
      LeftRotation(a,Len,k);
      display(a);   printf("---------------\n");
 }
  system("PAUSE");  return 0;
}
以下是用 C++实现的一次移动算法代码,并进行了泛化,
使之可以适用于不同的类型,包括用不同整型变量表示k,m等
参数的应用:
求最大公因数,辗转相除,可以应用于任何求最大公因式/
数的场合,只要参数类型支持求余和赋值:
template<typename intT>
intT HCF(const intT & x, const intT & y) {
    intT a = x, b = y, r = a%b;
    while(r != 0) {
        a = b; b = r; r = a%b;
    }
    return b;
};
区间移动,支持任何类型的数组:
template<typename T,typename U>
void Carry(T point[], const U & len, const U & m){
    U start = 0,p = 0;
    T pv;
    U hloc = HCF(len, m);
    U step = len - m;
    for (U i = 0; i<hloc; i++) {
        p = i; start = p; pv = point[p] ;
        do {
            p = (step+p)%len;
            std::swap(point[p] , pv);
        }while(p != start);
    }
};
用迭代器实现的区间移动,可以应用于 STL 容器等场合:
template<typename iterT,typename U>
void Carry(iterT &iter, const U & len, const U & m) {
    iterT nb = iter + (len-m);
    iterT p;
    iterT start = point;
    iterT pm = point + m;
    iterator_traits<iterT>::value_type pv;
    U hloc = HCF(len, m);
    for (U i = 0; i<hloc; i++) {
        p = point + i;
        start = p; pv = *p ;
        do {
            if (p < pm)
                p = nb + (p - point);
            else
                p -= m;
            std::swap(*p , pv);
        }while(p != start);
    }
};
代码中使用了 std::swap 函数来交换变量值,这个函数在
<algorithm>中。另外为了析取迭代器的值,我使用了<iterator>
中的iterator_traits操作。有兴趣的朋友不妨编写一个适用于普通
指针的偏特化版本。
两步倒排算法的实现很简单,在这里就不写出来了。重点
是采用一个足够简单的交换和计算中界的代码。这样的功能,C
风格的代码就可以做到足够好了。
有些朋友认为直接改变索引就可以重排数组,对于某些高
级语言,例如 Python中的内置线性容器list,这是可以的。但是
在C/C++中,数组和链表是不同的概念,数组是内存堆中的连
续块,不可以用这种方法来对待。对于C/C++程序,我们经常
要直接操作内存,要关注算法的复杂度,这并不是缺点,相反,
无论高级的虚拟机语言有多少好处,总需要有底层的技术来管
理内存,用尽可能高效的算法处理面向硬件的问题。否则,用
什么来开发虚拟机呢?这个算法问题实际上在内存管理,例如
虚拟机的实现方面,就有很大意义。在虚拟机内存管理中,我
们面对的总是不够快的 CPU和不够大的内存,需要有一个高效
的算法来移动虚拟机管理的数据。对于Java或 C#程序员,这
个过程通常是透明的,但是这不表示它不存在。而默默支撑起
虚拟机的,正是这些 C/C++ 代码。
>>> 智慧擂台
Programmer 123
特性并把这个构件放到一个特定的地方,
这个构件就不仅仅会收到一个位置协调的
消息,并且会记住为什么它会被抓取。例
如,如果它被抓取同另外一个构件的左边
对齐,这个时候该构件会始终保持它们的
左对齐格式,即使它们的绝对位置发生了
改变。
NetBeans中有双路编辑——使用一个可
视化设计器和一个文本编辑器。一些可视化
设计器已经实现了这种方式。但是NetBeans
IDE使用保护模块来防止用户编辑代码。
Eclipse的 Visual Editor
Visual Editor是一个开源的 Eclipse 编
辑器。它同 JDT、PDE等其它 Eclipse 的工
具项目一样,是一个全新的Eclipse工具项
目。它可以进行可视化的编辑Java GUI程
序,也能编辑可视化的Java Bean组件。它
能与 Eclipse的Java Editor集成在一起,当
在 Visual Editor中编辑图形界面时,会立
即反馈到 Java Editor中的代码,反之亦
然,即无保护的双路编辑。
Visual Editor支持Swing和AWT的可视
Java组件开发。由于这个Framework设计的
具有通用性,它也可以很容易的实现C++
或其它语言下可视化开发。其将来的版本
(从 1.0 开始),将会支持SWT的开发。
Visual Editor目前支持所有的传统的
布局管理器。另外,SWT Designer也是流
行的 GUI 编辑器,不过是收费的。
JBuilder 的布局管理器
除了经典的布局管理器外,JBuilder
提供了五个方便的布局管理器,它们是:
(1)XYLayout 布局管理器:组件所在
的位置通过相对于左上角坐标确定,其大
小通过宽度和长度确定,当窗口大小发生
变化时,组件的位置和大小保持原位。
(2)PaneLayout 布局管理器:通过百
分比规定组件所占容器空间,当用户界
面调整时,组件的大小也会相应调整。
(3)VerticalFlowLayout 布局管理器:
它和FlowLayout 类似,只不过它以垂直而
非水平的方式排列组件。
(4)BoxLayout2 布局管理器:它是
Swing 标准包中javax.swing.BoxLayout 布
局管理器的一个包裹类,允许你通过查
看器的选择,间接使用BoxLayout的功能。
BoxLayout 将几个组件组合在一起,以水
平或者垂直的方式排列,窗口大小调整
时,组件大小不会随着改变。
(5)OverLayOut2 布局管理器:它是
Swing 标准包中 java.swing.OverLayout 布
局管理的包裹类,允许你通过察看器的
选择,间接使用 OverLayout 的功能。
GUI小结
GUI设计部分,我更喜欢NetBeans,相
信很多用户也跟我一样,因为用起来真
的很方便。
曾看见有人说,在拖拽组件时,却不
能更改代码,觉得很别扭。其实我觉得受
保护的双路编辑才是应该推崇的方法,
这也是对 IDE完美工作的一种保证。
二.编译、运行、调试、打包
本节将比较三个平台在编译、运行、
调试、打包几个必要开发步骤中的具体
表现。
NetBeans
在代码行开头点击即可设置 / 取消
断点;支持条件断点、单步执行等流程控
制功能;支持局部变量、监视、堆栈显示等
功能;支持会话、线程的查看及修改;提
供了完善的远程调试功能;基于Ant,可
通过脚本支持调试。
Eclipse
带有专用的 Debug 视图并能自动切
换;其Debug的功能和Delphi的Debug比较
相似,Inspect、Watch等应有尽有;支持反
汇编、内存、堆栈、寄存器显示等高级功
能;支持会话、线程的查看及修改;似乎
无远程调试;可根据模块的需求扩展。
JBuilder
高度集成,十分丰富的调试环境,支
持以上2款IDE的全部功能;4种编译器及各
自特有的编译选项:Borland Make、Borland
Make(JB8)、Project javac、javac;智能单步、
智能源码、智能交换;多线程调试;内置混
淆打包;JBuilder的调试环境可谓傲视群伦,
开发纯java程序时,使用起来十分方便。
三.WEB 与 J2EE 开发
JSP、Servlet
NetBeans支持Servlet 2.4和JSP 2.0。
支持使用 Tomcat 5 部署和调试两层 J2EE
1.4 和 1.3 应用程序。以下是 NetBeans 为
Web应用程序开发提供的便利:内置Tomcat
服务器支持;生成和维护部署容易的内
容,包括添加到项目中的 Servlets进行注
册;生成与维护具有编译、清除、测试、
打包、部署指令的Ant脚本。该脚本使开
发者无需手动将文件移动到服务器;用
于编辑 Servlets、JSP、HTML和标签库的
代码自动完成和帮助;提供“编译JSP”命
令,使用这一命令可以帮助开发者在部
署前检测JSP文件的错误,不管这些错误
出现在编译过程中还是 J S P 文件向
Servlets 转换过程中;提供全面的调试支
持,包括“步进JSP文件”以及“跟踪HTTP
请求”;大量的 Web模板:JSP、Servlet、
Filter、Web应用侦听器、标签库描述、标
签、标签处理、Web Service、消息处理、
Web客户端等;描述文件web.xml可视化
编辑器;监测 HTTP 事务处理。
E c l i p s e 在不安装 L O M B O Z 或者
MyEclipse 的情况下编写 Web应用程序真
是麻烦之极。首先你需要手动安装Tomcat
或者其他服务器,然后在Eclipse 中配置;
接下来编写代码,再更改web.xml文件做
部署。最后很可能因为配置不好的原因,
无法启动或者部署Web服务器。好在对web
.xml编辑时也是可视化的。
JBuilder一体化的解决办法倒是很好,
并且通过 OpenTools 框架支持很多种Web
服务器。当然也需要手动安装这些服务
器,并且添加这些服务器的 Lib到你的项
>>> SUN 征文
124 程序员
Product & Application产品&应用
框架名称
Struts
Hibernate
Spring
Cocoon
JSF
NetBeans 5.5 Eclipse 3.x JBuilder 2005
支持,向导,文档丰富 MyEclipse 良好支持 支持,向导,文档丰富
Nbxdoclet支持,5.5加 Hibernate Syn 支持 手动配置
入数据库结构和实体类
的相互生成和向导
支持,向导,文档丰富 Spring plugin 4 Eclipse 手动配置
Spring for JBuilder2005 OpenTools
暂没找到直接支持 Lepido 支持 支持,向导,文档丰富
支持,向导,文档丰富 JSF Tool Project 支持 支持,向导,文档丰富
目中。JBuilder还为各种部署文件提供了
方便的编辑工具:
l web.xml:Web Module DD Editor
l struts-config.xml:Struts Config Editor
l faces-config.xml:Faces Config Editor
另外JBuilder也对Jsp和Servlet提供监
听器,监视各种事件的发生。
JBuilder 提供了最为完善的Web开发
环境,其次 Netbeans功能也十分丰富。
EJB/J2EE
NetBeans
从 NetBeans IDE 4.1 版本开始,
NetBeans 提供创建和编辑 EJB丰富的向导
和编辑器。
NetBeans 5.0提供以下针对企业开发
的支持:建立和编辑EJB的可视化编辑器;
控制 CMP和实体 Bean关系的可视化编辑
器;通过鼠标点击就可以在Web模块中加
入对 EJB的调用;完整的组装、部署、运
行和调试企业应用程序的支持;注册和
测试Web Service;通过鼠标点击就可以在
Web模块或EJB中加入对Web Service的调
用;由EJB或者Java类自底向上的建立Web
Service;由WSDL文件自顶向下的建立Web
Service;可以导入其他 IDE的J2EE项目,前
提是其与 BluePrints标准兼容。
Eclipse与 Lomboz
Lomboz是Eclipse的一个主要的开源插
件(open-source plug-in),Lomboz插件能
够使Java开发者更好的使用Eclipse去创建,
调试和部署基于J2EE的 Java应用服务器。
Lomboz 的主要功能有:使用 HTML,
Servlets,JSP 等方式建立 Web应用程序;
J S P 的编辑带有高亮显示和编码助手、
JSP语法检查;利用Wizard创建Web应用、
EJB应用和 EJB客户端测试程序;支持部
署 EAR、WAR和 JAR;利用xDoclet 开发符
合 EJB 1.1、2.0和 3.0的应用;能够实现
端口对端口的本地和远程的测试应用服
务;能够支持所有的有可扩展定义的Java
应用服务;能够利用强大的Java调试器调
试正在运行的服务器端代码(JSP&EJB);
通过使用 Wizard 和代码生成器提高开发
效率;创建Web服务客户端的WSDL形式
的文件。
Lomboz 适用的服务器有:Apache
Tomcat,JBOSS,JOnAS,Resin,Orion,JRun,
Oracle IAS,BEA WebLogic Server和 IBM
WebSphere等。
三种平台对框架的支持比较
小 结
对于J2EE 开发,Eclipse的各种支持是
对全面和及时的,但是否成熟,则未必。并
且开发者经常被成堆的插件弄得头昏脑胀。
NetBeans的最新版本提供了对最新标
准,如EJB 3.0 的支持,并且内置对常见
框架支持。这说明,现在完全能够全面转
向 NetBeans。
四.J2ME 开发
NetBeans Mobility
Netbeans IDE和 Mobility Pack 提供的
项目管理功能非常出色,将目标平台、应
用程序描述符、编译运行、混淆、签名等
功能集成在了一起。开发者只需要选中
项目,右键选择属性即可配置上述选项。
值得注意的一点是,当项目中使用了图
片或者媒体文件等资源的时候,应该在
“库和资源”选项中讲资源文件所在的文
件夹添加到“捆绑的库和资源”中。避免
在 Java 程序中访问资源的时候抛出空指
针异常。Mobility Pack 还直接集成了
Proguard 混淆器,可以设置混淆的级别,
混淆的级别越高,混淆的力度就越大。
Mobility Pack提供了可视化用户界面
设计器,开发者可以用鼠标拖拽的方式
设计应用程序的用户界面,通过流程控
制器实现界面之间的跳转,而不用编写
任何代码。无线连接向导是Mobility Pack
另一新特性,能方便快速的开发出端到
端的企业级应用程序,服务器端只提供
需要导出的服务类,Netbeans IDE会自动
生成服务器端的 Servlet 以及客户端用于
连接网络的代码。虽然上述两个功能使
用起来非常方便,但是缺乏灵活性,你很
难再更改开发工具为你自动生成的代码。
Eclipse 和 EclipseME
不仅要下载安装 EclipseME插件,还
要安装 WTK,并且在 Eclipse环境中配置。
使用 Eclipse 搭建 J 2 M E 的开发环境比
Netbeans IDE稍显复杂。事实上,管理
Eclipse 的各种插件已经让开发者头疼不
已,有些插件的更新还很难保证。
JBuilder 和 WTK
从JBuilder 9版本开始,Borland将WTK
直接集成到了开发工具内。如果使用以
前版本的 JBuilder,那么需要首先安装
MoblieSet 插件。
小 结
其实,各种开发工具只是以自己的
方式对 M I D P 应用程序的开发进行了封
装, MIDP应用程序的开发流程都是一样。
事实已经证明,除了使用手机供应商自
己的套件外(如 Nokia Toolkit),WTK和
NetBeans Mobility的用户最多——这方面
SUN 征文 >>>

Mais conteúdo relacionado

Mais de Chui-Wen Chiu

Mais de Chui-Wen Chiu (20)

Python 庫簡介
Python 庫簡介Python 庫簡介
Python 庫簡介
 
Asp.Net Mvc 1.0
Asp.Net Mvc 1.0Asp.Net Mvc 1.0
Asp.Net Mvc 1.0
 
天下第一 夜市總冠軍
天下第一 夜市總冠軍天下第一 夜市總冠軍
天下第一 夜市總冠軍
 
下班就跑是富有哲學道理1
下班就跑是富有哲學道理1下班就跑是富有哲學道理1
下班就跑是富有哲學道理1
 
認識腸病毒
認識腸病毒認識腸病毒
認識腸病毒
 
排隊的店
排隊的店排隊的店
排隊的店
 
柬埔寨鄉村婚禮
柬埔寨鄉村婚禮柬埔寨鄉村婚禮
柬埔寨鄉村婚禮
 
新 創 意
新 創 意新 創 意
新 創 意
 
挖好屬於自己的井
挖好屬於自己的井挖好屬於自己的井
挖好屬於自己的井
 
Why The Us Wants War 080702
Why The Us Wants War  080702Why The Us Wants War  080702
Why The Us Wants War 080702
 
你今天的選擇是什麼?
你今天的選擇是什麼?你今天的選擇是什麼?
你今天的選擇是什麼?
 
我的學思歷程 劉兆玄
我的學思歷程 劉兆玄我的學思歷程 劉兆玄
我的學思歷程 劉兆玄
 
Unknown Parameter Value
Unknown Parameter ValueUnknown Parameter Value
Unknown Parameter Value
 
你也在井裡嗎
你也在井裡嗎你也在井裡嗎
你也在井裡嗎
 
世界是平的
世界是平的世界是平的
世界是平的
 
感觸
感觸感觸
感觸
 
從衛星看地球奇景
從衛星看地球奇景從衛星看地球奇景
從衛星看地球奇景
 
感觸
感觸感觸
感觸
 
Pressure
PressurePressure
Pressure
 
全球暖化 明日的..
全球暖化  明日的..全球暖化  明日的..
全球暖化 明日的..
 

移動內存算法

  • 1. 120 程序员 Technology技术 本期的问题是: 对于有 K个元素的数组int a[K]={....};写一个高效算法将 数组内容循环左移 m 位 比如:int a[6] ={1,2,3,4,5,6},循环左移 3 位得到结果 {456123}, 要求: 1.不允许另外申请数组空间,但可以申请少许变量; 2.不允许采用每次左移。 这是一个有趣的问题,有朋友给出过一个很简单的解法: 1.将整个数组倒排; 2.将前 k-m 个元素和剩下的 m 个元素分别倒排。 这个算法需要对每个数组元素做两次写操作,具体而言是 2n次堆变量写操作和 n次栈变量写操作(因为倒排时调用交换 算法需要一个中间变量),有没有一种方法,只对数组元素进行 一次写操作就完成移动? 最直观的想法,就是从第一个元素开始,把它一步移动到 最终的目的位置,而该位置原有的元素的值取出,移动到它的 新位置。递归进行这个步骤。 首先,我们在数学上很容易理解,这是一个一一对应的映 射,绝不会在一个位置上出现两次移动。所以不会出现移动的 递归过程中途指向了已经移动过的元素。 那么,这个递归过程唯一的终止条件就是,当前移动的元 素,目的位置是移动过程的起始位置。 有兴趣的朋友不妨在纸上推演一下这个过程,并不复杂。 多试验几种组合,细心的朋友也许会发现,这个递归过程有时 候可以遍历整个数组,有时候则会跳过若干元素。这其中有没 有什么规律? 如果按照元素的索引下标标示元素,0到k-1中的任意元素 i,会移动到什么位置? 如果 i小于 m,它会移动到k-m+i,否则,它的新位置是i- m。这个过程其实可以统一在一个算式下: 对于任意的 i,它的新位置 i' = ((k - m) + i )%k。 那么,我们可以定义这个循环链:取整数 i0,使得 0=<i0 <m,定义 i1=((k-m)+i0)%k,i2=((k-m) + i1)%k……ix = ((k-m) + ix-1)%k。当 ix=i0 时循环终止。此时有i0 = ix = ((k-m) + ix-1)%k = ……=(x(k-m)+i0)%k。 因为我们知道 0=<i0<m,所以有 0 = x(k-m)%k,也就 是说,x(k-m) = yk,因为我们是遇到第一个x(k-m) = yk就 终止,显然等号左右的值就是 k-m和 k的最小公倍数。根据数 论知识,我们知道,k,m,k-m 这三个数有最大公约数 q,使 得 k=aq,m=bq,k-m=cq,a,b,c三个数两两互质。进而推出 x = a,y = c。也就是说,这个递归过程会经历 a 步。如果 k 和 m互质,a=k,递归过程会遍历整个区间。那么,它可以完成 对整个区间的移动操作。而如果k和 m的最大公约数q>1呢? 在这里有一个现象,任意两个 i,它们的差要么是 0,要么是 k 和 m 的最大公因是 q的整倍数。有兴趣的朋友可以尝试证明一 下。因为我们知道整个过程一共 a 步,k=aq,那么,i到 ix的序 列会形成一个步长为q的等差序列。所以,我们要移动整个0到 k-1区间,应该对 0 到 q-1 的元素应用这个递归算法。 这样的算法只需要一次堆变量写操作,但是因为需要一个 中间变量储存移动的元素,需要2n次栈变量写操作。再加上计 算目的地址,每次移动时所需的计算量略大于两次倒排,但是 在堆变量操作方面提高了效率。 本次大部分合格的参赛作品都采用了冒泡算法,通过两两交 换邻接元素来移动数组。有朋友还在来信中说明冒泡排序是线性 复杂度。这是错误的。冒泡法是o(n2)的,比起前面两种算法,冒 泡的效率太过低下。很多朋友在m大于或小于k/2时采用的不同 的左 /右位移代码,其实只要理清了算法,不必要做此判断。只 有一位ID为njwind 的朋友想到了利用数论知识。虽然他的代码还 达不到实用标准,但是这应该是本次比赛最好的作品了: #include <stdio.h> #include <stdlib.h> #define Len 6 /* 求最大公约数的函数 */ int CommonFactor(int m,int n){   int tmp;   if(m<n) {       tmp = m; m = n; n = tmp;   }   tmp = m % n; 移动内存算法 □ 文 / 刘鑫 智慧擂台 >>>
  • 2. Programmer 121   while(tmp != 0) {     m = n;  n = tmp;  tmp = m % n;   }   return n; } void display(int *pa){    int i;    printf("array: ");    for(i=0;i<Len; i++)   printf("%d ",pa[i]);    printf("\n"); } void swap(int *n1, int *n2){     int tmp;     tmp = *n1;  *n1 = *n2;  *n2 = tmp; } /* *p 数据指针,aLen:数据长度,k:左循环位数 */ void LeftRotation(int *p, int aLen, int k){    int i,tmp,factor;    k = k % aLen;    if ( k == 0) return;    k = aLen - k;    factor = CommonFactor(aLen, k);    if (factor == 1){      i = 0;      do{          i = (i+k)%aLen;          swap(p, p + i ) ;      } while(i != 0);    }    else{        for (i = 0;i < factor; i++){          tmp = i;          do{              tmp = (tmp+k)%aLen;              swap(&p[i], p + tmp ) ;          } while(tmp != i);        }    } } int main(int argc, char *argv[]){   int i,k,a[Len]={1,2,3,4,5,6};   for(i=0;i<8;i++){       for( k = 0; k<Len ;k++)  /* 数组赋值 */          a[k] = k+1;       k = i;  display(a);       printf("Len: %d, left rotation: %d\n",Len,k);       LeftRotation(a,Len,k);       display(a);   printf("---------------\n");  }   system("PAUSE");  return 0; } 以下是用 C++实现的一次移动算法代码,并进行了泛化, 使之可以适用于不同的类型,包括用不同整型变量表示k,m等 参数的应用: 求最大公因数,辗转相除,可以应用于任何求最大公因式/ 数的场合,只要参数类型支持求余和赋值: template<typename intT> intT HCF(const intT & x, const intT & y) {     intT a = x, b = y, r = a%b;     while(r != 0) {         a = b; b = r; r = a%b;     }     return b; }; 区间移动,支持任何类型的数组: template<typename T,typename U> void Carry(T point[], const U & len, const U & m){     U start = 0,p = 0;     T pv;     U hloc = HCF(len, m);     U step = len - m;     for (U i = 0; i<hloc; i++) {         p = i; start = p; pv = point[p] ;         do {             p = (step+p)%len;             std::swap(point[p] , pv);         }while(p != start);     } }; 用迭代器实现的区间移动,可以应用于 STL 容器等场合: template<typename iterT,typename U> void Carry(iterT &iter, const U & len, const U & m) {     iterT nb = iter + (len-m);     iterT p;     iterT start = point;     iterT pm = point + m;     iterator_traits<iterT>::value_type pv;     U hloc = HCF(len, m);     for (U i = 0; i<hloc; i++) {         p = point + i;         start = p; pv = *p ;         do {             if (p < pm)                 p = nb + (p - point);             else                 p -= m;             std::swap(*p , pv);         }while(p != start);     } }; 代码中使用了 std::swap 函数来交换变量值,这个函数在 <algorithm>中。另外为了析取迭代器的值,我使用了<iterator> 中的iterator_traits操作。有兴趣的朋友不妨编写一个适用于普通 指针的偏特化版本。 两步倒排算法的实现很简单,在这里就不写出来了。重点 是采用一个足够简单的交换和计算中界的代码。这样的功能,C 风格的代码就可以做到足够好了。 有些朋友认为直接改变索引就可以重排数组,对于某些高 级语言,例如 Python中的内置线性容器list,这是可以的。但是 在C/C++中,数组和链表是不同的概念,数组是内存堆中的连 续块,不可以用这种方法来对待。对于C/C++程序,我们经常 要直接操作内存,要关注算法的复杂度,这并不是缺点,相反, 无论高级的虚拟机语言有多少好处,总需要有底层的技术来管 理内存,用尽可能高效的算法处理面向硬件的问题。否则,用 什么来开发虚拟机呢?这个算法问题实际上在内存管理,例如 虚拟机的实现方面,就有很大意义。在虚拟机内存管理中,我 们面对的总是不够快的 CPU和不够大的内存,需要有一个高效 的算法来移动虚拟机管理的数据。对于Java或 C#程序员,这 个过程通常是透明的,但是这不表示它不存在。而默默支撑起 虚拟机的,正是这些 C/C++ 代码。 >>> 智慧擂台
  • 3. Programmer 123 特性并把这个构件放到一个特定的地方, 这个构件就不仅仅会收到一个位置协调的 消息,并且会记住为什么它会被抓取。例 如,如果它被抓取同另外一个构件的左边 对齐,这个时候该构件会始终保持它们的 左对齐格式,即使它们的绝对位置发生了 改变。 NetBeans中有双路编辑——使用一个可 视化设计器和一个文本编辑器。一些可视化 设计器已经实现了这种方式。但是NetBeans IDE使用保护模块来防止用户编辑代码。 Eclipse的 Visual Editor Visual Editor是一个开源的 Eclipse 编 辑器。它同 JDT、PDE等其它 Eclipse 的工 具项目一样,是一个全新的Eclipse工具项 目。它可以进行可视化的编辑Java GUI程 序,也能编辑可视化的Java Bean组件。它 能与 Eclipse的Java Editor集成在一起,当 在 Visual Editor中编辑图形界面时,会立 即反馈到 Java Editor中的代码,反之亦 然,即无保护的双路编辑。 Visual Editor支持Swing和AWT的可视 Java组件开发。由于这个Framework设计的 具有通用性,它也可以很容易的实现C++ 或其它语言下可视化开发。其将来的版本 (从 1.0 开始),将会支持SWT的开发。 Visual Editor目前支持所有的传统的 布局管理器。另外,SWT Designer也是流 行的 GUI 编辑器,不过是收费的。 JBuilder 的布局管理器 除了经典的布局管理器外,JBuilder 提供了五个方便的布局管理器,它们是: (1)XYLayout 布局管理器:组件所在 的位置通过相对于左上角坐标确定,其大 小通过宽度和长度确定,当窗口大小发生 变化时,组件的位置和大小保持原位。 (2)PaneLayout 布局管理器:通过百 分比规定组件所占容器空间,当用户界 面调整时,组件的大小也会相应调整。 (3)VerticalFlowLayout 布局管理器: 它和FlowLayout 类似,只不过它以垂直而 非水平的方式排列组件。 (4)BoxLayout2 布局管理器:它是 Swing 标准包中javax.swing.BoxLayout 布 局管理器的一个包裹类,允许你通过查 看器的选择,间接使用BoxLayout的功能。 BoxLayout 将几个组件组合在一起,以水 平或者垂直的方式排列,窗口大小调整 时,组件大小不会随着改变。 (5)OverLayOut2 布局管理器:它是 Swing 标准包中 java.swing.OverLayout 布 局管理的包裹类,允许你通过察看器的 选择,间接使用 OverLayout 的功能。 GUI小结 GUI设计部分,我更喜欢NetBeans,相 信很多用户也跟我一样,因为用起来真 的很方便。 曾看见有人说,在拖拽组件时,却不 能更改代码,觉得很别扭。其实我觉得受 保护的双路编辑才是应该推崇的方法, 这也是对 IDE完美工作的一种保证。 二.编译、运行、调试、打包 本节将比较三个平台在编译、运行、 调试、打包几个必要开发步骤中的具体 表现。 NetBeans 在代码行开头点击即可设置 / 取消 断点;支持条件断点、单步执行等流程控 制功能;支持局部变量、监视、堆栈显示等 功能;支持会话、线程的查看及修改;提 供了完善的远程调试功能;基于Ant,可 通过脚本支持调试。 Eclipse 带有专用的 Debug 视图并能自动切 换;其Debug的功能和Delphi的Debug比较 相似,Inspect、Watch等应有尽有;支持反 汇编、内存、堆栈、寄存器显示等高级功 能;支持会话、线程的查看及修改;似乎 无远程调试;可根据模块的需求扩展。 JBuilder 高度集成,十分丰富的调试环境,支 持以上2款IDE的全部功能;4种编译器及各 自特有的编译选项:Borland Make、Borland Make(JB8)、Project javac、javac;智能单步、 智能源码、智能交换;多线程调试;内置混 淆打包;JBuilder的调试环境可谓傲视群伦, 开发纯java程序时,使用起来十分方便。 三.WEB 与 J2EE 开发 JSP、Servlet NetBeans支持Servlet 2.4和JSP 2.0。 支持使用 Tomcat 5 部署和调试两层 J2EE 1.4 和 1.3 应用程序。以下是 NetBeans 为 Web应用程序开发提供的便利:内置Tomcat 服务器支持;生成和维护部署容易的内 容,包括添加到项目中的 Servlets进行注 册;生成与维护具有编译、清除、测试、 打包、部署指令的Ant脚本。该脚本使开 发者无需手动将文件移动到服务器;用 于编辑 Servlets、JSP、HTML和标签库的 代码自动完成和帮助;提供“编译JSP”命 令,使用这一命令可以帮助开发者在部 署前检测JSP文件的错误,不管这些错误 出现在编译过程中还是 J S P 文件向 Servlets 转换过程中;提供全面的调试支 持,包括“步进JSP文件”以及“跟踪HTTP 请求”;大量的 Web模板:JSP、Servlet、 Filter、Web应用侦听器、标签库描述、标 签、标签处理、Web Service、消息处理、 Web客户端等;描述文件web.xml可视化 编辑器;监测 HTTP 事务处理。 E c l i p s e 在不安装 L O M B O Z 或者 MyEclipse 的情况下编写 Web应用程序真 是麻烦之极。首先你需要手动安装Tomcat 或者其他服务器,然后在Eclipse 中配置; 接下来编写代码,再更改web.xml文件做 部署。最后很可能因为配置不好的原因, 无法启动或者部署Web服务器。好在对web .xml编辑时也是可视化的。 JBuilder一体化的解决办法倒是很好, 并且通过 OpenTools 框架支持很多种Web 服务器。当然也需要手动安装这些服务 器,并且添加这些服务器的 Lib到你的项 >>> SUN 征文
  • 4. 124 程序员 Product & Application产品&应用 框架名称 Struts Hibernate Spring Cocoon JSF NetBeans 5.5 Eclipse 3.x JBuilder 2005 支持,向导,文档丰富 MyEclipse 良好支持 支持,向导,文档丰富 Nbxdoclet支持,5.5加 Hibernate Syn 支持 手动配置 入数据库结构和实体类 的相互生成和向导 支持,向导,文档丰富 Spring plugin 4 Eclipse 手动配置 Spring for JBuilder2005 OpenTools 暂没找到直接支持 Lepido 支持 支持,向导,文档丰富 支持,向导,文档丰富 JSF Tool Project 支持 支持,向导,文档丰富 目中。JBuilder还为各种部署文件提供了 方便的编辑工具: l web.xml:Web Module DD Editor l struts-config.xml:Struts Config Editor l faces-config.xml:Faces Config Editor 另外JBuilder也对Jsp和Servlet提供监 听器,监视各种事件的发生。 JBuilder 提供了最为完善的Web开发 环境,其次 Netbeans功能也十分丰富。 EJB/J2EE NetBeans 从 NetBeans IDE 4.1 版本开始, NetBeans 提供创建和编辑 EJB丰富的向导 和编辑器。 NetBeans 5.0提供以下针对企业开发 的支持:建立和编辑EJB的可视化编辑器; 控制 CMP和实体 Bean关系的可视化编辑 器;通过鼠标点击就可以在Web模块中加 入对 EJB的调用;完整的组装、部署、运 行和调试企业应用程序的支持;注册和 测试Web Service;通过鼠标点击就可以在 Web模块或EJB中加入对Web Service的调 用;由EJB或者Java类自底向上的建立Web Service;由WSDL文件自顶向下的建立Web Service;可以导入其他 IDE的J2EE项目,前 提是其与 BluePrints标准兼容。 Eclipse与 Lomboz Lomboz是Eclipse的一个主要的开源插 件(open-source plug-in),Lomboz插件能 够使Java开发者更好的使用Eclipse去创建, 调试和部署基于J2EE的 Java应用服务器。 Lomboz 的主要功能有:使用 HTML, Servlets,JSP 等方式建立 Web应用程序; J S P 的编辑带有高亮显示和编码助手、 JSP语法检查;利用Wizard创建Web应用、 EJB应用和 EJB客户端测试程序;支持部 署 EAR、WAR和 JAR;利用xDoclet 开发符 合 EJB 1.1、2.0和 3.0的应用;能够实现 端口对端口的本地和远程的测试应用服 务;能够支持所有的有可扩展定义的Java 应用服务;能够利用强大的Java调试器调 试正在运行的服务器端代码(JSP&EJB); 通过使用 Wizard 和代码生成器提高开发 效率;创建Web服务客户端的WSDL形式 的文件。 Lomboz 适用的服务器有:Apache Tomcat,JBOSS,JOnAS,Resin,Orion,JRun, Oracle IAS,BEA WebLogic Server和 IBM WebSphere等。 三种平台对框架的支持比较 小 结 对于J2EE 开发,Eclipse的各种支持是 对全面和及时的,但是否成熟,则未必。并 且开发者经常被成堆的插件弄得头昏脑胀。 NetBeans的最新版本提供了对最新标 准,如EJB 3.0 的支持,并且内置对常见 框架支持。这说明,现在完全能够全面转 向 NetBeans。 四.J2ME 开发 NetBeans Mobility Netbeans IDE和 Mobility Pack 提供的 项目管理功能非常出色,将目标平台、应 用程序描述符、编译运行、混淆、签名等 功能集成在了一起。开发者只需要选中 项目,右键选择属性即可配置上述选项。 值得注意的一点是,当项目中使用了图 片或者媒体文件等资源的时候,应该在 “库和资源”选项中讲资源文件所在的文 件夹添加到“捆绑的库和资源”中。避免 在 Java 程序中访问资源的时候抛出空指 针异常。Mobility Pack 还直接集成了 Proguard 混淆器,可以设置混淆的级别, 混淆的级别越高,混淆的力度就越大。 Mobility Pack提供了可视化用户界面 设计器,开发者可以用鼠标拖拽的方式 设计应用程序的用户界面,通过流程控 制器实现界面之间的跳转,而不用编写 任何代码。无线连接向导是Mobility Pack 另一新特性,能方便快速的开发出端到 端的企业级应用程序,服务器端只提供 需要导出的服务类,Netbeans IDE会自动 生成服务器端的 Servlet 以及客户端用于 连接网络的代码。虽然上述两个功能使 用起来非常方便,但是缺乏灵活性,你很 难再更改开发工具为你自动生成的代码。 Eclipse 和 EclipseME 不仅要下载安装 EclipseME插件,还 要安装 WTK,并且在 Eclipse环境中配置。 使用 Eclipse 搭建 J 2 M E 的开发环境比 Netbeans IDE稍显复杂。事实上,管理 Eclipse 的各种插件已经让开发者头疼不 已,有些插件的更新还很难保证。 JBuilder 和 WTK 从JBuilder 9版本开始,Borland将WTK 直接集成到了开发工具内。如果使用以 前版本的 JBuilder,那么需要首先安装 MoblieSet 插件。 小 结 其实,各种开发工具只是以自己的 方式对 M I D P 应用程序的开发进行了封 装, MIDP应用程序的开发流程都是一样。 事实已经证明,除了使用手机供应商自 己的套件外(如 Nokia Toolkit),WTK和 NetBeans Mobility的用户最多——这方面 SUN 征文 >>>