热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

App竞品技术分析(3)减小安装包的体积(转)

http:blog.csdn.netJspAndAsparticledetails493394031从几件小事说起春节在家帮姐姐的iPhone手机安装市面上形形色色的App,忘记她

http://blog.csdn.net/JspAndAsp/article/details/49339403

1 从几件小事说起

  春节在家帮姐姐的iPhone手机安装市面上形形色色的App,忘记她是使用4G流量包月了,于是在下载了10个App后,不但耗尽了流量,还按照0.3元/兆的价格扣了七八十元流量费用。后来我检查了这几个App的体积,发现每个App体积都是40-50M的样子,这让我很吃惊,因为我记得两年前这些App也就在10-20M的样子。

  另一件记忆犹新的事情,是去公园景点游玩,当时公园门口有个活动“扫二维码下载App下单立减10元”,但是我发现下载这个40M的App要花费12元的流量,这样其实是要额外多花2元钱,所以“扫码立减”这件事情对于我这种小市民而言是很不划算的。

  由此而得到一个结论,App安装包的体积一定要小,至少要比竞争对手的App体积小。

  对于Android而言,国内的各大市场商店已经发现这个问题了,所以对于用户升级App,会为每个App提供增量下载的功能,所以App版本升级不再是几十M的流量,而只是下载1-2M的增量包就能升级到最新版本,这样就极大节省了流量。[1]

  对于iOS而言,AppStore从iOS6开始提供增量更新功能。对于iOS 6.x和iOS7.0,只要有文件改动过,这个文件就会进入到增量更新包中,比如说1个10M的文件,只改动了1KB的内容,这个10M文件就会进入到增量更新包中,包还是很大。到了iOS7.1及更高版本,这个机制进行了改良,它会把这1KB的改动内容放到增量更新包中,从而极大的减少了增量更新包的大小,但是安装的时候会变慢,因为要把这1KB的改动内容合并到10M文件中,这是个很繁琐很费时的工作。[2]

  尽管如此,以上种种措施只能解决升级用户的流量困扰,对新用户并无帮助。我们必须减小安装包的大小,才能吸引更多的新用户。

2 安装包为什么那么大

  是什么让App安装包的体积变得如此之大?

  我们在前面的章节看到了iOS和Android安装包的内部结构,对于可执行文件,我们无能为力;对于XML文件,这些文件在App打包压缩后会极大减小体积,所以也不用管它们;那么就只能在图片和音频文件上做文章了。

  各位读者看到这里,都请停下手中的工作,检查一下自家App包中图片和音频文件的大小。图片但凡是大于1M的,都是需要瘦身的。对于500KB-1M这个区间内的,也有瘦身的可能。我研究过很多知名的App,其中有很多图片都在2-3M的样子,其实真没有必要,之所以这么大,是因为UI设计人员提供的设计稿就是这么大,开发人员拿过来也不看文件体积大小直接就往项目里放,久而久之,App包的体积就大了。

  在众多App之中,我印象最深的是一款旅游类软件,它的所有图片都不超过100KB,甚至说50KB以上的都屈指可数。这是把极致做到家的表现。

  接下来说音频文件,对于应用类App而言,我见到的大都是App推送时发出的声音,这个声音很简单,不应该超过10KB。但我在很多App中看到的音频,都在100KB左右。这是我们优化的一个方向。网上有很多这样的软件,可以对音频进行大幅压缩。

3 png和jpg的区别和使用场景

  设计师曾经问过我,App为什么不使用jpg图片,因为同样的尺寸,png格式的图片要比jpg图片大很多。

  众所周知,png有透明通道,而jpg没有,此外png是无损压缩的而jpg是有损压缩的,所以png中存储的信息会很多,体积自然就大了。

  但是手机却偏偏对png情有独钟,会对其进行硬件加速,所以我们会发现,同样一张背景图,png虽然体积比jpg大但是加载速度却要快一些。

  终上所述,对于App包中的图片,我们都使用png格式的,而对于要从网上加载的图片,考虑到流量以及下载速度,则使用jpg格式的,因为它有较高的压缩率,体积很小。

  但是对于背景图、引导页,这种大尺寸的图片,我们还是倾向于使用jpg格式,虽然加载慢一些,但是体积小,减少了包的体积。我看过的App基本都是这么做的。

  对于Splash广告图,就是那个每次开启App一闪而过的广告,由于我们隔三岔五就要从线上下载新的广告图并展示在Spalsh页面上,所以这里使用jpg格式的图片。

  对于iOS,苹果规定启动页(Launch image)必须是png图片,否则审核时就会被拒。

  Google后来发布了一种新的图片格式,WebP,它的压缩率比jpg更好,已经慢慢普及。Android自然是支持的,iOS想要使用这种格式的图片,需要在程序中引入WebP解码器。

4 Splash、引导图和背景图

  通过对50多款App中的图片逐个分析,我发现有3种比较典型的场景,大多数公司的解决方案是雷同的:

  1. Splash默认广告是体积最大的,而且对应不同机型,要做多套,根据我的经验,每张图控制在300-500k左右就可以了。分辨率再高,对于手机而言,看不出效果。

  2. 引导图,设计师每次都会给几张高分辨率的图片,然后程序员不加思索直接放到App中,体积自然就变大了。其实,仔细观察,你会发现,为了保持风格统一,这些图片的背景都是一样的。所以我们完全可以这样做,比如说背景上有一只小兔子:

  • 把背景与小兔子拆分成2张图片。如果另一个引导图的背景上有一只小鸭子,那么就只需要这张小鸭子的图片了,背景图可以复用。
  • 根据分辨率,动态放置小兔子的位置,动态拉伸背景图,使之铺满整个屏幕。

  3. 对于背景图,为了达到一种视觉效果,这张图片经常被添加虚化等效果,既然如此,没有必要做得太清晰,应该控制在50k左右,看到很多App中类似的背景图都在1M左右,实在没有必要。背景图一般使用jpg文件。

5 iOS的1倍图、2倍图和3倍图

  iOS不使用像素作为单位,而是使用点这个单位,对于iPhone4及之后,1点等于2个像素;而对于iPhone3GS及之前,1点等于1个像素。这样就保证了之前在iPhone3GS上运行的App,不用修改也能在iPhone4上运行。[3]

  但是原先适用于iPhone3GS的图片,比如说a.png的尺寸是30 x 40像素,在iPhone4中看起来就模糊了。于是我们必须为a.png再准备一张60 x 80像素的图片,命名为a@2x.png,也放到App项目中,这样App在运行时会根据屏幕是否为iPhone3GS来选择相应的图片。iPhone3GS会选择a.png,iPhone4会选择a@2x.png。对于iPhone4而言,如果没有这张2倍图,则选择a.png,所以就模糊了。

  iPhone4S、iPhone5、iPhone5c、iPhone5s、iPhone6,它们都使用a@2x.png这张2倍图。

  直到iPhone6 Plus,才需要提供a@3x.png的图片。如果没有这张3倍图呢,它会选择1倍图或2倍图,我尝试过只有2倍图的情况,在iPhone6 Plus上确实是模糊的效果。

  那么问题就来了,我们需要为每张图都提供1倍图、2倍图和3倍图这3张图片吗?

  我看到一款国际版的App是这么处理图片的。它在提供了多国语言文字的同时,还为每张图片生成了1倍图、2倍图和3倍图。这就导致了这款App的体积非常大。看上去有点“宁可错杀一千,不可放走一个”的感觉,但只要反过来想,图片一张也不缺,永远不会模糊。

  我查看过很多App的图片,发现1倍图铺天盖地,但并不是每张1倍图都有相应的2倍图和3倍图,或者是只有相应的2倍图而没有3倍图,当然,也有只存在2倍图和3倍图而找不到1倍图的情况。图片管理五花八门,乱七八糟。

  但是在中国,可不是这样哦。我看过友盟给出的数据报告,中国iPhone3GS用户不足0.1%。于是,我有一个大胆的设想,就是把iOS App的包中所有的1倍图都干掉,为每张图生成2倍图和3倍图。

  很多公司都有根据1倍图批量生成2倍图和3倍图的工具,我也曾用C#写过一个。但是我发现有问题,并不是每张图片转换后都清晰,矢量图可以拉伸,但是拉伸位图就会失真。当我反过来根据3倍图批量生成1倍图和2倍图时,却发现位图可以压缩,而矢量图压缩后会失真。于是一种好的解决方案是,先把所有图片按照位图和矢量图进行分类,属于矢量图的,要提供1倍图,然后批量转换为2倍图和3倍图;而属于位图的,则是提供3倍图,然后批量转换为1倍图和2倍图。

  本文给出的解决方案,并不能有效减小iOS包的体积,说不定反而会增大包的大小,但是却能系统的对图片进行管理,从而确保每张图片都是清晰的。

6 在iOS中进行图片拉伸和旋转

  在Android技术领域,流行.9图这个概念,从而极大的节省了图片的体积。iOS其实也可以这么干,使用iOS的图片拉伸的语法,可以把一张.9图铺满一个区域,比如说按钮,如下所示:

(UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets

  其中capInsets这个参数是一个UIEdgeInsets类型的结构体,被capInsets覆盖到的区域将会保持不变,而未覆盖到的部分将会被用来平铺。

  以上这个方法只适用于iOS0及以上版本,0以下版本有另外的解决方案,但是目前国内的App都只支持0以上版本了,所以这里我就不提及了。

  对于箭头,更没必要准备上下左右4张图片,准备一张图片就够了,使用的时候在方向上进行旋转即可。

7 使用XML配置动画

  动画主要体现在引导图中以及加载进度条上。

  对于做应用类App的开发人员,他们做动画不是很在行,所以他们会要求设计师提供gif格式的动画,或者二十多张图片进行轮播,以达到gif动画的效果,殊不知,在编程上简单了,但是App的体积却相应变大了。

  比较简单的解决方案是,减少动画中的关键帧,来降低动画的大小。

  稍微正规一点,还是要使用原生的Android或iOS原生代码来实现。任何复杂的动画,都是由四种简单的动画组成的,分别是:移动、旋转、缩放、渐变。在Android中,是使用XML来配置的,上述这四种简单动画都有对应的XML语法,可以很快拼凑出一个复杂的动画;而对于iOS,只好使用编码方式了。

  我们为什么不仿照Android的XML动画实现技术,为iOS也量身定制一套XML的动画标签呢?从而不用写任何objective-C代码,配置几行XML就展现一个动画。

  我见过一家App就是使用这个思想在plist中配置属性来做iOS动画的,如图9-4所示,就是一个平移的动画:

  技术分享

  图9-4 配置文件中的平移动画

  基于这个配置,还需要有一个动画引擎,来解析这个配置文件,将其翻译成objective-C原生语言。在设计模式中,我们称之为解释器模式。

  不单如此,我还需要有个测试页面,通过在这个页面中修改动画的属性,然后点击按钮能立刻看到改动后的效果,而不需要重新运行App程序。点个按钮就能执行输入框中的XML脚本。

  使用上述的若干方法,我们可以把1个500KB左右的gif文件,减小到50KB的几张图片,并且极大地节省了而开发成本。

8 iOS使用storyboard还是xib?

  抱歉,我始终不喜欢storyboard,但是存在即合理。我曾经认为storyboard比xib大,是导致iOS安装包体积变大的一个原因,于是我做了一件探索性的工作,就是把storyboard中的页面拆分为若干个xib文件,然后重新打包,但是结果却是前后大小一致。

  结论是,是否使用storyboard,对ipa包大小没有影响。

9 字体文件的学问

  我在某个ipa包中发现了ttf格式的字体文件。起初还以为是他们的App使用了某种特定字体,但打开这个ttf文件后才发现,这里面存放的居然是图片,如图9-5所示:

  技术分享

  图9-5 字体文件中的icon图片

  每个icon对应一个十六进制的数字,比如说第一个是\Ue600,这个值是唯一的。

  观察这个字体文件,我们看到所有的icon具有以下共性:

  • 这些icon都是单色的,可以在App中的页面里设置这些icon为其他颜色,但也必须是单色。
  • 这些icon可大可小,因为它们是一种“字体”,字体是矢量图,所以拉伸不会失真。
  • 这个ttf文件体积很小,比做成单独的png图片要小。

  有人立刻就会联想到iOS的1倍图、2倍图和3倍图,每次都要准备3张图片,分别适用于不同的手机型号。如果做成一个字体,就可以减少体积,再也不用设计@2x和@3x两套图了——这种方案仅限于单色图片。

  我们一般到下述网站来把单色icon转换成字体文件:https://icomoon.io。或者使用FontLab这样的工具自己来制作。

  接下来我们来看如何在App中推广这门技术。

  1)Android

  首先把这个字体文件放到assets目录下,如图9-6所示:

  技术分享

  图9-6 assets目录下的字体文件

  接下来,我们将icon和十六进制编码的映射关系保存在drawable资源文件中:




  这样就可以使用R.id.font_icon_1_normal这样的语法来取出这个图片了。

TextView textView1 = (TextView) findViewById(R.id.textView1);
Typeface fOnt= Typeface.createFromAsset(getAssets(), "icomoon.ttf");
textView1.setTypeface(font);
textView1.setTextSize(12);
textView1.setText(getResources().getString(R.string.font_icon_1_normal));

  也可以将其设计为一个Drawable对象,然后设置给ImageView这样的控件。

  2)对于iOS,实现思路差不多。

  首先我们要把icmoon.ttf文件添加到项目中,如图9-7所示:

  技术分享

  图9-7 UseIconInTTF中的icomoon.ttf文件

  在Supporting Files目录下的UserIconInTTF-Info.plist文件中,增加一个配置,类型指定为Fonts provided by application,在其中添加对icomoon.ttf字体文件的声明,如图9-8所示:

  技术分享

  图9-8 在UseIconInTTF-Info.plist配置icomoon.ttf

  与Android类似,为了不直接使用\ue605这样的十六机制编码数字,我们将icon和十六进制编码的映射关系定义为一个宏TTFConstants:  

#define font_icon_1_normal "\ue605"
#define font_icon_1_pressed "\ue606"

  接下来只要两行代码就能显示这个字体文件中的图片:

[self.label1 setFont:[UIFont fontWithName:@"icomoon" size:12]];
[self.label1 setText:
[NSString stringWithUTF8String: font_icon_1_normal]];
10 表情图片打包下载

  对于表情图片。很多App中集成了聊天功能,有了聊天,自然就要提供各种表情图片,有静态图png,也有动画gif,虽然每个都不大,但是数量多啊,都打到包里面一起发布,会直接导致包变大。

  考虑到实际的场景,用户不会一打开App就使用聊天功能,所以我们可以把这些表情图片打包成一个Zip包,在启动App的时候,在一个新的线程中异步下载这个Zip包然后解压到本地。这样以后聊天的时候就可以使用本地的图片了。对此,我们要做好版本增量升级功能,以确保有新表情图片的时候也能下载到本地后使用。

11 清除未使用图片

  对于Android而言,Eclipse可以自动检查出哪些图片没有用到。

  对于iOS而言,则需要写个小程序,逐一检查哪些图片没有使用到,注意,对于a@2x.png和a@3x.png的处理,要先将@2x和@3x过滤掉。

  无论是Android还是iOS,即使发现到冗余图片,也不能直接删除,因为我们的程序经常会在代码中动态决定要显示哪些图片,我们只能检查这些图片在版本库的修改历史,来决定这些图片是否真的不需要了。

12 Proguard不只是用来混淆的

  一提起Android中的Proguard,我们首先想到的是代码混淆,那是因为我们要经常去修改proguard.cfg文件,去keep那些不需要被混淆的类和方法。

  其实,Proguard还能瘦身apk,在打包时它会帮忙检查那些不使用的类和方法,将其移除。最有效果的就是那些第三方SDK了,比如说aSmack这个用于xmpp的SDK有几万个方法,但其实我们只使用其中很小的一部分。Proguard会帮助我们把不使用的部分移除,从而极大的减小了apk的体积。

13 在iOS中使用pdf格式的图片

  在研究各家App的过程中,我发现某款App的ipa文件中有几张pdf格式的图片。

  在研究中还发现,有几款App的ipa包中的每张图片都做成imageset的形式,每个imageset目录中都同时存在这张图片的1倍图、2倍图和3倍图,如图9-9所示:

  技术分享

  图9-9 cancelSelectedListBtn.imageset目录下的3张图片

  上述这两件看似无关的事情,咋一看毫无关联,其实是使用了iOS的一个新技术。让我们从这些蛛丝马迹中探赜索隐。

  就是这几张pdf图片,我研究了半天,请设计师同学做成同样的png图片,体积相差不大,所以和png相比毫无优势。由于这个App的ipa包中有几百张图片,其中只有这3张图片是pdf格式的,所以我怀疑,这只是他们的新技术尝试。

  再观察imageset目录下的那3张图片,我发现每张图片都是这样的。这不由使我意识到,一定是用了什么工具,一次性生成的这些图片。

  搜索关键字ios+pdf,直到找到《Using Vector Images in Xcode 6》这篇文章[4],才发现这是iOS8才出现的一种新技术,只能在XCode6上使用。

  在这里简单介绍一下这门技术,先绘制一张pdf矢量图,然后XCode6在编译的时候,会生成3张pdf格式的图片,分别是1倍图、2倍图、3倍图。这样就避免了图片不全导致的模糊,也避免了每次都要设计师准备3套图的麻烦。

  但是,我们为什么要在用户的iPhone上装一些永远用不到的图片呢?苹果煞费苦心的搞出来这样一门技术,仍然没有解决App体积日益膨胀的现实,而且这门技术只会让App的体积变得更庞大——而这才是用户的痛点所在。如果是我来设计下一版iOS,我会让App中只包括pdf矢量图,只有在用户下载完App开始安装的时候,才会根据用户的机型,把pdf转换为相应的图片,比如说iPhone 6+上App生成的图片就是3倍图。

  苹果公司在iOS9中推出了App瘦身功能,据说能大幅减少要下载的App包的体积。具体效果如何,我们拭目以待。

14 iOS的包永远比Android包体积大吗?

  我比较了100多款App后发现,同一款App的iOS和Android版本,iOS的ipa包的一定比Android的apk包在体积上大很多。

  但总是有特立独行的App,比如说某款著名视频播放软件,Android版本23.2M,而iOS版本才20.5M。我起初以为这个App的Android版本做的有问题,于是仔细研究了这个Android包里的内容,我就发现这家公司Android技术做的很精致,之所以比iOS版本体积大,是因为Android版本为几十种分辨率都适配了不同的图片和布局,以确保用户体验在任何分辨率下都是一致的。

  如图9-10所示,居然有12种layout布局:

  技术分享

  图9-10 Android项目中的Layout文件夹

  drawable文件夹就更多了,高达28个,限于篇幅,这里就不贴图了。

  以上只是特例,而大多数App并没有做的那么细致,比如说:

  1)首先是不支持那么多分辨率。这是由当前App的开发现状导致的。一方面是产品经理和设计师在人力的不足,另一方面则因为设计师偏爱iPhone,一般只会给出iPhone版本的设计稿,然后让Android开发人员根据iPhone的设计稿去适配。于是Android开发人员只好去做UI自适应,使用.9图拉伸技术,实在搞不定了,才去找设计师重新给画一张。所以我们会看到iPhone的App大都很精致,相应的Android版本都很粗糙,这是因为Android App的UI很多都是开发人员凭着自己的审美观去二次加工的。

  2)其次,你会发现,不同drawable目录下放置着不同内容的图片。用开发人员的画讲,好找。比如说drawable目录下放各种Selector文件,drawable–hdpi目录下放美食类图片,drawable-large目录下放门票图片。所以说,目录虽多,但其实只有一套图。殊不知,这样反而降低了App运行的速度,因为它在相应分辨率的drawable目录下找不到某张图片时,就会逐个遍历每个drawable目录下的图片,直至找到该图片的位置。

15 从代码层面减少iOS包的体积

  对于iOS而言,在ipa包中会有一个.a格式的二进制文件,这是代码编译后生成的文件,往往占据了整个ipa包的50%到80%的体积。苹果曾要求所有的App都支持64位,于是在此基础上,ipa包的体积又扩大了将近一倍,主要是那个.a文件编译后变大了。

  我们要想办法减少这个.a文件的大小,其实就是要减少项目中的冗余代码。经过不断地摸索和尝试,我发现这些冗余代码分为3部分:

  1)已经不使用的类。为此,我们需要写一个Python脚本,逐个检查哪些类不再使用了。检查的过程中我发现,某个类即使不使用了,但是在其他类中仍然保持对它的引用,所以我们要排除掉这种特殊情况,不让它对我们的检查工作造成影响。

  还存在这么一种情况,在A类中使用了B。A类不再使用了,第一遍执行Python脚本找出来A类,将其删除了。这时B类就孤零零的放在那里,也不再使用了,所以我们有必要再次执行Python脚本,将B找出来。以此类推,不停地执行这个Python脚本,直到再也找不到不再使用的类为止。

  2)已经不再使用的方法。这个找起来有些费劲,因为Objective-C独特的方法签名形式(方法签名由三部分组成,包括方法名称、参数和返回类型)。

仍然是写一个Python脚本,逐个遍历每个类中的方法,然后到项目中查找是否使用到了。

  在执行过程中,遇到这么一种情况,A类和B类都有这个loveBaobao这个方法,方法签名也完全相同。这时Python是区分不出来到底是使用了哪个类的loveBaobao方法的。我们也只能将其汇总起来,然后用手动检查。

  此外,有很多方法是系统自带的,比如说UITableView的那6个方法,只要是使用了UITableView的页面,都有这6个方法。我们在执行Python脚本的时候,不应该统计这样的方法。所以需要做一个白名单,事先把这些方法填进去。

  3)代码相似度问题。初级程序员在写代码时,喜欢把一段代码从A类粘贴到B类中,然后修改其中的几个变量名称,这个功能就算做完了。于是两段相似度极高的代码就产生了。

  稍微懂得些面向对象思想的人,都知道这时候需要把这样的代码抽象出来,比如说在Utils类中新建一个方法,然后要用到这段逻辑的人调用Utils类的这个方法即可。

  但并不是所有的程序员都有这样的境界,即使是有几年经验的人,也会因为急着下班二人世界或者给孩子换尿布而采用复制粘贴大法敷衍了事。久而久之,冗余代码就多了,包的体积自然就大了。为此,我们需要有一个检查代码相似度的工具。在iOS领域,我推荐Simian这个工具。有兴趣的读者可以尝试一下,对你们的项目使用一下这个工具,看能找出来多少相似的代码来。


[1] 关于Android增量更新技术,请参见http://blog.csdn.net/hmg25/article/details/8100896

[2] 关于iOS增量更新机制,请参见https://developer.apple.com/library/ios/qa/qa1779/_index.html?utm_source=iOS+Dev+Weekly&utm_campaign=iOS_Dev_Weekly_Issue_114&utm_medium=email

[3] 详细内容请参见知乎上的这篇文章:http://www.zhihu.com/question/25421514/answer/31623909

[4] 文章参见http://martiancraft.com/blog/2014/09/vector-images-xcode6/

App竞品技术分析 (3)减小安装包的体积(转)


推荐阅读
  • 嵌入式开发环境搭建与文件传输指南
    本文详细介绍了如何为嵌入式应用开发搭建必要的软硬件环境,并提供了通过串口和网线两种方式将文件传输到开发板的具体步骤。适合Linux开发初学者参考。 ... [详细]
  • 解决TensorFlow CPU版本安装中的依赖问题
    本文记录了在安装CPU版本的TensorFlow过程中遇到的依赖问题及解决方案,特别是numpy版本不匹配和动态链接库(DLL)错误。通过详细的步骤说明和专业建议,帮助读者顺利安装并使用TensorFlow。 ... [详细]
  • 本文探讨了在使用Selenium进行自动化测试时,由于webdriver对象实例化位置不同而导致浏览器闪退的问题,并提供了详细的代码示例和解决方案。 ... [详细]
  • 反向投影技术主要用于在大型输入图像中定位特定的小型模板图像。通过直方图对比,它能够识别出最匹配的区域或点,从而确定模板图像在输入图像中的位置。 ... [详细]
  • 在使用STM32Cube进行定时器配置时,有时会遇到延时不准的问题。本文探讨了可能导致延时不准确的原因,并提供了解决方法和预防措施。 ... [详细]
  • 利用Selenium与ChromeDriver实现豆瓣网页全屏截图
    本文介绍了一种使用Selenium和ChromeDriver结合Python代码,轻松实现对豆瓣网站进行完整页面截图的方法。该方法不仅简单易行,而且解决了新版Selenium不再支持PhantomJS的问题。 ... [详细]
  • 本文详细介绍超文本标记语言(HTML)的基本概念与语法结构。HTML是构建网页的核心语言,通过标记标签描述页面内容,帮助开发者创建结构化、语义化的Web页面。 ... [详细]
  • 哈密顿回路问题旨在寻找一个简单回路,该回路包含图中的每个顶点。本文将介绍如何判断给定的路径是否构成哈密顿回路。 ... [详细]
  • JavaScript 中创建对象的多种方式
    本文介绍了 JavaScript 中创建对象的几种常见方法,包括字面量形式、构造函数、原型对象等。每种方法都有其特点和适用场景,通过对比分析,帮助开发者选择最适合的方式。 ... [详细]
  • 算法题解析:最短无序连续子数组
    本题探讨如何通过单调栈的方法,找到一个数组中最短的需要排序的连续子数组。通过正向和反向遍历,分别使用单调递增栈和单调递减栈来确定边界索引,从而定位出最小的无序子数组。 ... [详细]
  • 本文深入探讨了线性代数中向量的线性关系,包括线性相关性和极大线性无关组的概念。通过分析线性方程组和向量组的秩,帮助读者理解这些概念在实际问题中的应用。 ... [详细]
  • 本文介绍如何在 C++ 中使用链表结构存储和管理数据。通过具体示例,展示了静态链表的基本操作,包括节点的创建、链接及遍历。 ... [详细]
  • 本文旨在提供一套高效的面试方法,帮助企业在短时间内找到合适的产品经理。虽然观点较为直接,但其方法已被实践证明有效,尤其适用于初创公司和新项目的需求。 ... [详细]
  • 本文探讨了使用C#在SQL Server和Access数据库中批量插入多条数据的性能差异。通过具体代码示例,详细分析了两种数据库的执行效率,并提供了优化建议。 ... [详细]
  • Linux中的yum安装软件
    yum俗称大黄狗作用:解决安装软件包的依赖关系当安装依赖关系的软件包时,会将依赖的软件包一起安装。本地yum:需要yum源,光驱挂载。yum源:(刚开始查看yum源中的内容就是上图 ... [详细]
author-avatar
手机用户2502854361
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有