Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

深入Spring Boot:ClassLoader的继承关系和影响

$
0
0

前言

对spring boot本身启动原理的分析,请参考:http://hengyunabc.github.io/spring-boot-application-start-analysis/

Spring boot里的ClassLoader继承关系

可以运行下面提供的demo,分别在不同的场景下运行,可以知道不同场景下的Spring boot应用的ClassLoader继承关系。

https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-classloader-context

分三种情况:

在IDE里,直接run main函数

则Spring的ClassLoader直接是SystemClassLoader。ClassLoader的urls包含全部的jar和自己的target/classes

========= Spring Boot Application ClassLoader Urls =============
ClassLoader urls: sun.misc.Launcher$AppClassLoader@2a139a55
file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/classes/
file:/Users/hengyunabc/.m2/repository/org/springframework/cloud/spring-cloud-starter/1.1.9.RELEASE/spring-cloud-starter-1.1.9.RELEASE.jar
file:/Users/hengyunabc/.m2/repository/org/springframework/boot/spring-boot-starter/1.4.7.RELEASE/spring-boot-starter-1.4.7.RELEASE.jar
...

以fat jar运行

mvn clean package
java -jar target/demo-classloader-context-0.0.1-SNAPSHOT.jar

执行应用的main函数的ClassLoader是LaunchedURLClassLoader,它的parent是SystemClassLoader

========= ClassLoader Tree=============
org.springframework.boot.loader.LaunchedURLClassLoader@1218025c
- sun.misc.Launcher$AppClassLoader@6bc7c054
-- sun.misc.Launcher$ExtClassLoader@85ede7b

并且LaunchedURLClassLoader的urls是 fat jar里的BOOT-INF/classes!/目录和BOOT-INF/lib里的所有jar。

========= Spring Boot Application ClassLoader Urls =============
ClassLoader urls: org.springframework.boot.loader.LaunchedURLClassLoader@1218025c
jar:file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/
jar:file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/spring-boot-1.4.7.RELEASE.jar!/
jar:file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/spring-web-4.3.9.RELEASE.jar!/
...

SystemClassLoader的urls是demo-classloader-context-0.0.1-SNAPSHOT.jar本身。

========= System ClassLoader Urls =============
ClassLoader urls: sun.misc.Launcher$AppClassLoader@6bc7c054
file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo-classloader-context-0.0.1-SNAPSHOT.jar

以解压目录运行

mvn clean package
cd target
unzip demo-classloader-context-0.0.1-SNAPSHOT.jar -d demo
cd demo
java org.springframework.boot.loader.PropertiesLauncher

执行应用的main函数的ClassLoader是LaunchedURLClassLoader,它的parent是SystemClassLoader

========= ClassLoader Tree=============
org.springframework.boot.loader.LaunchedURLClassLoader@4aa298b7
- sun.misc.Launcher$AppClassLoader@2a139a55
-- sun.misc.Launcher$ExtClassLoader@1b6d3586

LaunchedURLClassLoader的urls是解压目录里的BOOT-INF/classes//BOOT-INF/lib/下面的jar包。

========= Spring Boot Application ClassLoader Urls =============
ClassLoader urls: org.springframework.boot.loader.LaunchedURLClassLoader@4aa298b7
file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/BOOT-INF/classes/
jar:file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/BOOT-INF/lib/bcpkix-jdk15on-1.55.jar!/
jar:file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/BOOT-INF/lib/bcprov-jdk15on-1.55.jar!/
jar:file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/BOOT-INF/lib/classmate-1.3.3.jar!/

SystemClassLoader的urls只有当前目录:

========= System ClassLoader Urls =============
ClassLoader urls: sun.misc.Launcher$AppClassLoader@2a139a55
file:/Users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/

其实还有两种运行方式:mvn spring-boot:runmvn spring-boot:run -Dfork=true,但是比较少使用,不单独讨论。感觉兴趣的话可以自行跑下。

总结spring boot里ClassLoader的继承关系

  • 在IDE里main函数执行时,只有一个ClassLoader,也就是SystemClassLoader
  • 在以fat jar运行时,有一个LaunchedURLClassLoader,它的parent是SystemClassLoader

    LaunchedURLClassLoader的urls是fat jar里的BOOT-INF/classesBOOT-INF/lib下的jar。SystemClassLoader的urls是fat jar本身。

  • 在解压目录(exploded directory)运行时,和fat jar类似,不过url都是目录形式。目录形式会有更好的兼容性。

spring boot 1.3.* 和 1.4.* 版本的区别

在spring boot 1.3.* 版本里

  • 应用的类和spring boot loader的类都是打包在一个fat jar里
  • 应用依赖的jar放在fat jar里的/lib下面。

在spring boot 1.4.* 版本后

  • spring boot loader的类放在fat jar里
  • 应用的类打包放在fat jar的BOOT-INF/classes目录里
  • 应用依赖的jar放在fat jar里的/lib下面。

spring boot 1.4的打包结构改动是这个commit引入的
https://github.com/spring-projects/spring-boot/commit/87fe0b2adeef85c842c009bfeebac1c84af8a5d7

这个commit的本意是简化classloader的继承关系,以一种直观的parent优先的方式来实现LaunchedURLClassLoader,同时打包结构和传统的war包应用更接近。

但是这个改动引起了很多复杂的问题,从上面我们分析的ClassLoader继承关系就有点头晕了。

目前的ClassLoader继承关系带来的一些影响

有很多用户可能会发现,一些代码在IDE里跑得很好,但是在实际部署运行时不工作。很多时候就是ClassLoader的结构引起的,下面分析一些案例。

demo.jar!/BOOT-INF/classes!/ 这样子url不工作

因为spring boot是扩展了标准的jar协议,让它支持多层的jar in jar,还有directory in jar。参考spring boot应用启动原理分析

在spring boot 1.3的时候尽管会有jar in jar,但是一些比较健壮的代码可以处理这种情况,比如tomcat8自己就支持jar in jar。

但是绝大部分代码都不会支持像demo.jar!/BOOT-INF/classes!/ 这样子directory in jar的多重url,所以在spring boot1.4里,很多库的代码都会失效。

demo.jar!/META-INF/resources 下的资源问题

在servlet 3.0规范里,应用可以把静态资源放在META-INF/resources下面,servlet container会支持读取。但是从上面的继承结果,我们可以发现一个问题:

  • 应用以fat jar来启动,启动embedded tomcat的ClassLoader是LaunchedURLClassLoader
  • LaunchedURLClassLoader的urls并没有fat jar本身
  • 应用的main函数所在的模块的src/main/resources/META-INF/resources目录被打包到了fat jar里,也就是demo.jar!/META-INF/resources
  • 应用的fat jar是SystemClassLoader的url,也就是LaunchedURLClassLoader的parent

这样子就造成了一些奇怪的现象:

  • 应用直接用自己的ClassLoader.getResources()是可以获取到META-INF/resources的资源的
  • 但是embedded tomcat并没有把fat jar本身加入到它的 ResourcesSet 里,因为它在启动时ClassLoader是LaunchedURLClassLoader,它只扫描自己的ClassLoader的urls
  • 应用把资源放在其它的jar包的META-INF/resources下可以访问到,把资源放在自己的main函数的src/main/resources/META-INF/resources下时,访问不到了

另外,spring boot的官方jsp的例子只支持war的打包格式,不支持fat jar,也是由这个引起的。

getResource("")getResources("") 的返回值的问题

getResource("")的语义是返回ClassLoader的urls的第一个url,很多时候使用者以为这个就是它们自己的classes的目录,或者是jar的url。

但是实际上,因为ClassLoader加载urls列表时,有随机性,和OS低层实现有关,并不能保证urls的顺序都是一样的。所以getResource("")很多时候返回的结果并不一样。

但是很多库,或者应用依赖这个代码来定位扫描资源,这样子在spring boot下就不工作了。

另外,值得注意的是spring boot在三种不同形式下运行,getResources("")返回的结果也不一样。用户可以自己改下demo里的代码,打印下结果。

简而言之,不要依赖这两个API,最好自己放一个资源来定位。或者直接利用spring自身提供的资源扫描机制。

类似 classpath*:**-service.xml 的通配问题

用户有多个代码模块,在不同模块下都放了多个*-service.xml的spring配置文件。

用户如果使用类似classpath*:**-service.xml的通配符来加载资源的话,很有可能出现在IDE里跑时,可以正确加载,但是在fat jar下,却加载不到的问题。

从spring自己的文档可以看到相关的解析:

https://docs.spring.io/spring/docs/4.3.9.RELEASE/javadoc-api/org/springframework/core/io/support/PathMatchingResourcePatternResolver.html

WARNING: Note that “classpath*:” when combined with Ant-style patterns will only work reliably with at least one root directory before the pattern starts, unless the actual target files reside in the file system. This means that a pattern like “classpath*:*.xml” will not retrieve files from the root of jar files but rather only from the root of expanded directories. This originates from a limitation in the JDK’s ClassLoader.getResources() method which only returns file system locations for a passed-in empty String (indicating potential roots to search). This ResourcePatternResolver implementation is trying to mitigate the jar root lookup limitation through URLClassLoader introspection and “java.class.path” manifest evaluation; however, without portability guarantees.

就是说使用 classpath*来匹配其它的jar包时,需要有一层目录在前面,不然的话是匹配不到的,这个是ClassLoader.getResources() 函数导致的。

因为在IDE里跑时,应用所依赖的其它模块通常就是一个classes目录,所以通常没有问题。

但是当以fat jar来跑时,其它的模块都被打包为一个jar,放在BOOT-INF/lib下面,所以这时通配就会失败。

总结

  • 这个新的BOOT-INF打包格式有它的明显好处:更清晰,更接近war包的格式。
  • spring boot的ClassLoader的结构修改带来的复杂问题,并非当初修改的人所能预见的
  • 很多问题需要理解spring boot的ClassLoader结构,否则不能找到根本原因
作者:hengyunabc 发表于2017/8/19 16:31:31 原文链接
阅读:0 评论:0 查看评论

struts+hibernate+easyui+mysql实现注册登录和增删改查

$
0
0

btw:半年前帮助一个大学生通过计算机考试,给她写的例子,在csdn发布了这篇文章,趁着闲暇,我把这个demo分享到简书上。毕竟,以后就在简书上写上自己的技术心得和生活感悟嘛

题记:最近复习了很多知识,如struts2、hibernate,包括easyui,我将这些整合在一起做了个用户登录和对文章的增删该查,把写的东西整理成博客,方便以后复习,也为初学者提供一个平台,前人种树,后人乘凉嘛 : )

一:先看看效果

1.注册页面

20161221211005294.png
20161221211005294.png

说明:注册界面用js做了做了验证,另外,注册的密码用了md5做了加密,注册之后直接跳转登录界面进行登录

2.登录界面:

20161221212305774.png
20161221212305774.png

说明:这里我加入了验证码

3.欢迎首页

20161221212339197.png
20161221212339197.png

说明:登录成功之后会显示欢迎谁谁登录,可以注销这个用户,就返回登录界面了,退出没实现。

4.密码修改

20161221212700136.png
20161221212700136.png

说明:密码用了easyui效果,会验证新密码和旧密码是否重复,还有这三项都是必填项。

5.文章列表的增删改查
列表页:

20161221212942668.png
20161221212942668.png

说明:列表页有easyui效果,会好看很多,触碰下一条信息,会有条纹效果。
增加页面:

20161221213308013.png
20161221213308013.png

修改页面:
20161221213426859.png
20161221213426859.png

说明:点击哪一条,将哪一条信息读取到编辑页面,就可以进行修改了。
这里本来想实现1对多,多对1的关系的增删改查呢,所以我在数据库中创建了文章类型,后来出现了easyui的问题,因为很久没接触,我就放弃了复杂化了。。。

**
项目代码我放到了github,github地址是=>https://github.com/railsbigboy/she_demo
**

作者:i__am__sai 发表于2017/8/19 11:49:39 原文链接
阅读:1 评论:0 查看评论

剑指offer——26.二叉搜索树与双向链表

$
0
0

题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

代码

思路:将左子树构成双向链表,返回的是左子树的尾结点,将其连接到root的左边;
将右子树构成双向链表,将其追加到root结点之后,并返回尾结点;
向左遍历返回的链表至头结点处,即为所求双向链表的首结点。

function Convert(pRootOfTree)
{
    // write code here
    if(pRootOfTree==null){
        return null;
    }
    var lastNode=null;
    lastNode=convertNode(pRootOfTree,lastNode);
    var head=lastNode;
    while(head && head.left){//循环到头部
        head=head.left;
    }
    return head;
}
function convertNode(root,lastNode){
    if(root==null) return;
    if(root.left){//左子树
        lastNode=convertNode(root.left,lastNode)
    }
    root.left=lastNode;
    if(lastNode){
        lastNode.right=root;
    }
    lastNode=root;
    if(root.right){//右子树
        lastNode=convertNode(root.right,lastNode)
    }
    return lastNode;
}
作者:owen1190 发表于2017/8/19 16:37:16 原文链接
阅读:6 评论:0 查看评论

MIME一览

$
0
0

整理一帖,备查

常用类型

MIME Type / Internet Media Type File Extension Name
application/msexcel *.xls *.xla Microsoft Excel Dateien
application/mshelp *.hlp *.chm Microsoft Windows Hilfe Dateien
application/mspowerpoint *.ppt *.ppz *.pps *.pot Microsoft Powerpoint Dateien
application/msword *.doc *.dot Microsoft Word Dateien
application/octet-stream *.exe exe
application/pdf *.pdf Adobe PDF-Dateien
application/postscript *.ai *.eps *.ps Adobe PostScript-Dateien
application/rtf *.rtf Microsoft RTF-Dateien
application/x-httpd-php *.php *.phtml PHP-Dateien
application/x-shockwave-flash *.swf *.cab Flash Shockwave-Dateien
application/zip *.zip ZIP-Archivdateien
audio/basic *.au *.snd Sound-Dateien
audio/mpeg *.mp3 MPEG-Dateien
audio/x-midi *.mid *.midi MIDI-Dateien
audio/x-mpeg *.mp2 MPEG-Dateien
audio/x-wav *.wav Wav-Dateien
image/gif *.gif GIF-Dateien
image/jpeg *.jpeg *.jpg *.jpe JPEG-Dateien
image/x-windowdump *.xwd X-Windows Dump
text/css *.css CSS Stylesheet-Dateien
text/html *.htm *.html *.shtml -Dateien
text/javascript *.js JavaScript-Dateien
text/plain *.txt reine Textdateien
video/mpeg *.mpeg *.mpg *.mpe MPEG-Dateien
video/vnd.rn-realvideo *.rmvb realplay-Dateien
video/quicktime *.qt *.mov Quicktime-Dateien
video/vnd *.vivo *viv *.vivo Vivo-Dateien

MIME类型大全

Name MIME Type / Internet Media Type File Extension
3D Crossword Plugin application/vnd.hzn-3d-crossword *.x3d
3GP video/3gpp *.3gp
3GP2 video/3gpp2 *.3g2
3GPP MSEQ File application/vnd.mseq *.mseq
3M Post It Notes application/vnd.3m.post-it-notes *.pwn
3rd Generation Partnership Project - Pic Large application/vnd.3gpp.pic-bw-large *.plb
3rd Generation Partnership Project - Pic Small application/vnd.3gpp.pic-bw-small *.psb
3rd Generation Partnership Project - Pic Var application/vnd.3gpp.pic-bw-var *.pvb
3rd Generation Partnership Project - Transaction Capabilities Application Part application/vnd.3gpp2.tcap *.tcap
7-Zip application/x-7z-compressed *.7z
AbiWord application/x-abiword *.abw
Ace Archive application/x-ace-compressed *.ace
Active Content Compression application/vnd.americandynamics.acc *.acc
ACU Cobol application/vnd.acucobol *.acu
ACU Cobol application/vnd.acucorp *.atc
Adaptive differential pulse-code modulation audio/adpcm *.adp
Adobe (Macropedia) Authorware - Binary File application/x-authorware-bin *.aab
Adobe (Macropedia) Authorware - Map application/x-authorware-map *.aam
Adobe (Macropedia) Authorware - Segment File application/x-authorware-seg *.aas
Adobe AIR Application application/vnd.adobe.air-application-installer-package+zip *.air
Adobe Flash application/x-shockwave-flash *.swf
Adobe Flex Project application/vnd.adobe.fxp *.fxp
Adobe Portable Document Format application/pdf *.pdf
Adobe PostScript Printer Description File Format application/vnd.cups-ppd *.ppd
Adobe Shockwave Player application/x-director *.dir
Adobe XML Data Package application/vnd.adobe.xdp+xml *.xdp
Adobe XML Forms Data Format application/vnd.adobe.xfdf *.xfdf
Advanced Audio Coding (AAC) audio/x-aac *.aac
Ahead AIR Application application/vnd.ahead.space *.ahead
AirZip FileSECURE application/vnd.airzip.filesecure.azf *.azf
AirZip FileSECURE application/vnd.airzip.filesecure.azs *.azs
Amazon Kindle eBook format application/vnd.amazon.ebook *.azw
AmigaDE application/vnd.amiga.ami *.ami
Andrew Toolkit application/andrew-inset N/A
Android Package Archive application/vnd.android.package-archive *.apk
ANSER-WEB Terminal Client - Certificate Issue application/vnd.anser-web-certificate-issue-initiation *.cii
ANSER-WEB Terminal Client - Web Funds Transfer application/vnd.anser-web-funds-transfer-initiation *.fti
Antix Game Player application/vnd.antix.game-component *.atx
Apple Installer Package application/vnd.apple.installer+xml *.mpkg
Applixware application/applixware *.aw
Archipelago Lesson Player application/vnd.hhe.lesson-player *.les
Arista Networks Software Image application/vnd.aristanetworks.swi *.swi
Assembler Source File text/x-asm *.s
Atom Publishing Protocol application/atomcat+xml *.atomcat
Atom Publishing Protocol Service Document application/atomsvc+xml *.atomsvc
Atom Syndication Format application/atom+xml *.atom, *.xml
Attribute Certificate application/pkix-attr-cert *.ac
Audio Interchange File Format audio/x-aiff *.aif
Audio Video Interleave (AVI) video/x-msvideo *.avi
Audiograph application/vnd.audiograph *.aep
AutoCAD DXF image/vnd.dxf *.dxf
Autodesk Design Web Format (DWF) model/vnd.dwf *.dwf
Binary CPIO Archive application/x-bcpio *.bcpio
Binary Data application/octet-stream *.bin
Bitmap Image File image/bmp *.bmp
BitTorrent application/x-bittorrent *.torrent
Blackberry COD File application/vnd.rim.cod *.cod
Blueice Research Multipass application/vnd.blueice.multipass *.mpm
BMI Drawing Data Interchange application/vnd.bmi *.bmi
Bourne Shell Script application/x-sh *.sh
BTIF image/prs.btif *.btif
BusinessObjects application/vnd.businessobjects *.rep
Bzip Archive application/x-bzip *.bz
Bzip2 Archive application/x-bzip2 *.bz2
C Shell Script application/x-csh *.csh
C Source File text/x-c *.c
CambridgeSoft Chem Draw application/vnd.chemdraw+xml *.cdxml
Cascading Style Sheets (CSS) text/css *.css
ChemDraw eXchange file chemical/x-cdx *.cdx
Chemical Markup Language chemical/x-cml *.cml
Chemical Style Markup Language chemical/x-csml *.csml
CIM Database application/vnd.contact.cmsg *.cdbcmsg
Claymore Data Files application/vnd.claymore *.cla
Clonk Game application/vnd.clonk.c4group *.c4g
Close Captioning - Subtitle image/vnd.dvb.subtitle *.sub
Cloud Data Management Interface (CDMI) - Capability application/cdmi-capability *.cdmia
Cloud Data Management Interface (CDMI) - Contaimer application/cdmi-container *.cdmic
Cloud Data Management Interface (CDMI) - Domain application/cdmi-domain *.cdmid
Cloud Data Management Interface (CDMI) - Object application/cdmi-object *.cdmio
Cloud Data Management Interface (CDMI) - Queue application/cdmi-queue *.cdmiq
ClueTrust CartoMobile - Config application/vnd.cluetrust.cartomobile-config *.c11amc
ClueTrust CartoMobile - Config Package application/vnd.cluetrust.cartomobile-config-pkg *.c11amz
CMU Image image/x-cmu-raster *.ras
COLLADA model/vnd.collada+xml *.dae
Comma-Seperated Values text/csv *.csv
Compact Pro application/mac-compactpro *.cpt
Compiled Wireless Markup Language (WMLC) application/vnd.wap.wmlc *.wmlc
Computer Graphics Metafile image/cgm *.cgm
CoolTalk x-conference/x-cooltalk *.ice
Corel Metafile Exchange (CMX) image/x-cmx *.cmx
CorelXARA application/vnd.xara *.xar
CosmoCaller application/vnd.cosmocaller *.cmc
CPIO Archive application/x-cpio *.cpio
CrickSoftware - Clicker application/vnd.crick.clicker *.clkx
CrickSoftware - Clicker - Keyboard application/vnd.crick.clicker.keyboard *.clkk
CrickSoftware - Clicker - Palette application/vnd.crick.clicker.palette *.clkp
CrickSoftware - Clicker - Template application/vnd.crick.clicker.template *.clkt
CrickSoftware - Clicker - Wordbank application/vnd.crick.clicker.wordbank *.clkw
Critical Tools - PERT Chart EXPERT application/vnd.criticaltools.wbs+xml *.wbs
CryptoNote application/vnd.rig.cryptonote *.cryptonote
Crystallographic Interchange Format chemical/x-cif *.cif
CrystalMaker Data Format chemical/x-cmdf *.cmdf
CU-SeeMe application/cu-seeme *.cu
CU-Writer application/prs.cww *.cww
Curl - Applet text/vnd.curl *.curl
Curl - Detached Applet text/vnd.curl.dcurl *.dcurl
Curl - Manifest File text/vnd.curl.mcurl *.mcurl
Curl - Source Code text/vnd.curl.scurl *.scurl
CURL Applet application/vnd.curl.car *.car
CURL Applet application/vnd.curl.pcurl *.pcurl
CustomMenu application/vnd.yellowriver-custom-menu *.cmp
Data Structure for the Security Suitability of Cryptographic Algorithms application/dssc+der *.dssc
Data Structure for the Security Suitability of Cryptographic Algorithms application/dssc+xml *.xdssc
Debian Package application/x-debian-package *.deb
DECE Audio audio/vnd.dece.audio *.uva
DECE Graphic image/vnd.dece.graphic *.uvi
DECE High Definition Video video/vnd.dece.hd *.uvh
DECE Mobile Video video/vnd.dece.mobile *.uvm
DECE MP4 video/vnd.uvvu.mp4 *.uvu
DECE PD Video video/vnd.dece.pd *.uvp
DECE SD Video video/vnd.dece.sd *.uvs
DECE Video video/vnd.dece.video *.uvv
Device Independent File Format (DVI) application/x-dvi *.dvi
Digital Siesmograph Networks - SEED Datafiles application/vnd.fdsn.seed *.seed
Digital Talking Book application/x-dtbook+xml *.dtb
Digital Talking Book - Resource File application/x-dtbresource+xml *.res
Digital Video Broadcasting application/vnd.dvb.ait *.ait
Digital Video Broadcasting application/vnd.dvb.service *.svc
Digital Winds Music audio/vnd.digital-winds *.eol
DjVu image/vnd.djvu *.djvu
Document Type Definition application/xml-dtd *.dtd
Dolby Meridian Lossless Packing application/vnd.dolby.mlp *.mlp
Doom Video Game application/x-doom *.wad
DPGraph application/vnd.dpgraph *.dpg
DRA Audio audio/vnd.dra *.dra
DreamFactory application/vnd.dreamfactory *.dfac
DTS Audio audio/vnd.dts *.dts
DTS High Definition Audio audio/vnd.dts.hd *.dtshd
DWG Drawing image/vnd.dwg *.dwg
DynaGeo application/vnd.dynageo *.geo
ECMAScript application/ecmascript *.es
EcoWin Chart application/vnd.ecowin.chart *.mag
EDMICS 2000 image/vnd.fujixerox.edmics-mmr *.mmr
EDMICS 2000 image/vnd.fujixerox.edmics-rlc *.rlc
Efficient XML Interchange application/exi *.exi
EFI Proteus application/vnd.proteus.magazine *.mgz
Electronic Publication application/epub+zip *.epub
Email Message message/rfc822 *.eml
Enliven Viewer application/vnd.enliven *.nml
Express by Infoseek application/vnd.is-xpr *.xpr
eXtended Image File Format (XIFF) image/vnd.xiff *.xif
Extensible Forms Description Language application/vnd.xfdl *.xfdl
Extensible MultiModal Annotation application/emma+xml *.emma
EZPix Secure Photo Album application/vnd.ezpix-album *.ez2
EZPix Secure Photo Album application/vnd.ezpix-package *.ez3
FAST Search & Transfer ASA image/vnd.fst *.fst
FAST Search & Transfer ASA video/vnd.fvt *.fvt
FastBid Sheet image/vnd.fastbidsheet *.fbs
FCS Express Layout Link application/vnd.denovo.fcselayout-link *.fe_launch
Flash Video video/x-f4v *.f4v
Flash Video video/x-flv *.flv
FlashPix image/vnd.fpx *.fpx
FlashPix image/vnd.net-fpx *.npx
FLEXSTOR text/vnd.fmi.flexstor *.flx
FLI/FLC Animation Format video/x-fli *.fli
FluxTime Clip application/vnd.fluxtime.clip *.ftc
Forms Data Format application/vnd.fdf *.fdf
Fortran Source File text/x-fortran *.f
FrameMaker Interchange Format application/vnd.mif *.mif
FrameMaker Normal Format application/vnd.framemaker *.fm
FreeHand MX image/x-freehand *.fh
Friendly Software Corporation application/vnd.fsc.weblaunch *.fsc
Frogans Player application/vnd.frogans.fnc *.fnc
Frogans Player application/vnd.frogans.ltf *.ltf
Fujitsu - Xerox 2D CAD Data application/vnd.fujixerox.ddd *.ddd
Fujitsu - Xerox DocuWorks application/vnd.fujixerox.docuworks *.xdw
Fujitsu - Xerox DocuWorks Binder application/vnd.fujixerox.docuworks.binder *.xbd
Fujitsu Oasys application/vnd.fujitsu.oasys *.oas
Fujitsu Oasys application/vnd.fujitsu.oasys2 *.oa2
Fujitsu Oasys application/vnd.fujitsu.oasys3 *.oa3
Fujitsu Oasys application/vnd.fujitsu.oasysgp *.fg5
Fujitsu Oasys application/vnd.fujitsu.oasysprs *.bh2
FutureSplash Animator application/x-futuresplash *.spl
FuzzySheet application/vnd.fuzzysheet *.fzs
G3 Fax Image image/g3fax *.g3
GameMaker ActiveX application/vnd.gmx *.gmx
Gen-Trix Studio model/vnd.gtw *.gtw
Genomatix Tuxedo Framework application/vnd.genomatix.tuxedo *.txd
GeoGebra application/vnd.geogebra.file *.ggb
GeoGebra application/vnd.geogebra.tool *.ggt
Geometric Description Language (GDL) model/vnd.gdl *.gdl
GeoMetry Explorer application/vnd.geometry-explorer *.gex
GEONExT and JSXGraph application/vnd.geonext *.gxt
GeoplanW application/vnd.geoplan *.g2w
GeospacW application/vnd.geospace *.g3w
Ghostscript Font application/x-font-ghostscript *.gsf
Glyph Bitmap Distribution Format application/x-font-bdf *.bdf
GNU Tar Files application/x-gtar *.gtar
GNU Texinfo Document application/x-texinfo *.texinfo
Gnumeric application/x-gnumeric *.gnumeric
Google Earth - KML application/vnd.google-earth.kml+xml *.kml
Google Earth - Zipped KML application/vnd.google-earth.kmz *.kmz
GrafEq application/vnd.grafeq *.gqf
Graphics Interchange Format image/gif *.gif
Graphviz text/vnd.graphviz *.gv
Groove - Account application/vnd.groove-account *.gac
Groove - Help application/vnd.groove-help *.ghf
Groove - Identity Message application/vnd.groove-identity-message *.gim
Groove - Injector application/vnd.groove-injector *.grv
Groove - Tool Message application/vnd.groove-tool-message *.gtm
Groove - Tool Template application/vnd.groove-tool-template *.tpl
Groove - Vcard application/vnd.groove-vcard *.vcg
H.261 video/h261 *.h261
H.263 video/h263 *.h263
H.264 video/h264 *.h264
Hewlett Packard Instant Delivery application/vnd.hp-hpid *.hpid
Hewlett-Packard’s WebPrintSmart application/vnd.hp-hps *.hps
Hierarchical Data Format application/x-hdf *.hdf
Hit’n’Mix audio/vnd.rip *.rip
Homebanking Computer Interface (HBCI) application/vnd.hbci *.hbci
HP Indigo Digital Press - Job Layout Languate application/vnd.hp-jlyt *.jlt
HP Printer Command Language application/vnd.hp-pcl *.pcl
HP-GL/2 and HP RTL application/vnd.hp-hpgl *.hpgl
HV Script application/vnd.yamaha.hv-script *.hvs
HV Voice Dictionary application/vnd.yamaha.hv-dic *.hvd
HV Voice Parameter application/vnd.yamaha.hv-voice *.hvp
Hydrostatix Master Suite application/vnd.hydrostatix.sof-data *.sfd-hdstx
Hyperstudio application/hyperstudio *.stk
Hypertext Application Language application/vnd.hal+xml *.hal
HyperText Markup Language (HTML) text/html *.html
IBM DB2 Rights Manager application/vnd.ibm.rights-management *.irm
IBM Electronic Media Management System - Secure Container application/vnd.ibm.secure-container *.sc
iCalendar text/calendar *.ics
ICC profile application/vnd.iccprofile *.icc
Icon Image image/x-icon *.ico
igLoader application/vnd.igloader *.igl
Image Exchange Format image/ief *.ief
ImmerVision PURE Players application/vnd.immervision-ivp *.ivp
ImmerVision PURE Players application/vnd.immervision-ivu *.ivu
IMS Networks application/reginfo+xml *.rif
In3D - 3DML text/vnd.in3d.3dml *.3dml
In3D - 3DML text/vnd.in3d.spot *.spot
Initial Graphics Exchange Specification (IGES) model/iges *.igs
Interactive Geometry Software application/vnd.intergeo *.i2g
Interactive Geometry Software Cinderella application/vnd.cinderella *.cdy
Intercon FormNet application/vnd.intercon.formnet *.xpw
International Society for Advancement of Cytometry application/vnd.isac.fcs *.fcs
Internet Protocol Flow Information Export application/ipfix *.ipfix
Internet Public Key Infrastructure - Certificate application/pkix-cert *.cer
Internet Public Key Infrastructure - Certificate Management Protocole application/pkixcmp *.pki
Internet Public Key Infrastructure - Certificate Revocation Lists application/pkix-crl *.crl
Internet Public Key Infrastructure - Certification Path application/pkix-pkipath *.pkipath
IOCOM Visimeet application/vnd.insors.igm *.igm
IP Unplugged Roaming Client application/vnd.ipunplugged.rcprofile *.rcprofile
iRepository / Lucidoc Editor application/vnd.irepository.package+xml *.irp
J2ME App Descriptor text/vnd.sun.j2me.app-descriptor *.jad
Java Archive application/java-archive *.jar
Java Bytecode File application/java-vm *.class
Java Network Launching Protocol application/x-java-jnlp-file *.jnlp
Java Serialized Object application/java-serialized-object *.ser
Java Source File text/x-java-source,java *.java
JavaScript application/javascript *.js
JavaScript Object Notation (JSON) application/json *.json
Joda Archive application/vnd.joost.joda-archive *.joda
JPEG 2000 Compound Image File Format video/jpm *.jpm
JPEG Image image/jpeg *.jpeg, *.jpg
JPGVideo video/jpeg *.jpgv
Kahootz application/vnd.kahootz *.ktz
Karaoke on Chipnuts Chipsets application/vnd.chipnuts.karaoke-mmd *.mmd
KDE KOffice Office Suite - Karbon application/vnd.kde.karbon *.karbon
KDE KOffice Office Suite - KChart application/vnd.kde.kchart *.chrt
KDE KOffice Office Suite - Kformula application/vnd.kde.kformula *.kfo
KDE KOffice Office Suite - Kivio application/vnd.kde.kivio *.flw
KDE KOffice Office Suite - Kontour application/vnd.kde.kontour *.kon
KDE KOffice Office Suite - Kpresenter application/vnd.kde.kpresenter *.kpr
KDE KOffice Office Suite - Kspread application/vnd.kde.kspread *.ksp
KDE KOffice Office Suite - Kword application/vnd.kde.kword *.kwd
Kenamea App application/vnd.kenameaapp *.htke
Kidspiration application/vnd.kidspiration *.kia
Kinar Applications application/vnd.kinar *.kne
Kodak Storyshare application/vnd.kodak-descriptor *.sse
Laser App Enterprise application/vnd.las.las+xml *.lasxml
LaTeX application/x-latex *.latex
Life Balance - Desktop Edition application/vnd.llamagraphics.life-balance.desktop *.lbd
Life Balance - Exchange Format application/vnd.llamagraphics.life-balance.exchange+xml *.lbe
Lightspeed Audio Lab application/vnd.jam *.jam
Lotus 1-2-3 application/vnd.lotus-1-2-3 0.123
Lotus Approach application/vnd.lotus-approach *.apr
Lotus Freelance application/vnd.lotus-freelance *.pre
Lotus Notes application/vnd.lotus-notes *.nsf
Lotus Organizer application/vnd.lotus-organizer *.org
Lotus Screencam application/vnd.lotus-screencam *.scm
Lotus Wordpro application/vnd.lotus-wordpro *.lwp
Lucent Voice audio/vnd.lucent.voice *.lvp
M3U (Multimedia Playlist) audio/x-mpegurl *.m3u
M4v video/x-m4v *.m4v
Macintosh BinHex 4.0 application/mac-binhex40 *.hqx
MacPorts Port System application/vnd.macports.portpkg *.portpkg
MapGuide DBXML application/vnd.osgeo.mapguide.package *.mgp
MARC Formats application/marc *.mrc
MARC21 XML Schema application/marcxml+xml *.mrcx
Material Exchange Format application/mxf *.mxf
Mathematica Notebook Player application/vnd.wolfram.player *.nbp
Mathematica Notebooks application/mathematica *.ma
Mathematical Markup Language application/mathml+xml *.mathml
Mbox database files application/mbox *.mbox
MedCalc application/vnd.medcalcdata *.mc1
Media Server Control Markup Language application/mediaservercontrol+xml *.mscml
MediaRemote application/vnd.mediastation.cdkey *.cdkey
Medical Waveform Encoding Format application/vnd.mfer *.mwf
Melody Format for Mobile Platform application/vnd.mfmp *.mfm
Mesh Data Type model/mesh *.msh
Metadata Authority Description Schema application/mads+xml *.mads
Metadata Encoding and Transmission Standard application/mets+xml *.mets
Metadata Object Description Schema application/mods+xml *.mods
Metalink application/metalink4+xml *.meta4
Micosoft PowerPoint - Macro-Enabled Template File application/vnd.ms-powerpoint.template.macroenabled.12 *.potm
Micosoft Word - Macro-Enabled Document application/vnd.ms-word.document.macroenabled.12 *.docm
Micosoft Word - Macro-Enabled Template application/vnd.ms-word.template.macroenabled.12 *.dotm
Micro CADAM Helix D&D application/vnd.mcd *.mcd
Micrografx application/vnd.micrografx.flo *.flo
Micrografx iGrafx Professional application/vnd.micrografx.igx *.igx
MICROSEC e-Szign¢ application/vnd.eszigno3+xml *.es3
Microsoft Access application/x-msaccess *.mdb
Microsoft Advanced Systems Format (ASF) video/x-ms-asf *.asf
Microsoft Application application/x-msdownload *.exe
Microsoft Artgalry application/vnd.ms-artgalry *.cil
Microsoft Cabinet File application/vnd.ms-cab-compressed *.cab
Microsoft Class Server application/vnd.ms-ims *.ims
Microsoft ClickOnce application/x-ms-application *.application
Microsoft Clipboard Clip application/x-msclip *.clp
Microsoft Document Imaging Format image/vnd.ms-modi *.mdi
Microsoft Embedded OpenType application/vnd.ms-fontobject *.eot
Microsoft Excel application/vnd.ms-excel *.xls
Microsoft Excel - Add-In File application/vnd.ms-excel.addin.macroenabled.12 *.xlam
Microsoft Excel - Binary Workbook application/vnd.ms-excel.sheet.binary.macroenabled.12 *.xlsb
Microsoft Excel - Macro-Enabled Template File application/vnd.ms-excel.template.macroenabled.12 *.xltm
Microsoft Excel - Macro-Enabled Workbook application/vnd.ms-excel.sheet.macroenabled.12 *.xlsm
Microsoft Html Help File application/vnd.ms-htmlhelp *.chm
Microsoft Information Card application/x-mscardfile *.crd
Microsoft Learning Resource Module application/vnd.ms-lrm *.lrm
Microsoft MediaView application/x-msmediaview *.mvb
Microsoft Money application/x-msmoney *.mny
Microsoft Office - OOXML - Presentation application/vnd.openxmlformats-officedocument.presentationml.presentation *.pptx
Microsoft Office - OOXML - Presentation (Slide) application/vnd.openxmlformats-officedocument.presentationml.slide *.sldx
Microsoft Office - OOXML - Presentation (Slideshow) application/vnd.openxmlformats-officedocument.presentationml.slideshow *.ppsx
Microsoft Office - OOXML - Presentation Template application/vnd.openxmlformats-officedocument.presentationml.template *.potx
Microsoft Office - OOXML - Spreadsheet application/vnd.openxmlformats-officedocument.spreadsheetml.sheet *.xlsx
Microsoft Office - OOXML - Spreadsheet Teplate application/vnd.openxmlformats-officedocument.spreadsheetml.template *.xltx
Microsoft Office - OOXML - Word Document application/vnd.openxmlformats-officedocument.wordprocessingml.document *.docx
Microsoft Office - OOXML - Word Document Template application/vnd.openxmlformats-officedocument.wordprocessingml.template *.dotx
Microsoft Office Binder application/x-msbinder *.obd
Microsoft Office System Release Theme application/vnd.ms-officetheme *.thmx
Microsoft OneNote application/onenote *.onetoc
Microsoft PlayReady Ecosystem audio/vnd.ms-playready.media.pya *.pya
Microsoft PlayReady Ecosystem Video video/vnd.ms-playready.media.pyv *.pyv
Microsoft PowerPoint application/vnd.ms-powerpoint *.ppt
Microsoft PowerPoint - Add-in file application/vnd.ms-powerpoint.addin.macroenabled.12 *.ppam
Microsoft PowerPoint - Macro-Enabled Open XML Slide application/vnd.ms-powerpoint.slide.macroenabled.12 *.sldm
Microsoft PowerPoint - Macro-Enabled Presentation File application/vnd.ms-powerpoint.presentation.macroenabled.12 *.pptm
Microsoft PowerPoint - Macro-Enabled Slide Show File application/vnd.ms-powerpoint.slideshow.macroenabled.12 *.ppsm
Microsoft Project application/vnd.ms-project *.mpp
Microsoft Publisher application/x-mspublisher *.pub
Microsoft Schedule+ application/x-msschedule *.scd
Microsoft Silverlight application/x-silverlight-app *.xap
Microsoft Trust UI Provider - Certificate Trust Link application/vnd.ms-pki.stl *.stl
Microsoft Trust UI Provider - Security Catalog application/vnd.ms-pki.seccat *.cat
Microsoft Visio application/vnd.visio *.vsd
Microsoft Windows Media video/x-ms-wm *.wm
Microsoft Windows Media Audio audio/x-ms-wma *.wma
Microsoft Windows Media Audio Redirector audio/x-ms-wax *.wax
Microsoft Windows Media Audio/Video Playlist video/x-ms-wmx *.wmx
Microsoft Windows Media Player Download Package application/x-ms-wmd *.wmd
Microsoft Windows Media Player Playlist application/vnd.ms-wpl *.wpl
Microsoft Windows Media Player Skin Package application/x-ms-wmz *.wmz
Microsoft Windows Media Video video/x-ms-wmv *.wmv
Microsoft Windows Media Video Playlist video/x-ms-wvx *.wvx
Microsoft Windows Metafile application/x-msmetafile *.wmf
Microsoft Windows Terminal Services application/x-msterminal *.trm
Microsoft Word application/msword *.doc
Microsoft Wordpad application/x-mswrite *.wri
Microsoft Works application/vnd.ms-works *.wps
Microsoft XAML Browser Application application/x-ms-xbap *.xbap
Microsoft XML Paper Specification application/vnd.ms-xpsdocument *.xps
MIDI - Musical Instrument Digital Interface audio/midi *.mid
MiniPay application/vnd.ibm.minipay *.mpy
MO:DCA-P application/vnd.ibm.modcap *.afp
Mobile Information Device Profile application/vnd.jcp.javame.midlet-rms *.rms
MobileTV application/vnd.tmobile-livetv *.tmo
Mobipocket application/x-mobipocket-ebook *.prc
Mobius Management Systems - Basket file application/vnd.mobius.mbk *.mbk
Mobius Management Systems - Distribution Database application/vnd.mobius.dis *.dis
Mobius Management Systems - Policy Definition Language File application/vnd.mobius.plc *.plc
Mobius Management Systems - Query File application/vnd.mobius.mqy *.mqy
Mobius Management Systems - Script Language application/vnd.mobius.msl *.msl
Mobius Management Systems - Topic Index File application/vnd.mobius.txf *.txf
Mobius Management Systems - UniversalArchive application/vnd.mobius.daf *.daf
mod_fly / fly.cgi text/vnd.fly *.fly
Mophun Certificate application/vnd.mophun.certificate *.mpc
Mophun VM application/vnd.mophun.application *.mpn
Motion JPEG 2000 video/mj2 *.mj2
MPEG Audio audio/mpeg *.mpga
MPEG Url video/vnd.mpegurl *.mxu
MPEG Video video/mpeg *.mpeg
MPEG-21 application/mp21 *.m21
MPEG-4 Audio audio/mp4 *.mp4a
MPEG-4 Video video/mp4 *.mp4
MPEG4 application/mp4 *.mp4
Multimedia Playlist Unicode application/vnd.apple.mpegurl *.m3u8
MUsical Score Interpreted Code Invented for the ASCII designation of Notation application/vnd.musician *.mus
Muvee Automatic Video Editing application/vnd.muvee.style *.msty
MXML application/xv+xml *.mxml
N-Gage Game Data application/vnd.nokia.n-gage.data *.ngdat
N-Gage Game Installer application/vnd.nokia.n-gage.symbian.install *.n-gage
Navigation Control file for XML (for ePub) application/x-dtbncx+xml *.ncx
Network Common Data Form (NetCDF) application/x-netcdf *.nc
neuroLanguage application/vnd.neurolanguage.nlu *.nlu
New Moon Liftoff/DNA application/vnd.dna *.dna
NobleNet Directory application/vnd.noblenet-directory *.nnd
NobleNet Sealer application/vnd.noblenet-sealer *.nns
NobleNet Web application/vnd.noblenet-web *.nnw
Nokia Radio Application - Preset application/vnd.nokia.radio-preset *.rpst
Nokia Radio Application - Preset application/vnd.nokia.radio-presets *.rpss
Notation3 text/n3 *.n3
Novadigm’s RADIA and EDM products application/vnd.novadigm.edm *.edm
Novadigm’s RADIA and EDM products application/vnd.novadigm.edx *.edx
Novadigm’s RADIA and EDM products application/vnd.novadigm.ext *.ext
NpGraphIt application/vnd.flographit *.gph
Nuera ECELP 4800 audio/vnd.nuera.ecelp4800 *.ecelp4800
Nuera ECELP 7470 audio/vnd.nuera.ecelp7470 *.ecelp7470
Nuera ECELP 9600 audio/vnd.nuera.ecelp9600 *.ecelp9600
Office Document Architecture application/oda *.oda
Ogg application/ogg *.ogx
Ogg Audio audio/ogg *.oga
Ogg Video video/ogg *.ogv
OMA Download Agents application/vnd.oma.dd2+xml *.dd2
Open Document Text Web application/vnd.oasis.opendocument.text-web *.oth
Open eBook Publication Structure application/oebps-package+xml *.opf
Open Financial Exchange application/vnd.intu.qbo *.qbo
Open Office Extension application/vnd.openofficeorg.extension *.oxt
Open Score Format application/vnd.yamaha.openscoreformat *.osf
Open Web Media Project - Audio audio/webm *.weba
Open Web Media Project - Video video/webm *.webm
OpenDocument Chart application/vnd.oasis.opendocument.chart *.odc
OpenDocument Chart Template application/vnd.oasis.opendocument.chart-template *.otc
OpenDocument Database application/vnd.oasis.opendocument.database *.odb
OpenDocument Formula application/vnd.oasis.opendocument.formula *.odf
OpenDocument Formula Template application/vnd.oasis.opendocument.formula-template *.odft
OpenDocument Graphics application/vnd.oasis.opendocument.graphics *.odg
OpenDocument Graphics Template application/vnd.oasis.opendocument.graphics-template *.otg
OpenDocument Image application/vnd.oasis.opendocument.image *.odi
OpenDocument Image Template application/vnd.oasis.opendocument.image-template *.oti
OpenDocument Presentation application/vnd.oasis.opendocument.presentation *.odp
OpenDocument Presentation Template application/vnd.oasis.opendocument.presentation-template *.otp
OpenDocument Spreadsheet application/vnd.oasis.opendocument.spreadsheet *.ods
OpenDocument Spreadsheet Template application/vnd.oasis.opendocument.spreadsheet-template *.ots
OpenDocument Text application/vnd.oasis.opendocument.text *.odt
OpenDocument Text Master application/vnd.oasis.opendocument.text-master *.odm
OpenDocument Text Template application/vnd.oasis.opendocument.text-template *.ott
OpenGL Textures (KTX) image/ktx *.ktx
OpenOffice - Calc (Spreadsheet) application/vnd.sun.xml.calc *.sxc
OpenOffice - Calc Template (Spreadsheet) application/vnd.sun.xml.calc.template *.stc
OpenOffice - Draw (Graphics) application/vnd.sun.xml.draw *.sxd
OpenOffice - Draw Template (Graphics) application/vnd.sun.xml.draw.template *.std
OpenOffice - Impress (Presentation) application/vnd.sun.xml.impress *.sxi
OpenOffice - Impress Template (Presentation) application/vnd.sun.xml.impress.template *.sti
OpenOffice - Math (Formula) application/vnd.sun.xml.math *.sxm
OpenOffice - Writer (Text - HTML) application/vnd.sun.xml.writer *.sxw
OpenOffice - Writer (Text - HTML) application/vnd.sun.xml.writer.global *.sxg
OpenOffice - Writer Template (Text - HTML) application/vnd.sun.xml.writer.template *.stw
OpenType Font File application/x-font-otf *.otf
OSFPVG application/vnd.yamaha.openscoreformat.osfpvg+xml *.osfpvg
OSGi Deployment Package application/vnd.osgi.dp *.dp
PalmOS Data application/vnd.palm *.pdb
Pascal Source File text/x-pascal *.p
PawaaFILE application/vnd.pawaafile *.paw
PCL 6 Enhanced (Formely PCL XL) application/vnd.hp-pclxl *.pclxl
Pcsel eFIF File application/vnd.picsel *.efif
PCX Image image/x-pcx *.pcx
Photoshop Document image/vnd.adobe.photoshop *.psd
PICSRules application/pics-rules *.prf
PICT Image image/x-pict *.pic
pIRCh application/x-chat *.chat
PKCS #10 - Certification Request Standard application/pkcs10 *.p10
PKCS #12 - Personal Information Exchange Syntax Standard application/x-pkcs12 *.p12
PKCS #7 - Cryptographic Message Syntax Standard application/pkcs7-mime *.p7m
PKCS #7 - Cryptographic Message Syntax Standard application/pkcs7-signature *.p7s
PKCS #7 - Cryptographic Message Syntax Standard (Certificate Request Response) application/x-pkcs7-certreqresp *.p7r
PKCS #7 - Cryptographic Message Syntax Standard (Certificates) application/x-pkcs7-certificates *.p7b
PKCS #8 - Private-Key Information Syntax Standard application/pkcs8 *.p8
PocketLearn Viewers application/vnd.pocketlearn *.plf
Portable Anymap Image image/x-portable-anymap *.pnm
Portable Bitmap Format image/x-portable-bitmap *.pbm
Portable Compiled Format application/x-font-pcf *.pcf
Portable Font Resource application/font-tdpfr *.pfr
Portable Game Notation (Chess Games) application/x-chess-pgn *.pgn
Portable Graymap Format image/x-portable-graymap *.pgm
Portable Network Graphics (PNG) image/png *.png
Portable Pixmap Format image/x-portable-pixmap *.ppm
Portable Symmetric Key Container application/pskc+xml *.pskcxml
PosML application/vnd.ctc-posml *.pml
PostScript application/postscript *.ai
PostScript Fonts application/x-font-type1 *.pfa
PowerBuilder application/vnd.powerbuilder6 *.pbd
Pretty Good Privacy application/pgp-encrypted
Pretty Good Privacy - Signature application/pgp-signature *.pgp
Preview Systems ZipLock/VBox application/vnd.previewsystems.box *.box
Princeton Video Image application/vnd.pvi.ptid1 *.ptid
Pronunciation Lexicon Specification application/pls+xml *.pls
Proprietary P&G Standard Reporting System application/vnd.pg.format *.str
Proprietary P&G Standard Reporting System application/vnd.pg.osasli *.ei6
PRS Lines Tag text/prs.lines.tag *.dsc
PSF Fonts application/x-font-linux-psf *.psf
PubliShare Objects application/vnd.publishare-delta-tree *.qps
Qualcomm’s Plaza Mobile Internet application/vnd.pmi.widget *.wg
QuarkXpress application/vnd.quark.quarkxpress *.qxd
QUASS Stream Player application/vnd.epson.esf *.esf
QUASS Stream Player application/vnd.epson.msf *.msf
QUASS Stream Player application/vnd.epson.ssf *.ssf
QuickAnime Player application/vnd.epson.quickanime *.qam
Quicken application/vnd.intu.qfx *.qfx
Quicktime Video video/quicktime *.qt
RAR Archive application/x-rar-compressed *.rar
Real Audio Sound audio/x-pn-realaudio *.ram
Real Audio Sound audio/x-pn-realaudio-plugin *.rmp
Really Simple Discovery application/rsd+xml *.rsd
RealMedia application/vnd.rn-realmedia *.rm
RealVNC application/vnd.realvnc.bed *.bed
Recordare Applications application/vnd.recordare.musicxml *.mxl
Recordare Applications application/vnd.recordare.musicxml+xml *.musicxml
Relax NG Compact Syntax application/relax-ng-compact-syntax *.rnc
RemoteDocs R-Viewer application/vnd.data-vision.rdz *.rdz
Resource Description Framework application/rdf+xml *.rdf
RetroPlatform Player application/vnd.cloanto.rp9 *.rp9
RhymBox application/vnd.jisp *.jisp
Rich Text Format application/rtf *.rtf
Rich Text Format (RTF) text/richtext *.rtx
ROUTE 66 Location Based Services application/vnd.route66.link66+xml *.link66
RSS - Really Simple Syndication application/rss+xml *.rss, *.xml
S Hexdump Format application/shf+xml *.shf
SailingTracker application/vnd.sailingtracker.track *.st
Scalable Vector Graphics (SVG) image/svg+xml *.svg
ScheduleUs application/vnd.sus-calendar *.sus
Search/Retrieve via URL Response Format application/sru+xml *.sru
Secure Electronic Transaction - Payment application/set-payment-initiation *.setpay
Secure Electronic Transaction - Registration application/set-registration-initiation *.setreg
Secured eMail application/vnd.sema *.sema
Secured eMail application/vnd.semd *.semd
Secured eMail application/vnd.semf *.semf
SeeMail application/vnd.seemail *.see
Server Normal Format application/x-font-snf *.snf
Server-Based Certificate Validation Protocol - Validation Policies - Request application/scvp-vp-request *.spq
Server-Based Certificate Validation Protocol - Validation Policies - Response application/scvp-vp-response *.spp
Server-Based Certificate Validation Protocol - Validation Request application/scvp-cv-request *.scq
Server-Based Certificate Validation Protocol - Validation Response application/scvp-cv-response *.scs
Session Description Protocol application/sdp *.sdp
Setext text/x-setext *.etx
SGI Movie video/x-sgi-movie *.movie
Shana Informed Filler application/vnd.shana.informed.formdata *.ifm
Shana Informed Filler application/vnd.shana.informed.formtemplate *.itp
Shana Informed Filler application/vnd.shana.informed.interchange *.iif
Shana Informed Filler application/vnd.shana.informed.package *.ipk
Sharing Transaction Fraud Data application/thraud+xml *.tfi
Shell Archive application/x-shar *.shar
Silicon Graphics RGB Bitmap image/x-rgb *.rgb
SimpleAnimeLite Player application/vnd.epson.salt *.slt
Simply Accounting application/vnd.accpac.simply.aso *.aso
Simply Accounting - Data Import application/vnd.accpac.simply.imp *.imp
SimTech MindMapper application/vnd.simtech-mindmapper *.twd
Sixth Floor Media - CommonSpace application/vnd.commonspace *.csp
SMAF Audio application/vnd.yamaha.smaf-audio *.saf
SMAF File application/vnd.smaf *.mmf
SMAF Phrase application/vnd.yamaha.smaf-phrase *.spf
SMART Technologies Apps application/vnd.smart.teacher *.teacher
SourceView Document application/vnd.svd *.svd
SPARQL - Query application/sparql-query *.rq
SPARQL - Results application/sparql-results+xml *.srx
Speech Recognition Grammar Specification application/srgs *.gram
Speech Recognition Grammar Specification - XML application/srgs+xml *.grxml
Speech Synthesis Markup Language application/ssml+xml *.ssml
SSEYO Koan Play File application/vnd.koan *.skp
Standard Generalized Markup Language (SGML) text/sgml *.sgml
StarOffice - Calc application/vnd.stardivision.calc *.sdc
StarOffice - Draw application/vnd.stardivision.draw *.sda
StarOffice - Impress application/vnd.stardivision.impress *.sdd
StarOffice - Math application/vnd.stardivision.math *.smf
StarOffice - Writer application/vnd.stardivision.writer *.sdw
StarOffice - Writer (Global) application/vnd.stardivision.writer-global *.sgl
StepMania application/vnd.stepmania.stepchart *.sm
Stuffit Archive application/x-stuffit *.sit
Stuffit Archive application/x-stuffitx *.sitx
SudokuMagic application/vnd.solent.sdkm+xml *.sdkm
Sugar Linux Application Bundle application/vnd.olpc-sugar *.xo
Sun Audio - Au file format audio/basic *.au
SundaHus WQ application/vnd.wqd *.wqd
Symbian Install Package application/vnd.symbian.install *.sis
Synchronized Multimedia Integration Language application/smil+xml *.smi
SyncML application/vnd.syncml+xml *.xsm
SyncML - Device Management application/vnd.syncml.dm+wbxml *.bdm
SyncML - Device Management application/vnd.syncml.dm+xml *.xdm
System V Release 4 CPIO Archive application/x-sv4cpio *.sv4cpio
System V Release 4 CPIO Checksum Data application/x-sv4crc *.sv4crc
Systems Biology Markup Language application/sbml+xml *.sbml
Tab Seperated Values text/tab-separated-values *.tsv
Tagged Image File Format image/tiff *.tiff
Tao Intent application/vnd.tao.intent-module-archive *.tao
Tar File (Tape Archive) application/x-tar *.tar
Tcl Script application/x-tcl *.tcl
TeX application/x-tex *.tex
TeX Font Metric application/x-tex-tfm *.tfm
Text Encoding and Interchange application/tei+xml *.tei
Text File text/plain *.txt
TIBCO Spotfire application/vnd.spotfire.dxp *.dxp
TIBCO Spotfire application/vnd.spotfire.sfs *.sfs
Time Stamped Data Envelope application/timestamped-data *.tsd
TRI Systems Config application/vnd.trid.tpt *.tpt
Triscape Map Explorer application/vnd.triscape.mxs *.mxs
troff text/troff *.t
True BASIC application/vnd.trueapp *.tra
TrueType Font application/x-font-ttf *.ttf
Turtle (Terse RDF Triple Language) text/turtle *.ttl
UMAJIN application/vnd.umajin *.umj
Unique Object Markup Language application/vnd.uoml+xml *.uoml
Unity 3d application/vnd.unity *.unityweb
Universal Forms Description Language application/vnd.ufdl *.ufd
URI Resolution Services text/uri-list *.uri
User Interface Quartz - Theme (Symbian) application/vnd.uiq.theme *.utz
Ustar (Uniform Standard Tape Archive) application/x-ustar *.ustar
UUEncode text/x-uuencode *.uu
vCalendar text/x-vcalendar *.vcs
vCard text/x-vcard *.vcf
Video CD application/x-cdlink *.vcd
Viewport+ application/vnd.vsf *.vsf
Virtual Reality Modeling Language model/vrml *.wrl
VirtualCatalog application/vnd.vcx *.vcx
Virtue MTS model/vnd.mts *.mts
Virtue VTU model/vnd.vtu *.vtu
Visionary application/vnd.visionary *.vis
Vivo video/vnd.vivo *.viv
Voice Browser Call Control application/ccxml+xml, *.ccxml
VoiceXML application/voicexml+xml *.vxml
WAIS Source application/x-wais-source *.src
WAP Binary XML (WBXML) application/vnd.wap.wbxml *.wbxml
WAP Bitamp (WBMP) image/vnd.wap.wbmp *.wbmp
Waveform Audio File Format (WAV) audio/x-wav *.wav
Web Distributed Authoring and Versioning application/davmount+xml *.davmount
Web Open Font Format application/x-font-woff *.woff
Web Services Policy application/wspolicy+xml *.wspolicy
WebP Image image/webp *.webp
WebTurbo application/vnd.webturbo *.wtb
Widget Packaging and XML Configuration application/widget *.wgt
WinHelp application/winhlp *.hlp
Wireless Markup Language (WML) text/vnd.wap.wml *.wml
Wireless Markup Language Script (WMLScript) text/vnd.wap.wmlscript *.wmls
WMLScript application/vnd.wap.wmlscriptc *.wmlsc
Wordperfect application/vnd.wordperfect *.wpd
Worldtalk application/vnd.wt.stf *.stf
WSDL - Web Services Description Language application/wsdl+xml *.wsdl
X BitMap image/x-xbitmap *.xbm
X PixMap image/x-xpixmap *.xpm
X Window Dump image/x-xwindowdump *.xwd
X.509 Certificate application/x-x509-ca-cert *.der
Xfig application/x-xfig *.fig
XHTML - The Extensible HyperText Markup Language application/xhtml+xml *.xhtml
XML - Extensible Markup Language application/xml *.xml
XML Configuration Access Protocol - XCAP Diff application/xcap-diff+xml *.xdf
XML Encryption Syntax and Processing application/xenc+xml *.xenc
XML Patch Framework application/patch-ops-error+xml *.xer
XML Resource Lists application/resource-lists+xml *.rl
XML Resource Lists application/rls-services+xml *.rs
XML Resource Lists Diff application/resource-lists-diff+xml *.rld
XML Transformations application/xslt+xml *.xslt
XML-Binary Optimized Packaging application/xop+xml *.xop
XPInstall - Mozilla application/x-xpinstall *.xpi
XSPF - XML Shareable Playlist Format application/xspf+xml *.xspf
XUL - XML User Interface Language application/vnd.mozilla.xul+xml *.xul
XYZ File Format chemical/x-xyz *.xyz
YANG Data Modeling Language application/yang *.yang
YIN (YANG - XML) application/yin+xml *.yin
Z.U.L. Geometry application/vnd.zul *.zir
Zip Archive application/zip *.zip
ZVUE Media Manager application/vnd.handheld-entertainment+xml *.zmm
Zzazz Deck application/vnd.zzazz.deck+xml *.zaz
作者:Faremax 发表于2017/8/19 16:54:29 原文链接
阅读:0 评论:0 查看评论

剑指offer——27.字符串排列

$
0
0

题目描述

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

代码

思路:使用递归方法,n个元素的全排列 = (n-1) 个元素全排列 + 一个元素作为前缀。

function Permutation(str)
{
    // write code here
    var result=[];
    if(str.length<=0){
        return [];
    }
    var sortTemp='';
    var arr = str.split('');
    result=sortString(arr,sortTemp,[]);
    return result

}
function sortString(arr,sortTemp,result){
    if(arr.length==0){
        result.push(sortTemp)
    }else{
        var isRepeat={};
        for(var i=0;i<arr.length;i++){
            if(!isRepeat[arr[i]]){
                var temp=arr.splice(i,1)[0];//取出第一个字符
                sortTemp+=temp;
                sortString(arr,sortTemp,result);
                arr.splice(i,0,temp);//补全
                sortTemp=sortTemp.slice(0,sortTemp.length-1)//清空
                isRepeat[temp]=true;
            }
        }
    }
    return result;
}
作者:owen1190 发表于2017/8/19 16:55:22 原文链接
阅读:0 评论:0 查看评论

剑指offer——28.数组中出现次数超过一半

$
0
0

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

代码

思路:可以使用map数据结构,但因为牛客系统不识别es6,所以就使用对象来存储每个元素出现次数。

function MoreThanHalfNum_Solution(numbers)
{
    // write code here   
    var obj={};
    var len = numbers.length;
    numbers.map(function(num){
        if(obj[num]){
            obj[num]++
        }else{
            obj[num]=1;
        }
    })
    for (var i in obj){
        if(obj[i]>Math.floor(len/2)) return i
    }
    return 0;
}
作者:owen1190 发表于2017/8/19 16:56:55 原文链接
阅读:0 评论:0 查看评论

Spring Boot (教程十四:发送邮件)

$
0
0

GitHub 地址:

https://github.com/asd821300801/Spring-Boot.git


      相信活跃在互联网的大神都知道,现在大部分网站在注册的时候都要求用户填写邮箱进行注册验证,所以说发送邮件应该是网站必备的功能之一。在没有框架之前,我们是通过Java自带的JavaMail类来发送邮件的,后来spring推出了JavaMailSender类大大简化了发送邮件的过程,再到现在的Spring Boot又对其进行封装从而出现了 spring-boot-starter-mail。



前期准备


本章使用的是QQ的邮件服务,所以在这之前需要麻烦读者先去开通腾讯的SMTP功能

1


2



开通SMTP功能

3



QQ邮箱的授权码将作为邮箱密码使用。

4


如果不会开通,请参考博文:http://blog.csdn.net/caimengyuan/article/details/51224269




pom文件中加入发送邮件相关依赖


<!-- 邮件服务 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

properties文件中添加邮箱配置


  • application.properties
#####qq邮箱#####
#QQ邮件服务地址
spring.mail.host=smtp.qq.com
#用户名
spring.mail.username=xxxx@qq.com  
#密码(授权码)
spring.mail.password=iwfxjjhkziugechb 
#默认编码UTF-8
spring.mail.default-encoding=UTF-8
#端口,这里添加587即可
spring.mail.port=587
#邮件发送人
mail.fromMail.addr=xxxx@qq.com


配置信息这里使用587端口,刚开始用465端口我纠结了好久(使用465端口的错误详情),用不了,你可以尝试,默认的25端口应该也是不适合的



创建EmailService接口


  • EmailService.java

包所在:com.example.email


package com.example.email;

/**
 * 发送邮件服务
 * @author LingDu
 * 2017.8.18
 */
public interface EmailService {
    /**
     * 发送简单邮件
     * @param to
     * @param subject
     * @param content
     */
    public void sendSimpleEmail(String to, String subject, String content);
    /**
     * 发送html格式邮件
     * @param to
     * @param subject
     * @param content
     */
    public void sendHtmlEmail(String to, String subject, String content);
    /**
     * 发送带附件的邮件
     * @param to
     * @param subject
     * @param content
     * @param filePath
     */
    public void sendAttachmentsEmail(String to, String subject, String content, String filePath);
    /**
     * 发送带静态资源的邮件
     * @param to
     * @param subject
     * @param content
     * @param rscPath
     * @param rscId
     */
    public void sendInlineResourceEmail(String to, String subject, String content, String rscPath, String rscId);
}


创建EmailServiceImp实现类


  • EmailServiceImp.java

包所在:com.example.email


package com.example.email;

import java.io.File;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;

@Component
public class EmailServiceImp implements EmailService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private JavaMailSender mailSender;//spring 提供的邮件发送类

    @Value("${mail.fromMail.addr}")
    private String from;

    @Override
    public void sendSimpleEmail(String to, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();//创建简单邮件消息
        message.setFrom(from);//设置发送人
        message.setTo(to);//设置收件人

        /* String[] adds = {"xxx@qq.com","yyy@qq.com"}; //同时发送给多人
        message.setTo(adds);*/

        message.setSubject(subject);//设置主题
        message.setText(content);//设置内容
        try {
            mailSender.send(message);//执行发送邮件
            logger.info("简单邮件已经发送。");
        } catch (Exception e) {
            logger.error("发送简单邮件时发生异常!", e);
        }
    }

    @Override
    public void sendHtmlEmail(String to, String subject, String content) {
        MimeMessage message = mailSender.createMimeMessage();//创建一个MINE消息

        try {
            //true表示需要创建一个multipart message
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);

            mailSender.send(message);
            logger.info("html邮件发送成功");
        } catch (MessagingException e) {
            logger.error("发送html邮件时发生异常!", e);
        }

    }

    @Override
    public void sendAttachmentsEmail(String to, String subject, String content, String filePath) {
        MimeMessage message = mailSender.createMimeMessage();//创建一个MINE消息

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);// true表示这个邮件是有附件的

            FileSystemResource file = new FileSystemResource(new File(filePath));//创建文件系统资源
            String fileName = filePath.substring(filePath.lastIndexOf(File.separator));
            helper.addAttachment(fileName, file);//添加附件

            mailSender.send(message);
            logger.info("带附件的邮件已经发送。");
        } catch (MessagingException e) {
            logger.error("发送带附件的邮件时发生异常!", e);
        }

    }

    @Override
    public void sendInlineResourceEmail(String to, String subject, String content, String rscPath, String rscId) {
        MimeMessage message = mailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setFrom(from);
            helper.setTo(to);
            helper.setSubject(subject);
            helper.setText(content, true);

            FileSystemResource res = new FileSystemResource(new File(rscPath));

            //添加内联资源,一个id对应一个资源,最终通过id来找到该资源
            helper.addInline(rscId, res);//添加多个图片可以使用多条 <img src='cid:" + rscId + "' > 和 helper.addInline(rscId, res) 来实现

            mailSender.send(message);
            logger.info("嵌入静态资源的邮件已经发送。");
        } catch (MessagingException e) {
            logger.error("发送嵌入静态资源的邮件时发生异常!", e);
        }

    }

}


编写测试类


  • 需要将邮件服务注入进来
@Autowired
private EmailService emailService;


发送简单邮件


@Test
public void sendSimpleMail() throws Exception {
    emailService.sendSimpleEmail("821300801@qq.com","this is simple mail"," hello LingDu");
}

5



发送带html的邮件


    @Test
    public void sendHtmlMail() throws Exception {
        String content="<html>\n" +
                "<body>\n" +
                "    <h3>hello world ! 这是一封Html邮件!</h3>\n" +
                "</body>\n" +
                "</html>";
        emailService.sendHtmlEmail("821300801@qq.com","this is html mail",content);
    }

6



发送带附件的文件


@Test
public void sendAttachmentsMail() {
    String filePath="f:\\pikaqiu.png";
    emailService.sendAttachmentsEmail("821300801@qq.com", "主题:带附件的邮件", "收到附件,请查收!", filePath);

}

7



发送带静态资源的文件


@Test
public void sendInlineResourceMail() {
    String rscId = "001";
    String content="<html><body>这是有图片的邮件:<img src=\'cid:" + rscId + "\' ></body></html>";
    String imgPath = "f:\\pikaqiu.png";

    emailService.sendInlineResourceEmail("821300801@qq.com", "主题:这是有图片的邮件", content, imgPath, rscId);
}

8



知识扩充


发送模版邮件



有些时候我还还会收到固定格式的邮件,如:


尊敬的LingDu用户:

       恭喜您入住xxx平台VIP会员,您将享受xxx优惠福利,同时感谢您对xxx的关注与支持并欢迎您使用xx的产品与服务。
       ...

      这里假设用户名是经常变动的,如果每次发送邮件都需要手动拼接的话会不够优雅,并且每次模板的修改都需要改动代码的话也很不方便,因此对于这类邮件需求,都建议做成邮件模板来处理。模板的本质很简单,就是在模板中替换变化的参数,转换为html字符串即可,这里以thymeleaf为例来演示。



导入thymeleaf的包


<!-- 引入模板引擎. -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

注意:如果使用thymeleaf模版引擎,请将application.properties中的jsp配置去掉,否则会找不到页面

# 页面默认前缀目录
#spring.mvc.view.prefix=/WEB-INF/page/
# 响应页面默认后缀
#spring.mvc.view.suffix=.jsp


创建邮件模版


  • 在resorces/templates下创建email.html


<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8"/>
        <title>Title</title>
    </head>
    <body>
        <h4 th:text="|尊敬的:${username} 用户:|"></h4><br /><br />

       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;恭喜您入住xxx平台VIP会员,您将享受xxx优惠福利,同时感谢您对xxx的关注与支持并欢迎您使用xx的产品与服务。<br />
       &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...
    </body>
</html>


注入模版引擎


@Autowired
private TemplateEngine templateEngine;


解析模板并发送


    //发送模版消息
    @Test
    public void sendTemplateMail() {
        //创建邮件正文
        Context context = new Context();
        context.setVariable("username", "LingDu");
        String emailContent = templateEngine.process("email", context);

        System.out.println(emailContent);
        emailService.sendHtmlEmail("821300801@qq.com","主题:这是模板邮件",emailContent);
    }

注意:Context 类是在org.thymeleaf.context.Context包下的。



  • 这样就接收到固定格式的邮件了。

9



邮件服务注意事项


邮件发送失败


     因为各种原因,总会有邮件发送失败的情况,比如:邮件发送过于频繁、网络异常等。在出现这种情况的时候,我们一般会考虑重新重试发送邮件,会分为以下几个步骤来实现:


  • 1、接收到发送邮件请求,首先记录请求并且入库。

  • 2、调用邮件发送接口发送邮件,并且将发送结果记录入库。

  • 3、启动定时系统扫描时间段内,未发送成功并且重试次数小于3次的邮件,进行再次发送



异步发送


     很多时候邮件发送并不是我们主业务必须关注的结果,比如通知类、提醒类的业务可以允许延时或者失败。这个时候可以采用异步的方式来发送邮件,加快主交易执行速度,在实际项目中可以采用MQ发送邮件相关参数,监听到消息队列之后启动发送邮件。



工程结构图


10

作者:gfd54gd5f46 发表于2017/8/19 18:06:49 原文链接
阅读:179 评论:0 查看评论

【Java多线程与并发库】05 线程范围内共享变量ThreadLocal

$
0
0

【Java多线程与并发库】05 线程范围内共享变量ThreadLocal

ThreadLocal,是Thread Local Variable,线程局部变量。

ThreadLocal的作用和目的:
用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据。

它的功能非常简单,就是为每一个使用该变量的线程都提供一个变量的副本,是每一个线程都可以独立地改变自己的副本,而不会和其他的线程的副本冲突。

从线程的角度看,就好像每一个线程都完全拥有该变量一样。

TheadLocal类提供了3个public方法

T get():返回此线程局部变量中当前线程的值;

void remove():删除此线程局部变量中当前线程的值;

void set(T value):设置此线程局部变量中当前线程副本中的值。

每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值。

在此线程结束时可以调用ThreadLocal.clear方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量。

ThreadLocal的应用场景:
银行转账包含一些列操作:把转出账户的余额减少,把转入账户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据连接对象,转入和转出操作的代码分别是两个不同的账户对象的方法。

ThreadLocal 示例

import java.util.Random;

/**
 * description:
 *
 * @author liyazhou
 * @since 2017-08-14 21:03
 */
public class ThreadLocalTest {
    private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();

    public static void main(String... args){
        for (int i = 0; i < 2; i ++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    int data = new Random().nextInt();
                    System.out.println(Thread.currentThread().getName() + " put data, " + data);
                    x.set(data);
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }

    static class A{
        void get(){
            int data = x.get();  // ThreadLocal的成员方法get()
            System.out.println("A from " + Thread.currentThread().getName() + " get data : " + data);
        }
    }

    static class B{
        void get(){
            int data = x.get();  // ThreadLocal的成员方法get()
            System.out.println("B from " + Thread.currentThread().getName() + " get data : " + data);
        }
    }

}

执行结果是

Thread-1 put data, 503884994
Thread-0 put data, 1955108005
A from Thread-1 get data : 503884994
A from Thread-0 get data : 1955108005
B from Thread-0 get data : 1955108005
B from Thread-1 get data : 503884994

从结果可见,ThreadLocal变量可以实现数据在线程之间隔离。

ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题。
ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。

ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

通常我们认为:
如果多个线程之间需要共享资源,以达到线程之间的通信功能,就使用同步机制。
如果仅仅需要隔离多个线程之间的共享冲突,就可以使用ThreadLocal。

一句话概括ThreadLocal:
ThreadLocal变量会在每一个线程中都会产生一个独一无二的ThreadLocal对象,它们之间互不干扰。

引申:
一个ThreadLocal代表一个变量,故其中只能放一个数据,如果有两个变量都要线程范围内共享,则要顶一个两个ThreadLocal变量,如果有一百个变量要线程共享呢?那请先定义一个对象来装这一百个变量,然后在ThreadLocal中存储这一个对象。


参考:

《疯狂Java讲义》
深入研究java.util.ThreadLocal

作者:liyazhou0215 发表于2017/8/19 19:27:25 原文链接
阅读:157 评论:0 查看评论

HDU - 1176 免费馅饼(DP数塔)

$
0
0

点击打开题目链接

免费馅饼

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 52321    Accepted Submission(s): 18334


Problem Description
都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼。说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的10米范围内。馅饼如果掉在了地上当然就不能吃了,所以gameboy马上卸下身上的背包去接。但由于小径两侧都不能站人,所以他只能在小径上接。由于gameboy平时老呆在房间里玩游戏,虽然在游戏中是个身手敏捷的高手,但在现实中运动神经特别迟钝,每秒种只有在移动不超过一米的范围内接住坠落的馅饼。现在给这条小径如图标上坐标:

为了使问题简化,假设在接下来的一段时间里,馅饼都掉落在0-10这11个位置。开始时gameboy站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的馅饼。问gameboy最多可能接到多少个馅饼?(假设他的背包可以容纳无穷多个馅饼)
 

Input
输入数据有多组。每组数据的第一行为以正整数n(0<n<100000),表示有n个馅饼掉在这条小径上。在结下来的n行中,每行有两个整数x,T(0<T<100000),表示在第T秒有一个馅饼掉在x点上。同一秒钟在同一点上可能掉下多个馅饼。n=0时输入结束。
 

Output
每一组输入数据对应一行输出。输出一个整数m,表示gameboy最多可能接到m个馅饼。
提示:本题的输入数据量比较大,建议用scanf读入,用cin可能会超时。

 

Sample Input
6 5 1 4 1 6 1 7 2 7 2 8 3 0
 

Sample Output
4
 

Author
lwg
 

Recommend
We have carefully selected several similar problems for you:  1159 1058 1203 1257 1421 
 

Statistic | Submit | Discuss | Note

思路:

数塔问题。

按照时间顺序分行,构成数塔。从结束时间往上扫,找最终最大值。

状态方程:dp[i][j] += max(dp[i + 1][j], max(dp[i + 1][j + 1], dp[i + 1][j - 1]));

附上AC代码:

#include<bits/stdc++.h>

using namespace std;
const int maxn = 100000 + 5;
int dp[maxn][15];
int n, x, t, _max;

int main() {
    ios :: sync_with_stdio(false);
    while(cin >> n, n) {
        _max = 0;
        memset(dp, 0, sizeof(dp) );
        for(int i = 0; i < n; i++) {
            cin >> x >> t;
            dp[t][x + 1] ++;
            _max = max(_max, t);
        }
        for(int i = _max; i >= 0; i--) {
            for(int j =1; j <=11; j++) {
                dp[i][j] += max(dp[i + 1][j], max(dp[i + 1][j + 1], dp[i + 1][j - 1]));
            }
        }
        cout << dp[0][6] << endl;
    }
    return 0;
}
作者:l1832876815 发表于2017/8/19 20:27:50 原文链接
阅读:143 评论:0 查看评论

Java8容器源码-HashMap

$
0
0

前面已经学习了List的实现类并做了总结,今天开始学习HashMap源码。参考的JDK版本为1.8。

相信大家对HashMap的使用已经很熟悉了,它和List的最大的不同是它是以key-value的形式存储数据的。HashMap是如何保存和处理key-value键值对的?本文将分析HashMap的内部结构及实现原理,帮助大家更好的使用它。

HashMap数据结构

在分析HashMap源码之前,有必要了解HashMap的数据结构,否则很难理解下面的内容。

MarkdownPhotos/master/CSDNBlogs/container/HashMap/HashMapDateStructure.jpg

从上图中可以很清楚的看到,HashMap的数据结构是数组+链表+红黑树(红黑树since JDK1.8)。常把数组中的每一个节点称为一个。当向桶中添加一个key-value时,首先计算元素key的hash值,以此确定插入数组中的位置,但是可能存在同一hash值的元素已经被放在数组同一位置了,这种现象称为碰撞,这时按照尾插法(jdk1.7及以前为头插法)的方式添加key-value到同一hash值的元素的后面,形成了链表。当链表长度超过8(TREEIFY_THRESHOLD)时,链表就转换为红黑树。

部分顶部注释

Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap class is roughly equivalent to HashMap , except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.

HashMap是Map接口基于哈希表的实现。这种实现提供了所有可选的Map操作,允许key和value为null。HashMap大致和HashTable相同,除了HashMap是unsynchronized的,而且它允许key和value为null。

This implementation provides constant-time performance for the basic operations (get and put), assuming the hash function disperses the elements properly among the buckets. Iteration over collection views requires time proportional to the “capacity” of the HashMap instance (the number of buckets) plus its size (the number of key-value mappings). Thus, it’s very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important.

这个实现为基本实现(get and put)提供了稳定的性能,假设哈希函数在桶内正确分散元素。如果遍历操作很重要,就不要把capacity设置得太高(或load factor设置得太低),否则会严重降低遍历的效率。

An instance of HashMap has two parameters that affect its performance: initial capacity and load factor. The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets.

HashMap有两个影响性能的重要参数:初始化容量initial capacity、负载因子load factor。initial capacity*load factor就是当前允许的最大元素数目,超过initial capacity*load factor之后,HashMap就会进行rehashed操作来进行扩容,扩容后的的容量为之前的两倍。

下面还有很长,不翻了。

HashMap层次结构图

先来看看ArrayList的定义:

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable

从中我们可以了解到:

  • HashMap<K,V>:HashMap是以key-value形式存储数据的
  • extends AbstractMap<K,V>:继承了AbstractMap,实现Map接口时需要实现的工作量大大减少了。
  • implements Map<K,V>:实现了Map,实现了Map中声明的操作和default方法。
  • implements Cloneable:表明其可以调用clone()方法来返回实例的field-for-field拷贝。
  • implements Serializable:表明该类是可以序列化的。

建议大家以后查看一个类的继承实现关系的时候,使用类结构层次图。

MarkdownPhotos/master/CSDNBlogs/container/HashMap/HashMapTH.jpg

如何查看类层次结构图可以参考我写过的一篇文章:

eclipse-查看继承层次图/继承实现层次图

静态全局变量

/**
 * 默认初始化容量,值为16
 * 必须是2的n次幂.
 */
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

/**
 * 最大容量, 如果一个更大的值在构造函数总被指定,将被MAXIMUM_CAPACITY 替换.
 * 必须是2的倍数。最大容量为1<<30,即2的30次方。
 */
static final int MAXIMUM_CAPACITY = 1 << 30;

/**
 * 默认的负载因子。
 */
static final float DEFAULT_LOAD_FACTOR = 0.75f;

/**
 * 使用树形结构而不是链式结构临界值。
 * 当添加一个元素被添加到有至少TREEIFY_THRESHOLD个节点的桶中,桶将被转化为树形结构。
 * 临界值最小为8
 */
static final int TREEIFY_THRESHOLD = 8;

/**
 * 恢复成链式结构的桶大小临界值
 * 小于TREEIFY_THRESHOLD,临界值最大为6
 */
static final int UNTREEIFY_THRESHOLD = 6;

/**
 * 桶可能被转化为树形结构的最小容量。当哈希表的大小超过这个阈值,才会把链式结构转化成树型结构,否则仅采取扩容来尝试减少冲突。
 * 应该至少4*TREEIFY_THRESHOLD来避免扩容和树形结构化之间的冲突。
 */
static final int MIN_TREEIFY_CAPACITY = 64;

静态内部类Node

/**
 * HashMap的节点类型。既是HashMap底层数组的组成元素,又是每个单向链表的组成元素
 */
static class Node<K,V> implements Map.Entry<K,V> {
    //key的哈希值
    final int hash;
    final K key;
    V value;
    //指向下个节点的引用
    Node<K,V> next;
    //构造函数
    Node(int hash, K key, V value, Node<K,V> next) {
        this.hash = hash;
        this.key = key;
        this.value = value;
        this.next = next;
    }

    public final K getKey()        { return key; }
    public final V getValue()      { return value; }
    public final String toString() { return key + "=" + value; }

    public final int hashCode() {
        return Objects.hashCode(key) ^ Objects.hashCode(value);
    }

    public final V setValue(V newValue) {
        V oldValue = value;
        value = newValue;
        return oldValue;
    }

    public final boolean equals(Object o) {
        if (o == this)
            return true;
        if (o instanceof Map.Entry) {
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
            if (Objects.equals(key, e.getKey()) &&
                Objects.equals(value, e.getValue()))
                return true;
        }
        return false;
    }
}

静态公用方法

hash( Object key)

不管增加、删除、查找键值对,定位到哈希桶数组的位置都是很关键的第一步。计算位置的方法如下

(n - 1) & hash

其中的n为数组的长度,hash为hash(key)计算得到的值。

/**
 * 计算key的哈希值。
 */
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

从代码中可以看到,计算位置分为三步,第一步,取key的hashCode,第二步,key的hashCode高16位异或低16位,第三步,取模运算。

MarkdownPhotos/master/CSDNBlogs/container/HashMap/hashFunc.jpg

看到这里有个疑问,为什么要做异或运算?

设想一下,如果n很小,假设为16的话,那么n-1即为15(0000 0000 0000 0000 0000 0000 0000 1111),这样的值如果跟hashCode()直接做与操作,实际上只使用了哈希值的后4位。如果当哈希值的高位变化很大,低位变化很小,这样很容易造成碰撞,所以把高低位都参与到计算中,从而解决了这个问题,而且也不会有太大的开销。

comparableClassFor( Object x)

/**
 * 如果参数x实现了Comparable接口,返回参数x的类名,否则返回null
 */
static Class<?> comparableClassFor(Object x) {
    if (x instanceof Comparable) {
        Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
        if ((c = x.getClass()) == String.class) // bypass checks
            return c;
        if ((ts = c.getGenericInterfaces()) != null) {
            for (int i = 0; i < ts.length; ++i) {
                if (((t = ts[i]) instanceof ParameterizedType) &&
                    ((p = (ParameterizedType)t).getRawType() ==
                     Comparable.class) &&
                    (as = p.getActualTypeArguments()) != null &&
                    as.length == 1 && as[0] == c) // type arg is c
                    return c;
            }
        }
    }
    return null;
}

compareComparables( Class<?> kc, Object k, Object x)

/**
 * 如果x的类型为kc,则返回k.compareTo(x),否则返回0.
 */
@SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
static int compareComparables(Class<?> kc, Object k, Object x) {
    return (x == null || x.getClass() != kc ? 0 :
            ((Comparable)k).compareTo(x));
}

tableSizeFor( int cap)

/**
 * 返回大于等于cap的最小的二次幂数值。
 */
static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

/**
 * 存储键值对的数组,一般是2的幂
 */
transient Node<K,V>[] table;

/**
 * 键值对缓存,它们的映射关系集合保存在entrySet中。即使Key在外部修改导致hashCode变化,缓存中还可以找到映射关系
 */
transient Set<Map.Entry<K,V>> entrySet;

/**
 * 键值对的实际个数
 */
transient int size;

/**
 * 记录HashMap被修改结构的次数。
 * 修改包括改变键值对的个数或者修改内部结构,比如rehash
 * 这个域被用作HashMap的迭代器的fail-fast机制中(参考ConcurrentModificationException)
 */
transient int modCount;

/**
 * 扩容的临界值,通过capacity * load factor可以计算出来。超过这个值HashMap将进行扩容
 * @serial
 */

int threshold;

/**
 * 负载因子
 *
 * @serial
 */
final float loadFactor;

构造函数

HashMap( int initialCapacity, float loadFactor)

/**
 * 使用指定的初始化容量initial capacity 和负载因子load factor构造一个空HashMap
 *
 * @param  initialCapacity 初始化容量
 * @param  loadFactor      负载因子
 * @throws IllegalArgumentException 如果指定的初始化容量为负数或者加载因子为非正数。
 */
public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
}

HashMap( int initialCapacity)

/**
 * 使用指定的初始化容量initial capacity和默认负载因子DEFAULT_LOAD_FACTOR(0.75)构造一个空HashMap
 *
 * @param  initialCapacity 初始化容量
 * @throws IllegalArgumentException 如果指定的初始化容量为负数
 */
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

HashMap()

/**
 * 使用指定的初始化容量(16)和默认负载因子DEFAULT_LOAD_FACTOR(0.75)构造一个空HashMap
 */
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

HashMap( Map<? extends K, ? extends V>m)

/**
 * 使用指定Map m构造新的HashMap。使用指定的初始化容量(16)和默认负载因子DEFAULT_LOAD_FACTOR(0.75)
 * @param   m 指定的map
 * @throws  NullPointerException 如果指定的map是null
 */
public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}

常用方法

putMapEntries(Map<? extends K, ? extends V> m, boolean evict)

/**
 * Map.putAll and Map constructor的实现需要的方法。
 * 将m的键值对插入本map中
 * 
 * @param m the map
 * @param evict 初始化map时使用false,否则使用true
 */
final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
    int s = m.size();
    //如果参数map不为空
    if (s > 0) {
        //如果table没有初始化
        if (table == null) { // pre-size
            //前面讲到,initial capacity*load factor就是当前hashMap允许的最大元素数目。那么不难理解,s/loadFactor+1即为应该初始化的容量。
            float ft = ((float)s / loadFactor) + 1.0F;
            //如果ft小于最大容量MAXIMUM_CAPACITY,则容量为ft,否则容量为最大容量MAXIMUM_CAPACITY
            int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                     (int)ft : MAXIMUM_CAPACITY);
            //如果容量大于临界值
            if (t > threshold)
                //根据容量初始化临界值
                threshold = tableSizeFor(t);
        }
        //table已经初始化,并且map的大小大于临界值
        else if (s > threshold)
            //扩容处理
            resize();
        //将map中所有键值对添加到hashMap中
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
            K key = e.getKey();
            V value = e.getValue();
            //putVal方法的实现在下面
            putVal(hash(key), key, value, false, evict);
        }
    }
}

size()

/**
 * 返回map中键值对映射的个数
 * 
 * @return map中键值对映射的个数
 */
public int size() {
    return size;
}

isEmpty()

/**
 * 如果map中没有键值对映射,返回true
 * 
 * @return <如果map中没有键值对映射,返回true
 */
public boolean isEmpty() {
    return size == 0;
}

get( Object key)

/**
 * 返回指定的key对应的value,如果value为null,则返回null
 *
 * @see #put(Object, Object)
 */
public V get(Object key) {
    Node<K,V> e;
    //如果通过key获取到的node为null,则返回null,否则返回node的value。getNode方法的实现就在下面。
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}

getNode( int hash, Object key)

/**
 * 根据key的哈希值和key获取对应的节点
 * 
 * @param hash 指定参数key的哈希值
 * @param key 指定参数key
 * @return 返回node,如果没有则返回null
 */
final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    //如果哈希表不为空,而且key对应的桶上不为空
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        //如果桶中的第一个节点得哈希值就和指定参数hash匹配上了
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            //返回桶中的第一个节点
            return first;
        //如果桶中的第一个节点没有匹配上,而且有后续节点
        if ((e = first.next) != null) {
            //如果当前的桶采用红黑树,则调用红黑树的get方法去获取节点
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            //如果当前的桶不采用红黑树,即桶中为链式结构
            do {
                //遍历链表,直到key匹配,或者到链表末尾
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    //如果哈希表为空,返回null
    return null;
}

containsKey( Object key)

/**
 * 如果map中含有key为指定参数key的键值对,返回true
 * 
 * @param   key   指定参数key
 * @return 如果map中含有key为指定参数key的键值对,返回true
 */
public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}

put( K key, V value)

/**
 * 将指定参数key和指定参数value插入map中,如果key已经存在,那就替换key对应的value
 * 
 * @param key 指定key
 * @param value 指定value
 * @return 如果value被替换,则返回旧的value,否则返回null。当然,可能key对应的value就是null。
 */
public V put(K key, V value) {
    //putVal方法的实现就在下面
    return putVal(hash(key), key, value, false, true);
}

putVal( int hash, K key, V value, boolean onlyIfAbsent,boolean evict)

/**
 * Map.put和其他相关方法的实现需要的方法
 * 
 * @param hash 指定参数key的哈希值
 * @param key 指定参数key
 * @param value 指定参数value
 * @param onlyIfAbsent 如果为true,即使指定参数key在map中已经存在,也不会替换value
 * @param evict 如果为false,数组table在创建模式中
 * @return 如果value被替换,则返回旧的value,否则返回null。当然,可能key对应的value就是null。
 */
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    //如果哈希表为空
    if ((tab = table) == null || (n = tab.length) == 0)
        //调用resize()创建一个哈希表,并将哈希表长度赋给n
        n = (tab = resize()).length;
    //如果指定参数hash在表中没有对应位置,即为没有碰撞
    if ((p = tab[i = (n - 1) & hash]) == null)
        //直接将键值对插入到map中即可
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        //如果碰撞了
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            //将桶保存起来
            e = p;
        //如果桶内为红黑树结构,则调用红黑树对应的方法插入键值对
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        //不是红黑树结构,就是链式结构
        else {
            //遍历链式结构
            for (int binCount = 0; ; ++binCount) {
                //如果到了链尾都没有找到对应的key
                if ((e = p.next) == null) {
                    //插入键值对到链尾
                    p.next = newNode(hash, key, value, null);
                    //如果链的长度大于TREEIFY_THRESHOLD这个临界值,则把链变为红黑树
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    //跳出循环
                    break;
                }
                //如果找到了重复的key,判断链表中结点的key值与插入的元素的key值是否相等
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    //如果完全相等,跳出循环
                    break;
                //用于遍历桶中的链表,与前面的e = p.next组合,可以遍历链表
                p = e;
            }
        }
        //如果找到的节点为null
        if (e != null) { // existing mapping for key
            //保存节点的vlaue
            V oldValue = e.value;
            //如果onlyIfAbsent为false,或者oldValue为null
            if (!onlyIfAbsent || oldValue == null)
                //替换value
                e.value = value;
            //访问后回调
            afterNodeAccess(e);
            //返回节点的旧值
            return oldValue;
        }
    }
    //结构型修改次数+1
    ++modCount;
    //判断是否需要扩容
    if (++size > threshold)
        resize();
    //插入后回调
    afterNodeInsertion(evict);
    return null;
}

扩容resize()

向hashMap对象里不停的添加元素,而HashMap对象内部的数组无法装载更多的元素时,hashMap就需要扩大数组的长度,以便能装入更多的元素。当然数组是无法自动扩容的,扩容方法使用一个新的数组代替已有的容量小的数组。

/**
 * 对hashMap的数组table进行初始化或者扩容。
 * 如果table为null,则对table进行初始化,否则,因为我们正在使用2的幂的扩容,桶中的元素必须待在原本的位置,或者移动2的幂的位置。
 * @return 返回数组table
 */
final Node<K,V>[] resize() {
    //新建oldTab数组保存扩容前的数组table
    Node<K,V>[] oldTab = table;
    //定义oldCap保存扩容前table的容量
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    //保存扩容前的临界值
    int oldThr = threshold;
    int newCap, newThr = 0;
    //如果扩容前的table不为空
    if (oldCap > 0) {
        //如果当前容量>=最大容量
        if (oldCap >= MAXIMUM_CAPACITY) {
            //扩容临界值提高到正无穷
            threshold = Integer.MAX_VALUE;
            //无法进行扩容,返回原来的数组
            return oldTab;
        }//如果(oldCap*2<MAXIMUM_CAPACITY)&&oldCap>=DEFAULT_INITIAL_CAPACITY)
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)
            //容量增加一倍
            newThr = oldThr << 1; // double threshold
    }//如果以上两个条件都不成立,而且oldThr>0
    else if (oldThr > 0) // initial capacity was placed in threshold
        //数组的初始容量设置为老数组扩容的临界值
        newCap = oldThr;
    else {//新容量为默认初始化容量,新临界值为DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    if (newThr == 0) {//在当上面的条件判断中,只有oldThr > 0成立时,newThr == 0
        //ft为临时临界值,下面会确定这个临界值是否合法,如果合法,那就是真正的临界值
        float ft = (float)newCap * loadFactor;
        //当newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY,新的临界值为ft,否则为Integer.MAX_VALUE
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    //将hashMap的临界值设置为newThr
    threshold = newThr;
    //创建新的table,初始化容量为newCap
    @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    //
    table = newTab;
    if (oldTab != null) {
        //遍历旧哈希表的每个桶,将旧哈希表中的桶迁移到新的哈希表中
        for (int j = 0; j < oldCap; ++j) {
            Node<K,V> e;
            //如果旧桶不为null
            if ((e = oldTab[j]) != null) {
                //将旧桶置为null
                oldTab[j] = null;
                //如果旧桶中只有一个node
                if (e.next == null)
                    //将e也就是oldTab[j]放入newTab中e.hash & (newCap - 1)的位置
                    newTab[e.hash & (newCap - 1)] = e;
                //如果旧桶中的结构为红黑树
                else if (e instanceof TreeNode)
                    //将树中的node分离
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                else { //如果旧桶中的结构为链表。这段没有仔细研究
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    do {
                        next = e.next;
                        if ((e.hash & oldCap) == 0) {
                            if (loTail == null)
                                loHead = e;
                            else
                                loTail.next = e;
                            loTail = e;
                        }
                        else {
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    if (loTail != null) {
                        loTail.next = null;
                        newTab[j] = loHead;
                    }
                    if (hiTail != null) {
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    return newTab;
}

从代码中可以看到,扩容很耗性能。所以在使用HashMap的时候,先估算map的大小,初始化的时候给一个大致的数值,避免map进行频繁的扩容。

treeifyBin( Node<K,V>[] tab, int hash)

/**
 * 将链表转化为红黑树
 */
final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    //如果桶数组table为空,或者桶数组table的长度小于MIN_TREEIFY_CAPACITY,不符合转化为红黑树的条件
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
        //扩容
        resize();
    else if ((e = tab[index = (n - 1) & hash]) != null) {//如果符合转化为红黑树的条件,而且hash对应的桶不为null
        TreeNode<K,V> hd = null, tl = null;
        //遍历链表
        do {
            //替换链表node为树node,建立双向链表
            TreeNode<K,V> p = replacementTreeNode(e, null);
            //
            if (tl == null)
                hd = p;
            else {
                p.prev = tl;
                tl.next = p;
            }
            tl = p;
        } while ((e = e.next) != null);
        //遍历链表插入每个节点到红黑树
        if ((tab[index] = hd) != null)
            hd.treeify(tab);
    }
}

putAll( Map<? extends K, ? extends V> m)

/**
 * 将参数map中的所有键值对映射插入到hashMap中,如果有碰撞,则覆盖value。
 * @param m 参数map
 * @throws NullPointerException 如果map为null
 */
public void putAll(Map<? extends K, ? extends V> m) {
    putMapEntries(m, true);
}

remove( Object key)

/**
 * 删除hashMap中key为参数key的键值对
 *
 * @param  key 参数key
 * @return 如果没有对应的键值对,返回null,否则返回对应的value。
 */
public V remove(Object key) {
    Node<K,V> e;
    //remove方法的具体实现在下面
    return (e = removeNode(hash(key), key, null, false, true)) == null ?
        null : e.value;
}

removeNode( int hash, Object key, Object value,boolean matchValue, boolean movable)

/**
 * Map.remove和相关方法的实现需要的方法
 * 删除node
 * 
 * @param hash key的哈希值
 * @param key 参数key
 * @param value 如果matchValue为true,则value也作为确定被删除的node的条件之一,否则忽略
 * @param matchValue 如果为true,则value也作为确定被删除的node的条件之一
 * @param movable 如果为false,删除node时不会删除其他node
 * @return 返回被删除的node,如果没有node被删除,则返回null
 */
final Node<K,V> removeNode(int hash, Object key, Object value,boolean matchValue, boolean movable) {
    Node<K,V>[] tab; Node<K,V> p; int n, index;
    //如果数组table不为空且key映射到的桶不为空
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (p = tab[index = (n - 1) & hash]) != null) {
        //
        Node<K,V> node = null, e; K k; V v;
        //如果桶上node的就是要删除的node
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            node = p;
        else if ((e = p.next) != null) {
            if (p instanceof TreeNode)//如果桶内的结构为红黑树
                //得到key映射到的node
                node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
            else {//如果桶内的结构为链表
                do {//遍历链表,找到key映射到的node
                    if (e.hash == hash &&
                        ((k = e.key) == key ||
                         (key != null && key.equals(k)))) {
                        node = e;
                        break;
                    }
                    p = e;
                } while ((e = e.next) != null);
            }
        }
        //如果得到的node不为null&&(matchValue为false||node.value和参数value匹配)
        if (node != null && (!matchValue || (v = node.value) == value || (value != null && value.equals(v)))) {
            //如果桶内的结构为红黑树
            if (node instanceof TreeNode)
                //使用红黑树的删除方法删除node
                ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
            else if (node == p)//如果桶上node的就是要删除的node
                //删除node
                tab[index] = node.next;
            else//如果桶内的结构为链表
                p.next = node.next;
            //结构性修改次数+1
            ++modCount;
            //哈希表大小-1
            --size;
            afterNodeRemoval(node);
            //返回被删除的node
            return node;
        }
    }
    //如果数组table为空或key映射到的桶为空
    return null;
}

clear()

/**
 * 删除map中所有的键值对
 */
public void clear() {
    Node<K,V>[] tab;
    modCount++;
    if ((tab = table) != null && size > 0) {
        size = 0;
        for (int i = 0; i < tab.length; ++i)
            tab[i] = null;
    }
}

containsValue( Object value)

/**
 * 如果hashMap中的键值对有一对或多对的value为参数value,返回true
 *
 * @param value 参数value
 * @return 如果hashMap中的键值对有一对或多对的value为参数value,返回true
 */
public boolean containsValue(Object value) {
    Node<K,V>[] tab; V v;
    //
    if ((tab = table) != null && size > 0) {
        //遍历数组table
        for (int i = 0; i < tab.length; ++i) {
            //遍历桶中的node
            for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                if ((v = e.value) == value ||
                    (value != null && value.equals(v)))
                    return true;
            }
        }
    }
    return false;
}

keySet()

/**
 * 返回hashMap中所有key的视图。
 * 改变hashMap会影响到set,反之亦然。
 * 如果当迭代器迭代set时,hashMap被修改(除非是迭代器自己的remove()方法),迭代器的结果是不确定的。
 * set支持元素的删除,通过Iterator.remove、Set.remove、removeAll、retainAll、clear操作删除hashMap中对应的键值对。不支持add和addAll方法。
 *
 * @return 返回hashMap中所有key的set视图
 */
public Set<K> keySet() {
    //
    Set<K> ks = keySet;
    if (ks == null) {
        ks = new KeySet();
        keySet = ks;
    }
    return ks;
}

/**
 * 内部类KeySet
 */
final class KeySet extends AbstractSet<K> {
    public final int size()                 { return size; }
    public final void clear()               { HashMap.this.clear(); }
    public final Iterator<K> iterator()     { return new KeyIterator(); }
    public final boolean contains(Object o) { return containsKey(o); }
    public final boolean remove(Object key) {
        return removeNode(hash(key), key, null, false, true) != null;
    }
    public final Spliterator<K> spliterator() {
        return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super K> action) {
        Node<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next)
                    action.accept(e.key);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
}

values()

/**
 * 返回hashMap中所有value的collection视图
 * 改变hashMap会改变collection,反之亦然。
 * 如果当迭代器迭代collection时,hashMap被修改(除非是迭代器自己的remove()方法),迭代器的结果是不确定的。
 * collection支持元素的删除,通过Iterator.remove、Collection.remove、removeAll、retainAll、clear操作删除hashMap中对应的键值对。不支持add和addAll方法。
 *
 * @return 返回hashMap中所有key的collection视图
 */
public Collection<V> values() {
    Collection<V> vs = values;
    if (vs == null) {
        vs = new Values();
        values = vs;
    }
    return vs;
}

/**
 * 内部类Values
 */
final class Values extends AbstractCollection<V> {
    public final int size()                 { return size; }
    public final void clear()               { HashMap.this.clear(); }
    public final Iterator<V> iterator()     { return new ValueIterator(); }
    public final boolean contains(Object o) { return containsValue(o); }
    public final Spliterator<V> spliterator() {
        return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super V> action) {
        Node<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next)
                    action.accept(e.value);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
}

entrySet()

/**
 * 返回hashMap中所有键值对的set视图
 * 改变hashMap会影响到set,反之亦然。
 * 如果当迭代器迭代set时,hashMap被修改(除非是迭代器自己的remove()方法),迭代器的结果是不确定的。
 * set支持元素的删除,通过Iterator.remove、Set.remove、removeAll、retainAll、clear操作删除hashMap中对应的键值对。不支持add和addAll方法。
 *
 * @return 返回hashMap中所有键值对的set视图
 */
public Set<Map.Entry<K,V>> entrySet() {
    Set<Map.Entry<K,V>> es;
    return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}

/**
 * 内部类EntrySet
 */
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
    public final int size()                 { return size; }
    public final void clear()               { HashMap.this.clear(); }
    public final Iterator<Map.Entry<K,V>> iterator() {
        return new EntryIterator();
    }
    public final boolean contains(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Map.Entry<?,?> e = (Map.Entry<?,?>) o;
        Object key = e.getKey();
        Node<K,V> candidate = getNode(hash(key), key);
        return candidate != null && candidate.equals(e);
    }
    public final boolean remove(Object o) {
        if (o instanceof Map.Entry) {
            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
            Object key = e.getKey();
            Object value = e.getValue();
            return removeNode(hash(key), key, value, true, true) != null;
        }
        return false;
    }
    public final Spliterator<Map.Entry<K,V>> spliterator() {
        return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
    }
    public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
        Node<K,V>[] tab;
        if (action == null)
            throw new NullPointerException();
        if (size > 0 && (tab = table) != null) {
            int mc = modCount;
            for (int i = 0; i < tab.length; ++i) {
                for (Node<K,V> e = tab[i]; e != null; e = e.next)
                    action.accept(e);
            }
            if (modCount != mc)
                throw new ConcurrentModificationException();
        }
    }
}

JDK8重写的方法

// Overrides of JDK8 Map extension methods

getOrDefault( Object key, V defaultValue)

/**
 * 通过key映射到对应node,如果没映射到则返回默认值defaultValue
 *
 * @return key映射到对应的node,如果没映射到则返回默认值defaultValue
 */
@Override
public V getOrDefault(Object key, V defaultValue) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
}

putIfAbsent( K key, V value)

/**
 * 在hashMap中插入参数key和value组成的键值对,如果key在hashMap中已经存在,不替换value
 *
 * @return 如果key在hashMap中不存在,返回旧value
 */
@Override
public V putIfAbsent(K key, V value) {
    return putVal(hash(key), key, value, true, true);
}

remove( Object key, Object value)

/**
 * 删除hashMap中key为参数key,value为参数value的键值对。如果桶中结构为树,则级联删除
 *
 * @return 删除成功,返回true
 */
@Override
public boolean remove(Object key, Object value) {
    return removeNode(hash(key), key, value, true, true) != null;
}

replace( K key, V oldValue, V newValue)

/**
 * 使用newValue替换key和oldValue映射到的键值对中的value
 * 
 * @return 替换成功,返回true
 */
@Override
public boolean replace(K key, V oldValue, V newValue) {
    Node<K,V> e; V v;
    if ((e = getNode(hash(key), key)) != null &&
        ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
        e.value = newValue;
        afterNodeAccess(e);
        return true;
    }
    return false;
}

replace( K key, V value)

/**
 * 使用参数value替换key映射到的键值对中的value
 * 
 * @return 替换成功,返回true
 */
@Override
public V replace(K key, V value) {
    Node<K,V> e;
    if ((e = getNode(hash(key), key)) != null) {
        V oldValue = e.value;
        e.value = value;
        afterNodeAccess(e);
        return oldValue;
    }
    return null;
}

computeIfAbsent( K key,Function<? super K, ? extends V> mappingFunction)

/**
 * 待补充
 * 
 * @return 
 */
@Override
public V computeIfAbsent(K key,Function<? super K, ? extends V> mappingFunction) {
    if (mappingFunction == null)
        throw new NullPointerException();
    int hash = hash(key);
    Node<K,V>[] tab; Node<K,V> first; int n, i;
    int binCount = 0;
    TreeNode<K,V> t = null;
    Node<K,V> old = null;
    if (size > threshold || (tab = table) == null ||
        (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((first = tab[i = (n - 1) & hash]) != null) {
        if (first instanceof TreeNode)
            old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
        else {
            Node<K,V> e = first; K k;
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k)))) {
                    old = e;
                    break;
                }
                ++binCount;
            } while ((e = e.next) != null);
        }
        V oldValue;
        if (old != null && (oldValue = old.value) != null) {
            afterNodeAccess(old);
            return oldValue;
        }
    }
    V v = mappingFunction.apply(key);
    if (v == null) {
        return null;
    } else if (old != null) {
        old.value = v;
        afterNodeAccess(old);
        return v;
    }
    else if (t != null)
        t.putTreeVal(this, tab, hash, key, v);
    else {
        tab[i] = newNode(hash, key, v, first);
        if (binCount >= TREEIFY_THRESHOLD - 1)
            treeifyBin(tab, hash);
    }
    ++modCount;
    ++size;
    afterNodeInsertion(true);
    return v;
}

computeIfPresent( K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction)

/**
 * 待补充
 * 
 * @return 
 */
public V computeIfPresent(K key,BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    if (remappingFunction == null)
        throw new NullPointerException();
    Node<K,V> e; V oldValue;
    int hash = hash(key);
    if ((e = getNode(hash, key)) != null &&
        (oldValue = e.value) != null) {
        V v = remappingFunction.apply(key, oldValue);
        if (v != null) {
            e.value = v;
            afterNodeAccess(e);
            return v;
        }
        else
            removeNode(hash, key, null, false, true);
    }
    return null;
}

compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction)

/**
 * 待补充
 */
@Override
public V compute( K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    if (remappingFunction == null)
        throw new NullPointerException();
    int hash = hash(key);
    Node<K,V>[] tab; Node<K,V> first; int n, i;
    int binCount = 0;
    TreeNode<K,V> t = null;
    Node<K,V> old = null;
    if (size > threshold || (tab = table) == null ||
        (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((first = tab[i = (n - 1) & hash]) != null) {
        if (first instanceof TreeNode)
            old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
        else {
            Node<K,V> e = first; K k;
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k)))) {
                    old = e;
                    break;
                }
                ++binCount;
            } while ((e = e.next) != null);
        }
    }
    V oldValue = (old == null) ? null : old.value;
    V v = remappingFunction.apply(key, oldValue);
    if (old != null) {
        if (v != null) {
            old.value = v;
            afterNodeAccess(old);
        }
        else
            removeNode(hash, key, null, false, true);
    }
    else if (v != null) {
        if (t != null)
            t.putTreeVal(this, tab, hash, key, v);
        else {
            tab[i] = newNode(hash, key, v, first);
            if (binCount >= TREEIFY_THRESHOLD - 1)
                treeifyBin(tab, hash);
        }
        ++modCount;
        ++size;
        afterNodeInsertion(true);
    }
    return v;
}

merge( K key, V value,BiFunction<? super V, ? super V, ? extends V> remappingFunction)

/**
 * 待补充
 */
@Override
public V merge(K key, V value,BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
    if (value == null)
        throw new NullPointerException();
    if (remappingFunction == null)
        throw new NullPointerException();
    int hash = hash(key);
    Node<K,V>[] tab; Node<K,V> first; int n, i;
    int binCount = 0;
    TreeNode<K,V> t = null;
    Node<K,V> old = null;
    if (size > threshold || (tab = table) == null ||
        (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((first = tab[i = (n - 1) & hash]) != null) {
        if (first instanceof TreeNode)
            old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
        else {
            Node<K,V> e = first; K k;
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k)))) {
                    old = e;
                    break;
                }
                ++binCount;
            } while ((e = e.next) != null);
        }
    }
    if (old != null) {
        V v;
        if (old.value != null)
            v = remappingFunction.apply(old.value, value);
        else
            v = value;
        if (v != null) {
            old.value = v;
            afterNodeAccess(old);
        }
        else
            removeNode(hash, key, null, false, true);
        return v;
    }
    if (value != null) {
        if (t != null)
            t.putTreeVal(this, tab, hash, key, value);
        else {
            tab[i] = newNode(hash, key, value, first);
            if (binCount >= TREEIFY_THRESHOLD - 1)
                treeifyBin(tab, hash);
        }
        ++modCount;
        ++size;
        afterNodeInsertion(true);
    }
    return value;
}

forEach( BiConsumer<? super K, ? super V> action)

/**
 * 待补充
 */
@Override
public void forEach(BiConsumer<? super K, ? super V> action) {
    Node<K,V>[] tab;
    if (action == null)
        throw new NullPointerException();
    if (size > 0 && (tab = table) != null) {
        int mc = modCount;
        for (int i = 0; i < tab.length; ++i) {
            for (Node<K,V> e = tab[i]; e != null; e = e.next)
                action.accept(e.key, e.value);
        }
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
}

replaceAll( BiFunction<? super K, ? super V, ? extends V> function)

/**
 * 待补充
 */
@Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
    Node<K,V>[] tab;
    if (function == null)
        throw new NullPointerException();
    if (size > 0 && (tab = table) != null) {
        int mc = modCount;
        for (int i = 0; i < tab.length; ++i) {
            for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                e.value = function.apply(e.key, e.value);
            }
        }
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
}

Cloning and serialization

clone()

/**
 * 浅拷贝。
 * clone方法虽然生成了新的HashMap对象,新的HashMap中的table数组虽然也是新生成的,但是数组中的元素还是引用以前的HashMap中的元素。
 * 这就导致在对HashMap中的元素进行修改的时候,即对数组中元素进行修改,会导致原对象和clone对象都发生改变,但进行新增或删除就不会影响对方,因为这相当于是对数组做出的改变,clone对象新生成了一个数组。
 *
 * @return hashMap的浅拷贝
 */
@SuppressWarnings("unchecked")
@Override
public Object clone() {
    HashMap<K,V> result;
    try {
        result = (HashMap<K,V>)super.clone();
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
    result.reinitialize();
    result.putMapEntries(this, false);
    return result;
}

loadFactor()

// These methods are also used when serializing HashSets
final float loadFactor() { return loadFactor; }

capacity()

// These methods are also used when serializing HashSets
final int capacity() {
    return (table != null) ? table.length :
        (threshold > 0) ? threshold :
        DEFAULT_INITIAL_CAPACITY;
}

writeObject( java.io.ObjectOutputStream s)

/**
 * 序列化hashMap到ObjectOutputStream中
 * 将hashMap的总容量capacity、实际容量size、键值对映射写入到ObjectOutputStream中。键值对映射序列化时是无序的。
 */
private void writeObject(java.io.ObjectOutputStream s)
    throws IOException {
    int buckets = capacity();
    // Write out the threshold, loadfactor, and any hidden stuff
    s.defaultWriteObject();
    //写入总容量
    s.writeInt(buckets);
    //写入实际容量
    s.writeInt(size);
    //写入键值对
    internalWriteEntries(s);
}

// 写入hashMap键值对到ObjectOutputStream中
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
    Node<K,V>[] tab;
    if (size > 0 && (tab = table) != null) {
        for (int i = 0; i < tab.length; ++i) {
            for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                s.writeObject(e.key);
                s.writeObject(e.value);
            }
        }
    }
}

readObject( java.io.ObjectInputStream s)

/**
 * 到ObjectOutputStream中读取hashMap
 * 将hashMap的总容量capacity、实际容量size、键值对映射读取出来
 */
private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
    // 将hashMap的总容量capacity、实际容量size、键值对映射读取出来
    s.defaultReadObject();
    //重置hashMap
    reinitialize();
    //如果负载因子不合法,抛出异常
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new InvalidObjectException("Illegal load factor: " + loadFactor);
    //读出桶的数量,忽略
    s.readInt();                // Read and ignore number of buckets
    //读出实际容量size
    int mappings = s.readInt(); // Read number of mappings (size)
    //如果读出的实际容量size小于0,抛出异常
    if (mappings < 0)
        throw new InvalidObjectException("Illegal mappings count: " + mappings);
    else if (mappings > 0) { // (if zero, use defaults)
        //调整hashMap大小
        // Size the table using given load factor only if within range of 0.25...4.0。为什么?
        // 负载因子
        float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
        //初步得到的总容量,后续还会处理
        float fc = (float)mappings / lf + 1.0f;
        //处理初步得到的容量,确认最终的总容量
        int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
                   DEFAULT_INITIAL_CAPACITY :
                   (fc >= MAXIMUM_CAPACITY) ?
                   MAXIMUM_CAPACITY :
                   tableSizeFor((int)fc));
        //计算临界值,得到初步的临界值
        float ft = (float)cap * lf;
        //得到最终的临界值
        threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ? (int)ft : Integer.MAX_VALUE);
        @SuppressWarnings({"rawtypes","unchecked"})
        //新建桶数组table
            Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
        table = tab;

        // 读出key和value,并组成键值对插入hashMap中
        for (int i = 0; i < mappings; i++) {
            @SuppressWarnings("unchecked")
                K key = (K) s.readObject();
            @SuppressWarnings("unchecked")
                V value = (V) s.readObject();
            putVal(hash(key), key, value, false, false);
        }
    }
}

迭代器

HashIterator

/**
 * 待补充
 */
abstract class HashIterator {
    Node<K,V> next;        // next entry to return
    Node<K,V> current;     // current entry
    int expectedModCount;  // for fast-fail
    int index;             // current slot

    HashIterator() {
        expectedModCount = modCount;
        Node<K,V>[] t = table;
        current = next = null;
        index = 0;
        if (t != null && size > 0) { // advance to first entry
            do {} while (index < t.length && (next = t[index++]) == null);
        }
    }

    public final boolean hasNext() {
        return next != null;
    }

    final Node<K,V> nextNode() {
        Node<K,V>[] t;
        Node<K,V> e = next;
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        if (e == null)
            throw new NoSuchElementException();
        if ((next = (current = e).next) == null && (t = table) != null) {
            do {} while (index < t.length && (next = t[index++]) == null);
        }
        return e;
    }

    public final void remove() {
        Node<K,V> p = current;
        if (p == null)
            throw new IllegalStateException();
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        current = null;
        K key = p.key;
        removeNode(hash(key), key, null, false, false);
        expectedModCount = modCount;
    }
}

KeyIterator

/**
 * key迭代器
 */
final class KeyIterator extends HashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().key; }
}

ValueIterator

/**
 * value迭代器
 */
final class ValueIterator extends HashIterator
    implements Iterator<V> {
    public final V next() { return nextNode().value; }
}

EntryIterator

/**
 * 键值对迭代器
 */
final class EntryIterator extends HashIterator
    implements Iterator<Map.Entry<K,V>> {
    public final Map.Entry<K,V> next() { return nextNode(); }
}

可分割迭代器

HashMapSpliterator

/**
 * 待补充
 */
static class HashMapSpliterator<K,V> {
    final HashMap<K,V> map;
    Node<K,V> current;          // current node
    int index;                  // current index, modified on advance/split
    int fence;                  // one past last index
    int est;                    // size estimate
    int expectedModCount;       // for comodification checks

    HashMapSpliterator(HashMap<K,V> m, int origin,
                       int fence, int est,
                       int expectedModCount) {
        this.map = m;
        this.index = origin;
        this.fence = fence;
        this.est = est;
        this.expectedModCount = expectedModCount;
    }

    final int getFence() { // initialize fence and size on first use
        int hi;
        if ((hi = fence) < 0) {
            HashMap<K,V> m = map;
            est = m.size;
            expectedModCount = m.modCount;
            Node<K,V>[] tab = m.table;
            hi = fence = (tab == null) ? 0 : tab.length;
        }
        return hi;
    }

    public final long estimateSize() {
        getFence(); // force init
        return (long) est;
    }
}

KeySpliterator

/**
 * 待补充
 */
static final class KeySpliterator<K,V>
    extends HashMapSpliterator<K,V>
    implements Spliterator<K> {
    KeySpliterator(HashMap<K,V> m, int origin, int fence, int est,
                   int expectedModCount) {
        super(m, origin, fence, est, expectedModCount);
    }

    public KeySpliterator<K,V> trySplit() {
        int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        return (lo >= mid || current != null) ? null :
            new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
                                    expectedModCount);
    }

    public void forEachRemaining(Consumer<? super K> action) {
        int i, hi, mc;
        if (action == null)
            throw new NullPointerException();
        HashMap<K,V> m = map;
        Node<K,V>[] tab = m.table;
        if ((hi = fence) < 0) {
            mc = expectedModCount = m.modCount;
            hi = fence = (tab == null) ? 0 : tab.length;
        }
        else
            mc = expectedModCount;
        if (tab != null && tab.length >= hi &&
            (i = index) >= 0 && (i < (index = hi) || current != null)) {
            Node<K,V> p = current;
            current = null;
            do {
                if (p == null)
                    p = tab[i++];
                else {
                    action.accept(p.key);
                    p = p.next;
                }
            } while (p != null || i < hi);
            if (m.modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

    public boolean tryAdvance(Consumer<? super K> action) {
        int hi;
        if (action == null)
            throw new NullPointerException();
        Node<K,V>[] tab = map.table;
        if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
            while (current != null || index < hi) {
                if (current == null)
                    current = tab[index++];
                else {
                    K k = current.key;
                    current = current.next;
                    action.accept(k);
                    if (map.modCount != expectedModCount)
                        throw new ConcurrentModificationException();
                    return true;
                }
            }
        }
        return false;
    }

    public int characteristics() {
        return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
            Spliterator.DISTINCT;
    }
}

ValueSpliterator

/**
 * 待补充
 */
static final class ValueSpliterator<K,V>
    extends HashMapSpliterator<K,V>
    implements Spliterator<V> {
    ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est,
                     int expectedModCount) {
        super(m, origin, fence, est, expectedModCount);
    }

    public ValueSpliterator<K,V> trySplit() {
        int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        return (lo >= mid || current != null) ? null :
            new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
                                      expectedModCount);
    }

    public void forEachRemaining(Consumer<? super V> action) {
        int i, hi, mc;
        if (action == null)
            throw new NullPointerException();
        HashMap<K,V> m = map;
        Node<K,V>[] tab = m.table;
        if ((hi = fence) < 0) {
            mc = expectedModCount = m.modCount;
            hi = fence = (tab == null) ? 0 : tab.length;
        }
        else
            mc = expectedModCount;
        if (tab != null && tab.length >= hi &&
            (i = index) >= 0 && (i < (index = hi) || current != null)) {
            Node<K,V> p = current;
            current = null;
            do {
                if (p == null)
                    p = tab[i++];
                else {
                    action.accept(p.value);
                    p = p.next;
                }
            } while (p != null || i < hi);
            if (m.modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

    public boolean tryAdvance(Consumer<? super V> action) {
        int hi;
        if (action == null)
            throw new NullPointerException();
        Node<K,V>[] tab = map.table;
        if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
            while (current != null || index < hi) {
                if (current == null)
                    current = tab[index++];
                else {
                    V v = current.value;
                    current = current.next;
                    action.accept(v);
                    if (map.modCount != expectedModCount)
                        throw new ConcurrentModificationException();
                    return true;
                }
            }
        }
        return false;
    }

    public int characteristics() {
        return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
    }
}

EntrySpliterator

/**
 * 待补充
 */
static final class EntrySpliterator<K,V>
    extends HashMapSpliterator<K,V>
    implements Spliterator<Map.Entry<K,V>> {
    EntrySpliterator(HashMap<K,V> m, int origin, int fence, int est,
                     int expectedModCount) {
        super(m, origin, fence, est, expectedModCount);
    }

    public EntrySpliterator<K,V> trySplit() {
        int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        return (lo >= mid || current != null) ? null :
            new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
                                      expectedModCount);
    }

    public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
        int i, hi, mc;
        if (action == null)
            throw new NullPointerException();
        HashMap<K,V> m = map;
        Node<K,V>[] tab = m.table;
        if ((hi = fence) < 0) {
            mc = expectedModCount = m.modCount;
            hi = fence = (tab == null) ? 0 : tab.length;
        }
        else
            mc = expectedModCount;
        if (tab != null && tab.length >= hi &&
            (i = index) >= 0 && (i < (index = hi) || current != null)) {
            Node<K,V> p = current;
            current = null;
            do {
                if (p == null)
                    p = tab[i++];
                else {
                    action.accept(p);
                    p = p.next;
                }
            } while (p != null || i < hi);
            if (m.modCount != mc)
                throw new ConcurrentModificationException();
        }
    }

    public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
        int hi;
        if (action == null)
            throw new NullPointerException();
        Node<K,V>[] tab = map.table;
        if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
            while (current != null || index < hi) {
                if (current == null)
                    current = tab[index++];
                else {
                    Node<K,V> e = current;
                    current = current.next;
                    action.accept(e);
                    if (map.modCount != expectedModCount)
                        throw new ConcurrentModificationException();
                    return true;
                }
            }
        }
        return false;
    }

    public int characteristics() {
        return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
            Spliterator.DISTINCT;
    }
}

LinkedHashMap support

下面的几个protected的方法是为了被LinkedHashMap重写设计的,不是为其他子类设计的。几乎所有其他的内部方法也是protected的,但被声明为final,所以可以被LinkedHashMap, view classes和HashSet使用。

newNode( int hash, K key, V value, Node<K,V> next)

/**
 * 创建一个常规的(不是树的)node
 */
Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
    return new Node<>(hash, key, value, next);
}

replacementNode( Node<K,V> p, Node<K,V> next)

/**
 * 为了将一个TreeNodes转化为常规的node而设计
 * untreeify(HashMap<K,V> map)在使用这个方法
 */
Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
    return new Node<>(p.hash, p.key, p.value, next);
}

newTreeNode( int hash, K key, V value, Node<K,V> next)

// 创建一个树节点
TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
    return new TreeNode<>(hash, key, value, next);
}

replacementTreeNode( Node<K,V> p, Node<K,V> next)

// treeifyBin在使用这个方法
TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
    return new TreeNode<>(p.hash, p.key, p.value, next);
}

reinitialize()

/**
 * 将hashMap重置到初始化的默认状态
 * 被clone方法和readObject方法使用。
 */
void reinitialize() {
    table = null;
    entrySet = null;
    keySet = null;
    values = null;
    modCount = 0;
    threshold = 0;
    size = 0;
}

afterNodeAccess( Node<K,V> p)

//允许LinkedHashMap进行post-actions的回调函数
void afterNodeAccess(Node<K,V> p) { }

afterNodeInsertion( boolean evict)

//允许LinkedHashMap进行post-actions的回调函数
void afterNodeInsertion(boolean evict) { }

afterNodeRemoval( Node

//允许LinkedHashMap进行post-actions的回调函数
void afterNodeRemoval(Node<K,V> p) { }

internalWriteEntries( java.io.ObjectOutputStream s)

// 仅被writeObject调用,为了确认共存的排序
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
    Node<K,V>[] tab;
    if (size > 0 && (tab = table) != null) {
        for (int i = 0; i < tab.length; ++i) {
            for (Node<K,V> e = tab[i]; e != null; e = e.next) {
                s.writeObject(e.key);
                s.writeObject(e.value);
            }
        }
    }
}

TreeNode

定义

/**
 * 树节点。
 * 继承LinkedHashMap.Entry,所以可以被用作常规node或者链node的扩展
 */
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {}

TreeNode<K,V> parent;  //父节点
TreeNode<K,V> left;//坐子树
TreeNode<K,V> right;//右子树
TreeNode<K,V> prev;    // needed to unlink next upon deletion
boolean red;//颜色属性

构造函数

TreeNode(int hash, K key, V val, Node<K,V> next) {
    super(hash, key, val, next);
}

方法

待补充

HashMap就先讲到这里,关于Java8和Java7的HashMap实现方式的不同,扩容机制详解、TreeNode详解以后会补充。

更多文章:

作者:panweiwei1994 发表于2017/8/19 20:38:27 原文链接
阅读:158 评论:0 查看评论

面试题30:最小的K个数及topK问题的解决

$
0
0

最近刷题老会被问到一些topK问题,今天把这些问题的解决方案整理一下。

题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

这是《剑指offer》中的最小的K个数问题,如果不考虑数据的数量,最直观的方案就是排序然后即可找出符合要求的k个数,时间复杂度为O(Nlog(N)),这并不是一个好的解决方案。但牛客oj是可以过的。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> output;
        if(input.empty() || k<0 || input.size()<k)
            return output;
        sort(input.begin(),input.end());
        int i=0;
        while(i<k)
            {
            output.push_back(input[i]);
            i++;
        }
        return output;
    }
};

第二种方案:我们要找的是K个数,其实并不要求把所有的数都必须排好序,只要是类有序也可以满足要求。也就是说如果当前数组是可以改变的,我们可以让第K个数左边的都是比自己小,右边是比自己大的。这样也满足条件,时间复杂度为O(N)。但就我个人而言,觉得仍不是最好的方案。数据量一旦过大,这两种方案的时间复杂度都过高。

在这里我说的第三种使用优先级队列,优先级队列是默认建小堆,然后每次只需要将堆头的数据pop掉,优先队列会自动调整保证仍是一个优先队列,接着pop,直到pop出K个数。时间复杂度为O(NlogK)。

这个题并不难,前两天在网上看到一道题类似这道题,但是又不太相同。题目如下:本公司现在要给公司员工发波福利,在员工工作时间会提供大量的水果供员工补充营养。由于水果种类比较多,但是却又不知道哪种水果比较受欢迎,然后公司就让每个员工报告了自己最爱吃的k种水果,并且告知已经将所有员工喜欢吃的水果存储于一个数组中。然后让我们统计出所有水果出现的次数,并且求出大家最喜欢吃的前k种水果。要求打印出最喜欢的水果,并且效率尽可能的高。

这道题和上面一样都是topK问题,但是这里除了统计水果的次数还要保存是哪种水果,可能看到的时候还有点懵,但是在STL中有很多数据结构供我们考虑。因为考虑到要保存两个信息,我们可以用map,map的底层是红黑树,这里我们将水果的名字和次数都保存起来。

首先通过用迭代器遍历保存数组,统计出每次水果出现的次数。接下来通过优先队列建大堆,所以这个时候需要自己去写个仿函数,将其变成大堆。然后将信息通过优先队列建大堆,这个时候只需要pop出K个数即可。代码如下。

void GetFavoriteFruit(const vector<string>& fruits, size_t k)
{
    map<string, int> count;
    for (size_t i = 0; i < fruits.size(); i++)  //把水果对应的存入map中
    {
        map<string, int>::iterator it = count.find(fruits[i]);
        if (it != count.end())
            it->second++;
        else
        {
            count.insert(make_pair(fruits[i], 1));
        }
    }


    struct Compare
    {
        bool operator()(map<string, int>::iterator l, map<string, int>::iterator r)
        {
            return l->second < r->second;
        }
    };

    priority_queue<map<string, int>::iterator,vector<map<string,int>::iterator>,Compare> p;
    map<string, int>::iterator countIt = count.begin();
    while (countIt != count.end())
    {
        p.push(countIt);
        ++countIt;  
    }

    while (k--)
    {
        p.top()->first;
        cout << p.top()->first << ":" << p.top()->second << endl;
        p.pop();
    }
}

void TestTopK()
{
    //西瓜 4  香蕉3  苹果3 橘子2
    vector<string> fruits = { "西瓜", "香蕉","西瓜", "香蕉", "苹果", "西瓜", "苹果", "橘子", "西瓜", "香蕉" };
    GetFavoriteFruit(fruits, 2);
}

优先队列头文件queue,还有就是对优先队列的接口一定要熟悉。

这里写图片描述

在上面的几种方案里,我们一直在说数据量过大怎么办,假设现在有10亿(N)个数,我们想找出前50(K)个,如果用排序去统计,那么时间复杂度会很大,这不是我们期待的。如果我们用堆去进行统计就会快速便捷很多,我们先将前50个数建小堆,然后从第50个向后比较,比堆头大就置换进来,在去调整堆,时间复杂度为:O(Nlog(K))。这种方案是比较适合处理海量数据的。

值得注意的是,堆排序只能随机访问的数据结构进行排序,也就是说数组这一类,所以在使用的时候,我是用了一个vector来保存map的迭代器,优先队列的三个参数意义分别是放什么,用什么容器放,怎么比。priority_queue< map< string, int>::iterator,vector< map< string,int>::iterator>,Compare> p,意思是优先级队列是用map的迭代器构成的,用vector保存迭代器,用自己实现的compare进行比较。

作者:Monster_Girl 发表于2017/8/19 21:09:15 原文链接
阅读:131 评论:0 查看评论

排序--归并排序

$
0
0
<?php
class Test
{
  public function shellSort(&$arr)
  {
    $this->sort($arr,0,count($arr)-1);
  }
  public function sort(&$arr,$lo,$hi)
  {
     if($lo >= $hi)
     {
       return;
     }
     $tempNum =intval(($hi - $lo)/2);
     $mid = $lo + $tempNum;
     $this->sort($arr,$lo,$mid);
     $this->sort($arr,$mid+1,$hi);
     $this->merge($arr,$lo,$mid,$hi);
     print_r($arr);
  }

  public function merge(&$arr,$lo,$mid,$hi)
  {

    $m = $lo;
    $n = $mid+1;

    for($k = $lo;$k <= $hi;$k++)
    {
      $temps[$k] = $arr[$k];
    }

    for($i = $lo; $i<=$hi; $i++)
    {
      if($m > $mid)
      {
        $arr[$i] = $temps[$n++];
      }
      else if($n > $hi)
      {
        $arr[$i] = $temps[$m++];
      }
      else if($temps[$m] > $temps[$n])
      {
        $arr[$i] = $temps[$n++];
      }
      else
      {
        $arr[$i] = $temps[$m++];
      }
    }
  }
}

$test = new Test();
$params = array(5,8,7,6);
$test->shellSort($params);



作者:renpengddxx 发表于2017/8/19 21:14:18 原文链接
阅读:125 评论:0 查看评论

Uva 10256 The Great Divide(凸包)

$
0
0

题目地址:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1197

思路:

分离两种点,即为分离两种点组成的两个凸包:

1.任取A凸包中的一点,判断是否在B凸包中;任取B凸包中的一点,判断是否在A凸包中;

2.任取A凸包上一条线段,判断是否与B凸包中线段相交;任取B凸包上一条线段,判断是否与A凸包中线段相交。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debug
using namespace std;
struct Point
{
    double x,y;
    Point(double x=0.0,double y=0.0):x(x),y(y) {}
    void read()
    {
        scanf("%lf%lf",&x,&y);
    }
};
typedef Point Vector;
int dcmp(double x)
{
    if(fabs(x)<0) return 0;
    else return x<0?-1:1;
}
bool operator < (Point A,Point B)
{
    if(A.x==B.x) return A.y<A.y;
    else return A.x<B.x;
}
Vector operator - (Vector A,Vector B)
{
    return Vector(A.x-B.x,A.y-B.y);
}
double Cross(Vector A,Vector B)
{
    return A.x*B.y-A.y*B.x;
}
double Dot(Vector A,Vector B)
{
    return A.x*B.x+A.y*B.y;
}
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)
{
    double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1),
           c3=Cross(b2-b1,a1-b1),c4=Cross(b2-b1,a2-b1);
    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
}
bool isPointOnSegment(Point p,Point a1,Point a2)
{
    return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}
int ConvexHull(Point* p,int n,Point* ch)
{
    sort(p,p+n);
    int m=0;
    for(int i=0; i<n; i++)
    {
        while(m>1&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
        ch[m++]=p[i];
    }
    int k=m;
    for(int i=n-2; i>=0; i--)
    {
        while(m>k&&Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])<=0) m--;
        ch[m++]=p[i];
    }
    if(n>1) m--;
    return m;
}

int isPointInPolygon(Point p,Point* poly,int n)
{
    int wn=0;
    for(int i=0; i<n; i++)
    {
        if(isPointOnSegment(p,poly[i],poly[(i+1)%n])) return -1;
        int k=dcmp(Cross(poly[(i+1)%n]-poly[i],p-poly[i]));
        int d1=dcmp(poly[i].y-p.y);
        int d2=dcmp(poly[(i+1)%n].y-p.y);
        if(k>0&&d1<=0&&d2>0) wn++;
        if(k<0&&d2<=0&&d1>0) wn--;
    }
    if(wn!=0) return 1;
    return 0;
}

const int maxn=500+50;

int m,c;
int num1,num2;
Point p1[maxn],p2[maxn];
Point convex1[maxn],convex2[maxn];

int checkIn()
{
    for(int i=0; i<num1; i++)
    {
        if(isPointInPolygon(convex1[i],convex2,num2))
        {
            return 1;
        }
    }
    for(int i=0; i<num2; i++)
    {
        if(isPointInPolygon(convex2[i],convex1,num1))
        {
            return 1;
        }
    }
    return 0;
}

int checkIntersection()
{
    for(int i=0; i<num1; i++)
    {
        for(int j=0; j<num2; j++)
        {
            if(SegmentProperIntersection(convex1[i],convex1[(i+1)%num1],convex2[j],convex2[(j+1)%num2]))
            {
                return 1;
            }
        }
    }
    return 0;
}

int main()
{
#ifdef debu
    freopen("in.txt","r",stdin);
#endif // debug
    while(scanf("%d%d",&m,&c)!=EOF&&(m+c))
    {
        for(int i=0; i<m; i++) p1[i].read();
        for(int i=0; i<c; i++) p2[i].read();
        num1=ConvexHull(p1,m,convex1);
        num2=ConvexHull(p2,c,convex2);
        if(!checkIn()&&!checkIntersection())
        {
            printf("Yes\n");
        }
        else
        {
            printf("No\n");
        }
    }
    return 0;
}



作者:wang2147483647 发表于2017/8/19 21:21:42 原文链接
阅读:142 评论:0 查看评论

《华为机试在线训练》之简单错误记录

$
0
0

题目描述

开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。

 

处理: 

 

1、 记录最多8条错误记录,循环记录,对相同的错误记录(净文件名称和行号完全匹配)只记录一条,错误计数增加;

 

2、 超过16个字符的文件名称,只记录文件的最后有效16个字符;

 

3、 输入的文件可能带路径,记录文件名称不能带路径。


输入描述:

一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。

输出描述:

将所有的记录统计并将结果输出,格式:文件名 代码行数 数目,一个空格隔开,如:

示例1

输入

E:\V1R2\product\fpgadrive.c   1325

输出

          看题目中的处理要求和测试用例可以发现,输出结果一定要除掉路径,就是要将“\”之前的字符全都去掉,不打印输出,同时注意到题目要求只能记录文件的最后16个有效字符,意思就是说如果文件名称大于16个字符的话,只截取后面16个字符作为文件名称输出,最后看要求1,记录最多8条错误记录,循环记录,对相同的记录只记录一条,错误计数增加,这就要做错误相同性判断,根据这些要求可以将该题目细分为三个部分:

一,去路径处理

    

string getfilename(string &path)
{
    int pos;
    string result;
    pos=path.rfind('\\');  //寻找“\”的位置,标记为pos
    result=path.substr(pos+1,path.size()-pos);  //将从pos之后的数值存放在result中,这样就可以去掉路径
    if(result.length()>16)                      //判断result中的字符串长度是否大于16,如果大于16则要截取后面16个字符
    {
        result=result.substr(result.length()-16,16);      //截取后16个字符
    }
    return result;
}
     该函数中使用到了字符串的两个处理函数,rfind()和substr()函数,具体的操作在注释中可以清晰地看到,为什么要这样做,每一步的进行都是为了符合题目中处理的要求。以该子函数中的使用为例,简单介绍一下这两个函数。

 1,rfind()函数

      string中的find函数与rfind函数定义如下:

     int  find(char c,int pos=0) const; //从pos开始查找字符c在当前串中的位置

     int  find(const char *s,int pos=0) const; //从pos开始查找字符串s在当前串中的位置

     int  find(const char *s,int pos,int n) const; //从pos开始查找字符串s中前n个字符在当前串中的位置

     int  find(const string &s,int pos=0) const; //从pos开始查找字符串s在当前串中的位置

     //查找成功时返回所在的位置,失败了则返回string::npos的值

     int  find(char c,int pos=0) const; //从pos开始由后向前地查找字符c在当前串中的位置

     int  find(const char *s,int pos=0) const; //从pos开始由后向前地查找字符串s在当前串中的位置

     int  find(const char *s,int pos,int n) const; //从pos开始由后向前地查找字符串s中前n个字符在当前串中的位置

     int  find(const string &s,int pos=0) const; //从pos开始由后向前地查找字符串s在当前串中的位置

2,substr()函数

     substr函数的功能是从给定的字符表达式或者备注字段中返回一个子字符串。主要功能是复制字符串,要求从指定位置开始,并具有指定的长度。具体用法如下所示:

     string str;

     str.substr(pos,length);

     pos为指定的位置,length为从pos位置开始复制长度为length的字符串出来,可以称为字符截取函数。

二,结构体定义以及重复性函数

       

struct error_codes{
   string filename;
   int codeline;
   int counter=1;
   bool operator==(const error_codes &a)
   {
       if(a.filename==filename&&a.codeline==codeline)
        return true;
       else
        return false;
   }
};
      定义一个结构体来存放错误文件名称、错误行、错误数量,其中定义一个布尔函数,判断是否有重复的错误,即文件名称与错误行数都相等。

三,输入和重复性查找

      

while(cin>>path>>codeline)
    {
        error_codes temp;
        temp.filename=getfilename(path);
        temp.codeline=codeline;
        vector<error_codes>::iterator res;
        res=find(arr.begin(),arr.end(),temp);  //在arr中查找temp值,
        if(res==arr.end())
        {
            arr.push_back(temp);
        }
        else
        {
            res->counter++;
        }




    }
        因为有多组用例输入,所以要用while循环,之前有同学遇到过在自己的电脑上运行程序可以输出结果,但是在牛客网上提交代码的时候没有结果输出,这就是没有进行while循环输入的原因,因为测试用例为多组,所以要进行循环输入。在这里,在输入之后查找输入在之前的输入之中有没有重复一致的错误,如果有就错误计数加1。

四,完整程序代码如下:

       

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

struct error_codes{
   string filename;
   int codeline;
   int counter=1;
   bool operator==(const error_codes &a)
   {
       if(a.filename==filename&&a.codeline==codeline)
        return true;
       else
        return false;
   }
};

string getfilename(string &path);
int main()
{
    vector<error_codes> arr;
    string path;
    int codeline;

    //int error_line;
    while(cin>>path>>codeline)
    {
        error_codes temp;
        temp.filename=getfilename(path);
        temp.codeline=codeline;
        vector<error_codes>::iterator res;
        res=find(arr.begin(),arr.end(),temp);  //在arr中查找temp值,
        if(res==arr.end())
        {
            arr.push_back(temp);
        }
        else
        {
            res->counter++;
        }




    }
    int j=0;
        if(arr.size()>8)
        {
            j=arr.size()-8;
        }
        for(;j<arr.size();j++)
        {
            cout<<arr[j].filename<<" "<<arr[j].codeline<<" "<<arr[j].counter<<endl;
        }

    return 0;
}

string getfilename(string &path)
{
    int pos;
    string result;
    pos=path.rfind('\\');  //寻找“\”的位置,标记为pos
    result=path.substr(pos+1,path.size()-pos);  //将从pos之后的数值存放在result中,这样就可以去掉路径
    if(result.length()>16)                      //判断result中的字符串长度是否大于16,如果大于16则要截取后面16个字符
    {
        result=result.substr(result.length()-16,16);      //截取后16个字符
    }
    return result;
}

作者:huangchijun11 发表于2017/8/19 22:14:32 原文链接
阅读:126 评论:0 查看评论

【简书如何插入代码框】

$
0
0

【简书如何插入代码框】




步骤一:打开设置



步骤二:选择Markdown模式



步骤三:新建文章,在代码前面加上```即可(注:```为键盘上Esc键的下面英文符号)



步骤四:在```后面插入swift,可以使代码高亮显示,更加直观



步骤五:切换到预览模式,实时查看效果



步骤六:发布文章,看看你的代码框是否插入成功了呢?




作者:M_agician 发表于2017/8/20 1:40:22 原文链接
阅读:124 评论:0 查看评论

史上最简单的 MySQL 教程(二十八)「外键(上)」

$
0
0

外键

外键foreign key,外面的键,即不在自己表中的键。如果一张表中有一个非主键的字段指向另外一张表的主键,那么将该字段称之为外键。每张表中,可以有多个外键。

新增外键

外键既可以在创建表的时候增加,也可以在创建表之后增加(但是要考虑数据的问题)。

第 1 种:在创建表的时候,增加外键

  • 基本语法foreign key(外键字段) + references + 外部表名(主键字段);

执行如下 SQL 语句,进行测试:

-- 创建外键
create table my_foreign1(
    id int primary key auto_increment,
    name varchar(20) not null comment '学生姓名',
    c_id int comment '班级表ID',
    -- 增加外键
    foreign key(c_id) references class(id)  
)charset utf8;

foreign1

观察上图可知,字段c_idkey显示为MUL,表示多个键的意思。这是因为外键要求字段本身是一个索引(普通索引)如果字段本身没有索引,外键就会先创建一个索引,然后才创建外键本身。此外,CONSTRAINT后面的my_foreign_ibfk_1表示外键的名字。

第 2 种:在创建表之后,增加外键

  • 基本语法alter table + 表名 + add[constraint + 外键名字] + foreign key(外键字段) + references + 外部表名(主键字段);

执行如下 SQL 语句,进行测试:

-- 创建外键
create table my_foreign2(
    id int primary key auto_increment,
    name varchar(20) not null comment '学生姓名',
    c_id int comment '班级表ID'
)charset utf8;

-- 增加外键
alter table my_foreign2 add
-- 指定外键名
constraint test_foreign
-- 指定外键字段
foreign key(c_id)
-- 引用外部表主键
references class(id);

foreign2

如上图所示,显然咱们已经增加外键成功啦!

修改外键 & 删除外键

外键不能修改,只能先删除后增加。

  • 基本语法alter table + 表名 + drop foreign key + 外键名字;

执行如下 SQL 语句,进行测试:

-- 删除外键
alter table my_foreign1 drop foreign key my_foreign1_ibfk_1;

foreign3

观察上图可知,删除外键不能通过查看表结构来体现,而是应该通过创建表的语句来查看。


温馨提示:符号[]括起来的内容,表示可选项;符号+,则表示连接的意思。


———— ☆☆☆ —— 返回 -> 史上最简单的 MySQL 教程 <- 目录 —— ☆☆☆ ————

作者:qq_35246620 发表于2017/8/19 23:02:53 原文链接
阅读:13 评论:0 查看评论

Go语言学习笔记 --- concurrency、channel、select

$
0
0

学习笔记根据 无闻 go语言基础教程 整理

concurrency

  • 很多人都是冲着 Go 大肆宣扬的高并发而忍不住跃跃欲试,但其实从源码的解析来看,goroutine 只是由官方实现的超级”线程池”。
  • 不过话说回来,每个实例 4-5KB 的栈内存占用和由于实现机制而大幅减少的创建和销毁开销,是制造 Go 号称的高并发的根本原因。
  • 另外,goroutine 的简单易用,也在语言层面上给予了开发者巨大的便利。
  • 并发不是并行:Concurrency Is Not Parallelism
  • 并发主要由切换时间片来实现“同时”运行,在并行则是直接利用
  • 多核实现多线程的运行,但 Go 可以设置使用核数,以发挥多核计算机的能力。
  • Goroutine 奉行通过通信来共享内存,而不是共享内存来通信。

channel

  • Channel 是 goroutine 沟通的桥梁,大都是阻塞同步的
  • 通过 make 创建,close 关闭
  • Channel 是引用类型
  • 可以使用 for range 来迭代不断操作 channel
  • 可以设置单向或双向通道
  • 可以设置缓存大小,在未被填满前不会发生阻塞

select

  • 可处理一个或多个 channel 的发送与接收
  • 同时有多个可用的 channel时按随机顺序处理
  • 可用空的 select 来阻塞 main 函数
  • 可设置超时

示例代码

package main

import (
    "fmt"
    "time"
    "runtime"
    "sync"
)


func main() {
    // 说明,由于存在异步和阻塞等情况,测试时候需要一个函数一个函数的执行
    // 执行一个函数时,注释掉其他测试函数
    test1T()
    // test2()
    // test3()
    // test4()
    // test5()
    // test6()
    // test7T()
    // test8T()
    // test9T()
    // test10T()
    // test11T()
    // test12()
    // test13()
    // test14()
}

func test1() {
    fmt.Println("Go Go Go !!!")
}

func test1T() {
    fmt.Println("=============test1T=============")
    go test1() // 先启动goroutine
    time.Sleep(2 * time.Second) // 程序等待2s后退出
}

// 使用channel 来进行消息的发送
func test2() {
    fmt.Println("=============test2=============")
    c := make(chan bool) // 创建一个channel
    // 下面是用匿名函数
    go func() {
        fmt.Println("Go2") // Go2
        c <- true // c 存进一个bool型
    }()
    <-c // 在外面取出来 函数在执行到这一步的时候是阻塞状态,等c 存完之后才会执行这里,结束运行
}

// 可以使用 for range 来迭代不断操作 channel,等待channel完成,利用close函数,最后退出程序
func test3() {
    fmt.Println("=============test3=============")
    c := make(chan bool) // 创建一个channel ,make 即能存,又能取 (属于双向通道)
    // 下面是用匿名函数
    go func() {
        fmt.Println("Go2")
        c <- true // c 存进一个bool型
        close(c) // 在迭代时一定要注意close,否则会死锁,最终崩溃退出。
    }()
    for v := range c {
        fmt.Println(v) // true
    }
}

// 测试 使用无缓存的channel
func test4() {
    fmt.Println("=============test4=============")
    c := make(chan bool)
    go func() {
        fmt.Println("Go3")
        c <- true
    }()
    <- c // main 函数先执行,再去执行 goroutine, 此处是一直等待状态, 直到取出东西来,main函数退出
}

// 测试 使用无缓存的channel, 尝试位置调换, 无缓存是同步阻塞状态,直到读取到,才会结束
func test5() {
    fmt.Println("=============test5=============")
    c := make(chan bool)
    go func() {
        fmt.Println("Go3") // Go3
        <- c
    }()
    c <- true
}

// 测试使用有缓存的channel, 并且对调位置 ,有缓存是异步的
func test6() {
    fmt.Println("=============test6=============")
    c := make(chan bool, 1)
    go func() {
        fmt.Println("Go3") // 未输出
        <- c

    }()
     c <- true // 直接退出
}

func test7() {
    a := 1
    for i := 0; i<10000000; i++ {
        a += i
    }
    fmt.Println(a)
}

// 循环10个 goroutine ,什么都没输出
func test7T() {
    fmt.Println("=============test7T=============")
    for i := 0; i < 10; i++ {
        go test7()
    }
}

func test8(c chan bool, index int) {
    a := 1
    for i := 0; i<100; i++ {
        a += i
    }
    fmt.Println(index, a)
    if index == 9 {
        c <- true
    }
}

// 循环输出10个 goroutine , 但结果并未按照想象中的,10个分别输出执行,可能是go的api版本升级导致的, 默认使用多核处理
// 意想不到的结果是 每个goroutine 都是独立的,
// 如果第9个先输出,那么其他的可能并不会输出而是直接结束
func test8T() {
    fmt.Println("=============test8T=============")
    c := make(chan bool)
    for i := 0; i < 10; i++ {
        go test8(c, i)
    }
    <-c
}

// 循环10个 goroutine , 但是每个goroutine 都是独立的,如果第9个先输出,那么其他的可能并不会输出而是直接结束
// 同样使用test8 , 现在的情况是,输出结果和test8T是一样的
func test9T() {
    fmt.Println("=============test9T=============")
    runtime.GOMAXPROCS(runtime.NumCPU()) // 使用多核CPU,分配不定的, 不能够用最后一个goroutine的结果,作为10个都完成的判定
    c := make(chan bool)
    for i := 0; i < 10; i++ {
        go test8(c, i)
    }
    <-c
}

func test10(c chan bool, index int) {
    a := 1
    for i := 0; i<100; i++ {
        a += i
    }
    fmt.Println(index, a)
    c <- true
}

// 设置一个缓存长度为10的channel, 使用此种方法,10个channel会分别输出执行
func test10T() {
    fmt.Println("=============test10T=============")
    runtime.GOMAXPROCS(runtime.NumCPU()) // 使用多核CPU,分配不定的, 不能够用最后一个goroutine的结果,作为10个都完成的判定
    c := make(chan bool, 10) // 此处channel 长度为10
    for i := 0; i < 10; i++ {
        go test10(c, i)
    }
    // 循环取10次
    for i := 0; i < 10; i ++ {
        <-c
    }
}

// 使用第二种方法来完成执行10个channel
// 通过sync 同步包中的waitgroup 来创建一个任务组,在任务组中添加要完成的任务数
// 在没完成一次任务,就标记一次档,待完成任务数就会往下减,直到为0时,全部任务就会完成。

func test11(wg *sync.WaitGroup, index int) {
    a := 1
    for i := 0; i < 100; i++ {
        a += i
    }
    fmt.Println(index, a)

    wg.Done()
}

func test11T() {
    fmt.Println("=============test11T=============")
    runtime.GOMAXPROCS(runtime.NumCPU()) // 使用多核CPU,分配不定的, 不能够用最后一个goroutine的结果,作为10个都完成的判定
    wg := sync.WaitGroup{}
    wg.Add(10)
    for i := 0; i < 10; i++ {
        go test11(&wg, i)
    }
    wg.Wait()
}

// 使用select 测试多个channel
func test12() {
    fmt.Println("=============test12=============")
    c1, c2 := make(chan int), make(chan string)
    o := make(chan bool, 2) // 设置一个缓存为2的channel
    go func() {
        for {
            select {
            case v, ok := <-c1:
                if !ok {
                    o <- true
                    break
                }
                fmt.Println("c1",v)
            case v, ok := <- c2:
                if !ok {
                    o <- true
                    break
                }
                fmt.Println("c2", v)
            }
        }
    }()

    c1 <- 1
    c2 <- "hi"
    c1 <- 3
    c2 <- "hello"

    close(c1)
    close(c2)

    for i := 0; i < 2; i ++ {
        <- o
    }

    /*
    // 程序运行结果:
    c1 1
    c2 hi
    c1 3
    c2 hello

     */
}

func test13() {
    fmt.Println("=============test13=============")
    c := make(chan int)
    go func() {
        // 不断读出c的值
        for v := range c {
            fmt.Println(v)
        }
    }()

    // 随机向c中写入0或者1
    for i := 0; i < 6; i++ {
        select {
        case c <- 0:
        case c <- 1:
        }
    }

    /*
    // 随机输出结果:
    1
    1
    0
    0
    0

     */
}

// select 可设置超时
func test14() {
    fmt.Println("=============test14=============")
    c := make(chan bool)
    select {
    case v:= <-c: // 此处未向c中放入数据,所以程序一直在等待
        fmt.Println(v)
    case <- time.After(3 * time.Second): // time.After 返回一个channel,case被执行,输出 Timeout After 3 second
        fmt.Println("Timeout After 3 second")
    }

    /*
    // 程序在3s后的运行结果:
    Timeout After 3 second
     */

}
作者:Tyro_java 发表于2017/8/19 23:18:29 原文链接
阅读:54 评论:0 查看评论

排序--快速排序

$
0
0
<?php
class Test
{
  public function quickSort(&$arr)
  {
    $this->sort($arr,0,count($arr)-1); 
  }

  public function sort(&$arr,$lo,$hi)
  {
    if($lo >= $hi)
    {
      return;
    }
    $postion = $this->position($arr,$lo,$hi);
    $this->sort($arr,$lo,$postion-1);
    $this->sort($arr,$postion+1,$hi);
  }
  public function position(&$arr,$lo,$hi)
  {
    $key = $arr[$lo];
    $m = $lo;
    $n = $hi+1;

    while(true)
    {
      while($key > $arr[++$m])
      {
        if($m == $hi)
        {
          break;
        }
      }
      while($key < $arr[--$n])
      {
        if($n == $lo)
        {
          break;
        }
      }
      if($m >= $n)
      {
        break;
      }

      $temp = $arr[$m];
      $arr[$m] = $arr[$n];
      $arr[$n] = $temp;
    }

    $temp1 = $arr[$lo];
    $arr[$lo] = $arr[$n];
    $arr[$n] = $temp1;
    return $n;
  }
}

$test = new Test();
$params = array(5,8,7,6,4,8,9,1,4);
$test->quickSort($params);
print_r($params);
作者:renpengddxx 发表于2017/8/20 7:42:45 原文链接
阅读:109 评论:0 查看评论

剑指offer 面试题63 二叉搜索树的第 k 个结点

$
0
0

剑指offer 面试题63 二叉搜索树的第 k 个结点

题目:
    给定一棵二叉搜索树,请找出其中的第 k 大的结点。
    例如下面的二叉树中,按结点数值大小升序顺序,第三个结点的值是 7。
                 8
                / \
               6  10
             / \  / \
            5  7 9  11
package foroffer.top70;

import org.junit.Test;

/**
 * description:
 *
 * @author liyazhou
 * @create 2017-06-08 19:42
 * 面试题63:二叉搜索树的第 k 个结点
 *
 * 题目:
 *      给定一棵二叉搜索树,请找出其中的第 k 大的结点。
 *      例如下面的二叉树中,按结点数值大小升序顺序,第三个结点的值是 7。
 *                  8
 *                 / \
 *                6  10
 *              / \  / \
 *             5  7 9  11
 *
 * 考查点:
 *      1. 二叉搜索树
 *      2. 二叉树的中序遍历
 *      3. 递归,递归中状态变量的设置
 */


class BinTreeNode{
    int value;
    BinTreeNode left;
    BinTreeNode right;
    public BinTreeNode(int _value){ value = _value; }
    public void setChildren(BinTreeNode _left, BinTreeNode _right){
        left = _left;
        right = _right;
    }
}


public class Test63 {

    public BinTreeNode kthNode(BinTreeNode root, int[] k){
        BinTreeNode kthNode = null;
        if (root.left != null) kthNode = kthNode(root.left, k);  // 左子树的遍历
        // System.out.println("--------" + k[0]);
        if (kthNode == null){  // 中序遍历的操作
            k[0] --;
            if (k[0] == 0) kthNode = root;
        }
        if (kthNode == null && root.right != null)  // 右子树的遍历
            kthNode = kthNode(root.right, k);
        return kthNode;
    }


    @Test
    public void test(){
        BinTreeNode node8 = new BinTreeNode(8);
        BinTreeNode node6 = new BinTreeNode(6);
        BinTreeNode node10 = new BinTreeNode(10);
        BinTreeNode node5 = new BinTreeNode(5);
        BinTreeNode node7 = new BinTreeNode(7);
        BinTreeNode node9 = new BinTreeNode(9);
        BinTreeNode node11 = new BinTreeNode(11);

        node8.setChildren(node6, node10);
        node6.setChildren(node5, node7);
        node10.setChildren(node9, node11);

        BinTreeNode node = kthNode(node8, new int[]{3});
        System.out.println(node.value);
    }
}
作者:liyazhou0215 发表于2017/8/20 9:47:16 原文链接
阅读:16 评论:0 查看评论

2017CCPC 网络选拔赛1003 Ramsey定理

$
0
0

Ramsey定理

    任意6个人中,一定有三个人互为朋友,或者互相不是朋友。

证明

这里我就不证明了。下面链接有证明
鸽巢原理
Ramsey定理


AC代码

#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxn = 3000+5;
bool r[maxn][maxn];
int main() {
    int T, n;
    scanf("%d", &T);
    while(T--) {
        int rl;
        scanf("%d", &n);
        for(int i = 1; i < n; i++) {
            for(int j = i+1; j <= n; ++j) {
                scanf("%d", &rl);
                r[i][j] = r[j][i] = rl;
            }
        }
        if(n >= 6) {
            printf("Bad Team!\n");
            continue;
        }
        //暴力枚举三个人
        bool ok = false;
        for(int i = 1; i <= n; i++) {
            for(int j = i+1; j <= n; j++) {
                for(int k = j+1; k <= n; k++) {
                    if(r[i][j] == r[i][k] && r[i][j] == r[j][k]) {
                        ok = true;
                    }
                    if(ok) break;
                }
                if(ok) break;
            }
            if(ok) break;
        }
        if(ok) printf("Bad Team!\n");
        else printf("Great Team!\n");
    }
    return 0;
}

如有不当之处欢迎指出!

作者:flyawayl 发表于2017/8/20 10:02:46 原文链接
阅读:0 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>