AndroidPi

归并排序(Merge sort)

定义 归并排序采用分治策略进行比较操作排序,将待排序的n个元素分解为个含n/2个元素的两部分,使用递归或其它方式迭代地两个子序列进行同样的排序操作,然后合并两个已排序的子序列。 分析 序列的划分 序列的划分较为简单直接,n为奇数时两部分长度相差1,可以规定将较长的一部分作为第二部分的长度。 序列的合并 从最基本的合并开始,如果划分到一个子序列仅有一个元素时,不能进一步划分,对该子序列的归并排序会直接返回,对应于n=1时的归并排序,是直接求解的不需要进行归并操作。当单元素子序列归并排序完成时,将两个子序列进行合并得到两个元素的子序列,对应于n=2时的归并排序就完成了,以此类推,不失一般性考虑如何合并任意大小的两个已排序子序列的问题。 对于序列的划分操作需要进行lgn次,每次都需要对n个元素进行合并操作,而合并本身也是对两个有序子序列的再排序,合并的开销必须尽可能地小,至少需要将所有子序列遍历一遍,其渐进复杂度下界是Ω(n)。如果采用原址排序的方式,由于两个子序列除了自身是有序的,两者之间没有任何联系,这会是一个一般性的排序问题。因此,为了利用已排序的子序列,将两者复制后依次进行比较并合并回原序列中。 实现 def merge_sort(A, start, end): if end - start <= 1: return mid = (end + start) / 2 merge_sort(A, start, mid) merge_sort(A, mid, end) merge(A, start, mid, end) def merge(A, start, mid, end): left = [] right = [] for i in xrange(start, mid): left.append(A[i]) for i in xrange(mid, end): right.append(A[i]) i = 0 j = 0 current = start left_size = len(left) while i < left_size and j < len(right): if left[i] <= right[j]: A[current] = left[i] i += 1 else: A[current] = right[j] j += 1 current += 1 for k in xrange(i, left_size): A[current] = left[k] current += 1 if __name__ == '__main__': A = [12, 12, 123, 234, 1, 2, 3, 4000, 12, 234, 1, 891] merge_sort(A, 0, len(A)) print A

November 26, 2017 · 1 min · 134 words · LEOY

Kotlin数据类型

参考: 基本类型 相等性 空指针安全性 类型检查与转换 Java中有8种基本类型byte,short,int,long,float,double,boolean,char,还提供了支持字符串的java.lang.String类,最后提供了上述的数组类型。Kotlin中的数据类型与Java基本一致,不过可以将基本数据类型也看做对象。 数字 类型 |位宽度 --------|--------- Double |64 Float |32 Long |64 Int |32 Short |16 Byte |8 注意,Kotlin中字符不是数字。 在Java平台中,数字的以JVM中的基本数据类型保存于物理存储,除非我们想要一个可以为空(nullable)的数字或者使用了泛型,那么这时数字会装箱(boxed)为对应的类型。 数字装箱后不保留同一性(identity),但保留相等性(equality),这与Java中是一样的,两个数字值相等的对象是不同的两个对象,但它们的值是相等的。 与Java中不同的是,同一性比较使用三个等号符号:===或者!==,相等性比较使用:==或者!=。 对于数字的隐式转换和自动拆装箱,对比Java中和Kotlin中有何区别: Java中,表达式中的数字类型会自动拆箱为对应的基础类型,然后向上转型为表达式中较大的基础类型。自动装箱只能发生在对应的基础类型上。 Integer a = 11; Short b = 12; Long c = 13L; int i = 1; short j = 2; long k = 3; k = a; k = a + b; k = i + j; k += i; a = a + b; a = i + j; c += i; c = 14; // error, right expression is 'int' c = i + j; // error, right expression is 'int' c = a + b; // error, right expression is 'int' Kotlin中,与类型系统是相关的,因为所有数字类型都认为是对象,可以认为没有拆箱的说法,并且也没有隐式的类型提升,运算符事实上都是重载的操作符。 var a: Int?...

November 1, 2017 · 4 min · 661 words · LEOY

Kotlin高阶函数与Lambdas

参考: Lambdas 高阶函数 一个高阶函数接收函数作为其参数,或者返回一个函数。举个栗子,如下所示,lock()函数接收一个lock对象和一个函数,获取锁,运行函数,然后释放锁: fun <T> lock(lock: Lock, body: () -> T): T { lock.lock() try { return body() } finally { lock.unlock() } } body有一个函数类型:() -> T,它是一个返回类型为T的值的方法。 如果我们想调用lock(),我们可以将另一个函数作为参数传递给它(参考:方法引用): fun toBeSynchronized() = sharedResource.operation() val result = lock(lock, ::toBeSynchronized) 此外,一个更加便捷的方式是传递一个lambda表达式: val result = lock(lock, { sharedResource.operation() }) Lambda表达式先简要介绍下,后面小节会有详细描述: 一个lambda表达式总是由花括弧包围 它的参数在记号->前声明,参数类型可以忽略 正文跟在->后 在Kotlin中如果一个函数的最后一个参数是一个函数,并且使用lambda表达式传递对应的参数,有一个简便的方式来表示,即将lambda表达式放在函数参数列表括弧外: lock (lock) { sharedResource.operation() } 另一个例子,如下map()函数所示: fun <T, R> List<T>.map(transform: (T) -> R): List<R> { val result = arrayListOf<R>() for (item in this) result....

October 30, 2017 · 3 min · 428 words · LEOY

Kotlin对象

参考: 对象声明 对象表达式和声明(Object Expressions and Declarations) 对象表达式(Object expressions) Object表达式可以创建匿名类: window.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { // ... } override fun mouseEntered(e: MouseEvent) { // ... } }) 与Java匿名类不同的是,Java仅仅只能使用已有类型进行实例化,Kotlin可以在实例化匿名类时对匿名类进行定义,也就是说匿名类不用使用已有类型,如下所示: 继承已有的类型: open class A(x: Int) { public open val y: Int = x } interface B {...} val ab: A = object : A(1), B { override val y = 15 } 或者不继承已有的类,默认继承Any: fun foo() { val adHoc = object { var x: Int = 0 var y: Int = 0 } print(adHoc....

October 30, 2017 · 2 min · 260 words · LEOY

Kotlin类的定义

数据类(Data Classes) 我们常常创建仅仅持有数据的类,类似Java中的POJO或JavaBean,其对象我们一般称为实体(entity),因此它对应我们常说的Entity类。在一般UI应用分层架构中,例如MVC,MVP,MVVM等,都含有一个模型(Model)层,实体类型就属于这一块,它是构建业务的基石。 为此Kotlin专门定义了data类型: data class User(val name: String, val age: Int) 编译器会根据主构造函数中声明的属性自动生成如下成员: equals()/hashCode()对 toString()方法,返回字符串形式为"User(name=John, age=42)" componentN() 方法,其中N对应于属性声明的顺序 copy()函数 为了保持生成代码的一致性和行为的有效性,data类必须满足以下要求: 主构造器需要至少一个参数 所有主构造器参数需要声明为val或var Data类型不能是abstruct、open、sealed或inner的 此外,对于成员继承,成员生成遵循以下规则: 如果一个data类正文中明确实现了equals(),hashCode(),toString()方法,或者超类中有final修饰的实现,那么这些方法便不会生成,直接使用已有的实现。 如果超类有open修饰的componentN()方法并且返回兼容的类型,那么对应的生成方法会重写超类的方法,否则会报错。 显式地实现componentN()和copy()是不允许的 在JVM中,如果生成类需要有一个无参构造器,所有属性的默认值必须明确指定。 data class User(val name: String = "", val age: Int = 0) 拷贝 copy()方法有什么用?有时我们需要拷贝一个对象,同时改变它的某些属性,并保持其它属性不变,使用copy()方法就可以了,其实现类似这样: fun copy(name: String = this.name, age: Int = this.age) = User(name, age) 对象的属性值作为copy的默认参数值,我们可以传递希望改变的值,而保留其它值不变: val jack = User(name = "Jack", age = 2) val newJack = jack.copy(name = "New Java") 结构声明(Destructuring Declarations) 生成的component方法可以使它们使用解构声明中:...

October 30, 2017 · 1 min · 125 words · LEOY