Android面试题(六)-1常用算法/图片处理

24 篇文章 0 订阅

六、常用算法

1、快速排序

 

把整个序列看做一个数组,把第零个位置看做中轴,和最后一个比,如果比它小交换,比它大不做任何处理;交换了以后再和小的那端比,比它小不交换,比他大交换。这样循环往复,一趟排序完成,左边就是比中轴小的,右边就是比中轴大的,然后再用分治法,分别对这两个独立的数组进行排序。

 

public class QuickSort {

private static int[] a = {6,1,2,7,9,3,4,5,10,8};

public static void main(String[] args){

System.out.println("原数组值:");

for (int i : a) {

System.out.print(i+" ");

}

System.out.println();

quickSort(0, a.length-1);

System.out.println("排序后数组值:");

for (int i : a) {

System.out.print(i+" ");

}

System.out.println();

}

public static void quickSort(int left,int right){

int i,j,temp;

if(left>right){

return;

}

temp=a[left]; //temp中存的就是基准数

i=left;

j=right;

while(i!=j){

//顺序很重要,要先从右边开始找 ,直到找到一个小于基准的值

while(a[j]>=temp && i<j){

j--;

}

//再找右边的 ,直到找到一个大于基准的值

while(a[i]<=temp && i<j){

i++;

}

//交换两个数在数组中的位置

if(i<j) {

int t=a[i];

a[i]=a[j];

a[j]=t;

}

}

//最终将基准数归位

a[left]=a[i];

a[i]=temp;

if(left<i-1){

quickSort(left,i-1);//继续处理左边的,这里是一个递归的过程

}

if(right>j+1){

quickSort(i+1,right);//继续处理右边的 ,这里是一个递归的过程

}

}

}

2、选择排序

从数组一端选择一个数组中的一个元素,通过比较对比取出最小值(或者最大值)放在array的左边(右边 这里主要视遍历的开始为左还是右);逐个遍历;

/**选择排序

*遍历数组 然后每次遍历到一个元素之后 继续遍历该元素之后的所有元素 然后找 到最小的元素 和其换位置*/

public static int[] select(int[] array){

for (int i = 0; i < array.length; i++) {

int minPos = i;

for (int j = i + 1; j < array.length; j++) {

if (array[j] < array[minPos]){

minPos = j;

}

}

if (array[i] > array[minPos]){

int temp = array[i];

array[i] = array[minPos];

array[minPos] = temp;

}

}

return array;

}

3、插入排序

/***插入排序

*相当于 从0开始一直++ 然后一直排列索引跟之前的元素

* */

public static int[] insert(int[] array){

for (int i = 1; i < array.length; i++) {

int temp = array[i];

for (int j = i - 1; j >= 0 ; j--) {

if (array[j] > temp ){

array[j + 1] = array[j];

array[j] = temp;

}

 

}

 

}

return array;

}

4、冒泡排序

每次冒泡排序操作都会将相邻的两个元素进行比较,看是否满足大小关系要求,如果不满足,就交换这两个相邻元素的次序,一次冒泡至少让一个元素移动到它应该排列的位置,重复N次,就完成了冒泡排序。

public void bubbleSort(Integer[] arr) {

for(int i=0;i<arr.length-1;i++) {

for(int j=0;j<arr.length-i-1;j++) {

if(arr[j]>arr[j+1]) {

int temp=arr[j];

arr[j]=arr[j+1];

arr[j+1]=temp;

}

}

}

}

七、图片处理

1、Android缓存机制——LruCache

LRU是近期最少使用的算法,它的核心思想是当缓存满时,会优先淘汰那些近期最少使用的缓存对象。采用LRU算法的缓存有两种:LrhCache和DisLruCache,分别用于实现内存缓存和硬盘缓存,其核心思想都是LRU缓存算法。

import android.util.LruCache;

public class MyImageLoader {

private LruCache<String, Bitmap> mLruCache;

public MyImageLoader(){

//设置最大缓存空间为运行时内存的1/8

int maxMemory = (int) (Runtime.getRuntime().totalMemory()/1024);

int cacheSize = maxMemory / 8;

mLruCache = new LruCache<String, Bitmap>(cacheSize){

@Override

protected int sizeOf(String key, Bitmap value) {

return value.getRowBytes()*value.getHeight()/1024;

}

};

}

 

/**

* 添加图片到LruCache

* @param key

* @param bitmap

*/

public void addBitmap(String key,Bitmap bitmap){

if (getBitmap(key) == null){

mLruCache.put(key,bitmap);

}

}

 

/**

* 从缓存中获取图片Bitmap

* @param key

* @return

*/

public Bitmap getBitmap(String key){

return mLruCache.get(key);

}

 

/**

* 从缓存中删除指定的Bitmap

* @param key

*/

public void removeBitmapFromMemory(String key){

mLruCache.remove(key);

}

}

LruCache的核心思想很好理解,就是要维护一个缓存对象列表,其中对象列表的排列方式是按照访问顺序实现的,即一直没访问的对象,将放在队尾,即将被淘汰。而最近访问的对象将放在队头,最后被淘汰。

LruCache中维护了一个集合LinkedHashMap,该LinkedHashMap是以访问顺序排序的。当调用put()方法时,就会在结合中添加元素,并调用trimToSize()判断缓存是否已满,如果满了就用LinkedHashMap的迭代器删除队尾元素,即近期最少访问的元素。当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队头。

 

2、Android图片库对比

Android主流图片加载库

  • Picasso
  • Glide
  • Fresco

介绍& 对比

1.Picasso

Picasso中文翻译为’毕加索’,由Square公司开源的一个适用于Android的强大图像下载和缓存库.

功能介绍

  • 图片的异步加载(最基础功能)
  • 使用最少的内存完成复杂的图片转换,转换图片以适合所显示的ImageView,来减少内存消耗
  • 支持加载过程中和加载错误时显示对应图片
  • 在Adapter中的回收不在视野的ImageView和取消已经回收的ImageView下载进程
  • 支持加载多种数据源 网络、本地、资源、Assets 等
  • 自动添加磁盘和内存二级缓存功能
  • 支持优先级处理
  • 支持飞行模式、并发线程数根据网络类型而变
  • Picasso 没有实现本地缓存功能,交给了 Square 的另外一个网络库 okhttp 去实现,这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。
  •  

与其他开源库对比

优点如下:

  • 使用简单,代码简洁
  • 与Square 公司的其他开源库如 Retrofit 或者 OkHttp搭配使用兼容性会更好些,占用体积也会少些

缺点如下:

  • 功能较为简单-图片加载;
  • 性能(加载速度等等)较(Glide、Fresco)较差
  • 自身无实现“本地缓存”

 

2.Glide

Glide是由Google开源的一个图片加载库,是一款快速高效的Android开源媒体管理和图像加载框架,它将媒体解码,内存和磁盘缓存以及资源池包装成简单易用的界面.

功能介绍

  • 图片的异步加载(基础功能)
  • 支持设置加载尺寸、设置加载中以及加载失败图片、设置加载动画、设置图文混排
  • 多样式的媒体加载(设置缩略图支持:先加载缩略图 然后在加载全图)
  • 支持设置磁盘缓存策略、设置跳过内存缓存、清理缓存
  • 生命周期集成(然而还是有bug)

与其他开源库对比

优点如下:

  • 支持多样化媒体加载 Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图,甚至是 Video
  • 生命周期集成 通过设置绑定生命周期,我们可以更加高效的使用Glide提供的方式进行绑定,这样可以更好的让加载图片的请求的生命周期动态管理起来(使用还是有bug)
  • 高效的缓存策略 1.支持Memory和Disk图片缓存 2.Picasso 只会缓存原始尺寸的图片,而 Glide 缓存的是多种规格,即 Glide 会根据你 ImageView 的大小来缓存相应大小的图片尺寸 3.内存开销小,Glide 默认的 Bitmap 格式是 RGB_565 格式,而 Picasso 默认的是 ARGB_8888 格式,占用内存要小一半

缺点如下:

  • 使用方法复杂,实现方法较多
  • 使用较Fresco简单,但性能(加载速度 & 缓存)却比不上Fresco

3.Fresco

Fresco是由Facebook开源的用于管理图像及其使用内存的Android库

功能介绍

具体功能请前往官方文档查看

优点如下

  • 大大减少了OOM的发生,Facebook在底层使用了C++技术解决图片缓存问题
  • 使用简单,几乎全部功能都能在XML文件中直接制定

缺点如下:

  • 用法变得更加复杂了
  • 依赖包更加大了(2-3M)
  • 底层设计C++等技术,源码阅读更加困难

 

3、图片加载库-Glide源码分析

glide:3.7.0 使用

引入

compile 'com.github.bumptech.glide:glide:3.7.0'

混淆

-keep public class * implements com.bumptech.glide.module.GlideModule -keep public class * extends com.bumptech.glide.module.AppGlideModule -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { **[] $VALUES; public *; } # for DexGuard only -keepresourcexmlelements manifest/application/meta-data@value=GlideModule

使用

使用的方式十分简单,和Picasso差不多

Glide.with(this).load(imgUrl) .placeholder(R.drawable.ic_launcher_background) .into(mIv);

同样也可以为他设置其他,例如 listener 、 centerCrop 、transform 、 sizeMultiplier

.listener(new RequestListener<String, GlideDrawable>() { @Override public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) { return false; } }) .centerCrop() ....

之类的,这些使用的方法和Picasso十分类似。

使用和源码分析:

https://blog.csdn.net/qq_37237245/article/details/72956121

https://www.jianshu.com/p/8771a7142eea

内存缓存

Glide内存缓存的实现自然也是使用的LruCache算法。不过除了LruCache算法之外,Glide还结合了一种弱引用的机制,共同完成了内存缓存功能。

Glide的图片加载过程中会调用两个方法来获取内存缓存,loadFromCache()和loadFromActiveResources()。这两个方法中一个使用的就是LruCache算法,另一个使用的就是弱引用。

 

当acquired变量大于0的时候,说明图片正在使用中,也就应该放到activeResources弱引用缓存当中。而经过release()之后, 如果acquired变量等于0了,说明图片已经不再被使用了,那么此时会调用listener的onResourceReleased()方法来释放资源

 

当图片不再使用时,首先会将缓存图片从activeResources中移除,然后再将它put到LruResourceCache当中。这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能。

 

硬盘缓存

Glide是使用的自己编写的DiskLruCache工具类,但是基本的实现原理都是差不多的。

 

一种是调用decodeFromCache()方法从硬盘缓存当中读取图片,一种是调用decodeFromSource()来读取原始图片。默认情况下Glide会优先从缓存当中读取,只有缓存中不存在要读取的图片时,才会去读取原始图片。

 

调用transform()方法来对图片进行转换,然后在writeTransformedToCache()方法中将转换过后的图片写入到硬盘缓存中,调用的同样是DiskLruCache实例的put()方法,不过这里用的缓存Key是resultKey(也就是调整图片大小后进行缓存)。

 

4、自己去实现图片库,怎么做

应该具备以下功能:

  • 图片的同步加载
  • 图片的异步加载
  • 图片压缩
  • 内存缓存
  • 磁盘缓存
  • 网络拉取
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值