上一节的冒泡排序可以说是我们学习第一个真正的排序算法,并且解决了桶排序浪费空间的问题,但在算法的执行效率上却牺牲了很多,它的时间复杂度达到了 O(N2)。假如我们的计算机每秒钟可以运行 10 亿次,那么对 1 亿个数进行排序,桶排序则只需要 0.1 秒,而冒泡排序则需要 1 千万秒,达到 115 天之久,是不是很吓人。那有没有既不浪费空间又可以快一点的排序算法呢?
简化版的桶排序不仅仅有上一节所遗留的问题,更要命的是:它非常浪费空间!例如需要排序数的范围是 0~2100000000 之间,那你则需要申请 2100000001 个变量,也就是说要写成 int a[2100000001]。因为我们需要用 2100000001 个“桶”来存储 0~2100000000 之间每一个数出现的次数。
在我们生活的这个世界中到处都是被排序过的。站队的时候会按照身高排序,考试的名次需要按照分数排序,网上购物的时候会按照价格排序,电子邮箱中的邮件按照时间排序……总之很多东西都需要排序,可以说排序是无处不在。现在我们举个具体的例子来介绍一下排序算法。首先出场的我们的主人公小哼,上面这个可爱的娃就是啦。期末考试完了老师要将同学们的分数按照从高到低排序。
在各种算法流行的今天,小编为大家汇总了坐在马桶上看算法系列文章,文章图文并茂,风趣易懂,每天一算法让你轻松走进算法的世界,欢迎大家来学习。适用人群本书将繁琐难懂的算法问题,用风趣易懂的方式写出,适合初学者学习学习前提在你开始做本文提供的各种类型例子练习之前,你需要对 C++ 语言有一定的了解致谢:http://blog.51cto.
入门的最好办法就是学习 Android 自带的例子, 这里就通过学习 Android 的 NDK 自带的 demo 程序:hello-jni来达到这个目的。开发环境的搭建android 的 NDK 开发需要在 linux 下进行: 因为需要把 C/C++ 编写的代码生成能在 arm 上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在 linux 系统下才能完成。
NDK 开发环境的搭建下载安装 Android NDK 地址:http://blog.sina.com.cn/s/blog_718f290a01012ch0.html下载安装 cygwin由于 NDK 编译代码时必须要用到 make 和 gcc,所以你必须先搭建一个 linux 环境, cygwin 是一个在windows 平台上运行的 unix 模拟环境,它对于学习 unix/linux 操作环境,或者从 unix 到 Windows 的应用程序移植,非常有用。
NDK 产生的背景Android 平台从诞生起,就已经支持 C、C++ 开发。众所周知,Android 的 SDK 基于 Java 实现,这意味着基于Android SDK 进行开发的第三方应用都必须使用 Java 语言。但这并不等同于“第三方应用只能使用 Java”。
这篇文章比较偏理论,详细介绍了在编写本地代码时三种引用的使用场景和注意事项。可能看起来有点枯燥,但引用是在 JNI 中最容易出错的一个点,如果使用不当,容易使程序造成内存溢出,程序崩溃等现象。《Android JNI局部引用表溢出》这篇文章是一个 JNI 引用使用不当造成引用表溢出,最终导致程序崩溃的例子。建议看完这篇文章之后,再去看。
在前面几章我们学习到了,在 Java 中声明一个 native 方法,然后生成本地接口的函数原型声明,再用 C/C++ 实现这些函数,并生成对应平台的动态共享库放到 Java 程序的类路径下,最后在 Java 程序中调用声明的 native 方法就间接的调用到了 C/C++ 编写的函数了,在 C/C++ 中写的程序可以避开 JVM 的内存开销过大的限制、处理高性能的计算、调用系统服务等功能。
在前面我们学习到了在 Native 层如何调用 Java 静态方法和实例方法,其中调用实例方法的示例代码中也提到了调用构造函数来实始化一个对象,但没有详细介绍,一带而过了。还没有阅读过的同学请移步《JNI——C/C++ 访问 Java 实例方法和静态方法》阅读。这章详细来介绍下初始一个对象的两种方式,以及如何调用子类对象重写的父类实例方法。
实例变量和静态变量在上一章中我们学习到了如何在本地代码中访问任意 Java 类中的静态方法和实例方法,本章我们也通过一个示例来学习 Java 中的实例变量和静态变量,在本地代码中如何来访问和修改。静态变量也称为类变量(属性),在所有实例对象中共享同一份数据,可以直接通过【类名.变量名】来访问。
通过前面 5 章的学习,我们知道了如何通过 JNI 函数来访问 JVM 中的基本数据类型、字符串和数组这些数据类型。下一步我们来学习本地代码如何与 JVM 中任意对象的属性和方法进行交互。比如本地代码调用 Java 层某个对象的方法或属性,也就是通常我们所说的来自 C/C++层本地函数的 callback(回调)。
JNI 中的数组分为基本类型数组和对象数组,它们的处理方式是不一样的,基本类型数组中的所有元素都是 JNI 的基本数据类型,可以直接访问。而对象数组中的所有元素是一个类的实例或其它数组的引用,和字符串操作一样,不能直接访问 Java 传递给 JNI 层的数组,必须选择合适的 JNI 函数来访问和设置 Java 层的数组对象。
处理字符串从第三章中可以看出 JNI 中的基本类型和 Java 中的基本类型都是一一对应的,接下来先看一下 JNI 的基本类型定义:typedef unsigned char jboolean; typedef unsigned short jchar; typedef short jshort; typedef float jfloat; typedef double jdouble; typedef int jint;
当我们在调用一个 Java native 方法的时候,方法中的参数是如何传递给 C/C++ 本地函数中的呢?Java 方法中的参数与 C/C++ 函数中的参数,它们之间是怎么转换的呢?我猜你应该也有相关的疑虑吧,咱们先来看一个例子,还是以 HelloWorld 为例:HelloWorld.java:package com.study.jnilearn;
通过第一篇文章,大家明白了调用 native 方法之前,首先要调用 System.loadLibrary 接口加载一个实现了native 方法的动态库才能正常访问,否则就会抛出 java.lang.UnsatisfiedLinkError 异常,找不到 XX 方法的提示。现在我们想想,在 Java 中调用某个 native 方法时,JVM 是通过什么方式,能正确的找到动态库中 C/C++ 实现的那个 native 函数呢?
开发流程JNI 全称是 Java Native Interface(Java 本地接口)单词首字母的缩写,本地接口就是指用 C 和 C++ 开发的接口。由于 JNI 是 JVM 规范中的一部份,因此可以将我们写的 JNI 程序在任何实现了 JNI 规范的 Java 虚拟机中运行。同时,这个特性使我们可以复用以前用 C/C++ 写的大量代码。
相信很多做过 Java 或 Android 开发的朋友经常会接触到 JNI 方面的技术,由其做过 Android 的朋友,为了应用的安全性,会将一些复杂的逻辑和算法通过本地代码(C或C++)来实现,然后打包成.so动态库文件,并提供 Java 接口供应用层调用,这么做的目的主要就是为了提供应用的安全性,防止被反编译后被不法分子分析应用的逻辑。当然打包成.
JNI 是 Java 语言提供的 Java 和 C/C++ 相互沟通的机制,Java 可以通过 JNI 调用本地的 C/C++ 代码,本地的 C/C++ 的代码也可以调用 Java 代码。JNI 是本地编程接口,Java 和 C/C++ 互相通过的接口。Java 通过 C/C++ 使用本地的代码的一个关键性原因在于 C/C++ 代码的高效性。 代码和其他语言写的代码进行交互。NDK 是一系列工具的集合。
有人说 Java 是互联网编程领域的语言之王,不管这种说法是否言过其辞,但 Java 在互联网中的应用范围之广确是不争的事实。程序员在面试 Java 开发岗位时经常会遇上各类笔试面试题,针对这些笔试面试题做准备是必要的环节,在此过程中也能加深对 Java 知识的理解。本面试宝典的试题均来自于网上。
关注时代Java