分类 Coding 下的文章

设计模式:Bridge

针对问题

一个函数通常会包括声明与实现两部分。简单的说,声明的是“做什么”,而实现的内容则是“怎么做”。
在使用继承的面向对象设计中,通过对同一基类的继承,可以让基类中的同一个函数声明在不同派生类中有多个不同的实现。但是,在“派生”一个新类后,这个类所构造实例对象的函数声明和实现在编译时将绑定在一起。也就是说,虽然对于同一个接口,我们可以更换不同的对象来更改它的实现,但是对于同一个对象,它的某个函数的实现方式在编译时就已经确定,运行时无法修改。
Bridge模式则是将声明与实现放在两个不同的对象中,对于同一个对象,它某个函数的实现方式不是唯一的。
而另一个关于继承的问题则是派生类的继承层次问题:因为底层实现代码被绑定在派生类中,如果某个接口下有一个树形的继承关系,那么实现代码将出现在每一个叶子派生类中。如果我们要更换底层实现,那么就要为每一个叶子派生类创建一个平级的替换实现类,这个工作量是庞大的。… Read the rest

设计模式:Adapter

针对问题

适配器(Adapter)的概念在生活中应用相当广泛,比如电器的电源适配器、可以换头的万能螺丝刀等等。将这个概念放在软件开发中:将一个接口转换成我们希望的接口,就是Adapter模式。

介绍

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

实现

类适配器

类适配器使用多重继承对一个接口与另一个接口进行匹配,如图:

对象适配器

对象适配器依赖于对象组合,如下图:

两种方式都实现了将SpecificRequest接口到Request接口的转换。

可插入的适配器

以上两种方式介绍了如何把一个已知类的接口“转换”(适配)成另一个已知类,也就是已知Target和Adaptee,创建Adapter。接下来的问题是:如何把未知类的接口适配到已知类。这里实际上是已知Adaptee,创建Target和Adapter的过程。… Read the rest

设计模式:Prototype

针对问题

一般在需要创建对象时,创建者都是知道需要创建对象的类型之后调用构造函数并用相关的初始化语句完成对象的初始化。假设有这么一个场景:领导拿了一摞演讲稿让你再准备一份,这个时候有两种思路:打开word,把演讲稿重新敲一遍,然后打印出来;或者直接去复印一份。
Prototype模式就类似于复印的思路。这里演讲稿可以作为一个类,稿子里的文字是演讲稿实例中的内容。Prototype模式更准确的说是“利用对象创建对象”的模式,而当作模版的对象就叫做prototype。

介绍

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

实现

基本实现

Prototype模式的UML图如下:

基本实现非常简单,只要让某个类型提供Clone方法,返回自身的拷贝就可以了,但是要注意:
1、为了保证通用性,Clone方法一般是没有参数的。通过复制生成的对象需要在初始化Clone方法外初始化。… Read the rest

设计模式:Builder

针对问题

已知用Factory模式可以方便的创建一类或一组对象。但如果要创建一个由几部分组合而成或需要分布创建的复杂对象,并且复杂对象中包含其他对象的具体类型不确定或创建步骤不确定时,Factory模式就难以适应这种需求了。
一个简单的例子是方便面:泡面一般是开盖-倒水-等3分钟-加料这个顺序下,根据实际泡的东西不同,最终结果可以是泡好的方便面,也可以是方便泡饭,还可以是泡馍。而加料这个步骤可以在倒水前,也可以在倒水后(当然也可以不加)。这就类似于Builder模式的工作原理。

介绍

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

实现

Builder模式分为两个部分:Builder和Director。
Builder:为创建对象各个部件提供相应接口,并提供返回对象的接口。
Director:封装使用Builder构造对象的逻辑。
Builder模式的结构如下图:… Read the rest

设计模式:Singleton

针对问题

系统运行时的某个类仅有一个实例的情况。

介绍

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

实现

单线程

一般Singleton的实现分为3部分。
1、隐藏构造函数
2、创建并保存实例
3、返回实例

例子如下:

设计模式:Factory

Simple Factory

针对问题

在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例。假设有以下创建语句:

如果对类Human的实例化很频繁,那么在程序中就会大量出现此类代码,于是自然可以想到方法把这类重复语句提取到一个函数中去。

介绍

声明一个创建对象的接口,并封装了对象的创建过程。Factory这里类似于一个真正意义上的工厂(生产对象)。

实现

设计模式总结

设计模式的定义及用途

每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的解决方案,无需再重复相同的工作。即模式是在特定环境中解决问题的一种方案。

简单地说,就是从前辈们在程序设计过程中总结、抽象出来的通用优秀经验。主要目的一方面是为了增加程序的灵活性、可重用性。  另一方面也有助于程序设计的标准化和提高系统开发进度。

设计模式分类

1)根据其目的(模式是用来做什么的)可分为创建型(Creational),结构型(Structural)和行为型(Behavioral)三种:
• 创建型模式主要用于创建对象。
• 结构型模式主要用于处理类或对象的组合。
• 行为型模式主要用于描述对类或对象怎样交互和怎样分配职责。
2)根据范围,即模式主要是用于处理类之间关系还是处理对象之间的关系,可分为类模式和对象模式两种:… Read the rest

关于i++与++i的测试

问题

上网找了找,关于i++和++i两个速度为什么有区别,大致是这么一个说法:

计算机内部实现过程有别,详细如下:
i=i+1的过程相当:
  temp=i+1; i=temp;
i++的过程相当:
  temp=i; i=temp+1; return temp;
++i的过程最简单:
i增1然后return i 的值,一步完成,没有给任何temp变量赋值

最早是在[http://bbs.chinaunix.net/thread-388165-1-1.html]的1楼发表。
为了验证这个问题我写了一下测试程序,分别以下用4个编译器做测试(我手里只有这几个):
javac 1.6.0_26
gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3
arm-none-linux-gnueabi-gcc (ctng-1.6.1) 4.4.3
mipsel-linux-gcc (GCC) 4.1.2

测试程序

Java:

排序算法

几个概念

(1)排序稳定:如果两个数相同,对他们进行的排序结果为他们的相对顺序不变。例如A={1,2,1,2,1}这里排序之后是A = {1,1,1,2,2} 稳定就是排序后第一个1就是排序前的第一个1,第二个1就是排序前第二个1,第三个1就是排序前的第三个1。同理2也是一样。不稳定就是他们的顺序与开始顺序不一致。
(2)原地排序:指不申请多余的空间进行的排序,就是在原来的排序数据中比较和交换的排序。例如快速排序,堆排序等都是原地排序,合并排序,计数排序等不是原地排序。
总体上说,排序算法有两种设计思路,一种是基于比较,另一种不是基于比较。《算法导论》一书给出了这样一个证明:“基于比较的算法的最优时间复杂度是O(N lg N)”。对于基于比较的算法,有三种设计思路,分别为:插入排序,交换排序和选择排序。非基于比较的排序算法时间复杂度为O(lg… Read the rest

后缀数组

概念 

后缀:从母串的某一位置开始到结尾,suffix(i) = Ai,Ai+1…An。

后缀数组:后缀数组SA是个一维数组,它保存1…n的某个排列SA[1],SA[2]…SA[n],并且保证suffix(SA[i])< suffix(sa[i+1]),也就是将s的n个后缀从小到大排好序后的开头位置保存到sa中。

名次数组:名次数组Rank[i]保存的是以i开头的后缀的排名,与SA互为逆。简单的说,后缀数组是“排在第几的是谁”,名次数组是“你排第几”。

height数组,height[i] = suffix(SA[i-1])和suffix(SA[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。

算法

Ukkonen 算法 O(n)

DC3算法 O(3n)

倍增算法 O(nlogn),实现简单。

应用

例1:最长公共前缀

    给定一个串,求任意两个后缀的最长公共前缀。

解:先根据rank确定这两个后缀的排名i和j(i<j),在height数组i+1和j之间寻找最小值。(可以用rmq优化)

 

例2:最长重复子串(不重叠)(poj1743)

解:二分长度,根据长度len分组,若某组里SA的最大值与最小值的差>=len,则说明存在长度为len的不重叠的重复子串。Read the rest

分类目录