Java中使用HashMap改進查找性能的步驟
Java中,HashMap,其實就是鍵值對。一個Key,對應一個值;寫數(shù)據(jù)時,指定Key寫對應值;讀取時憑Key找到相應值。感覺就跟Redis差不多。
// 創(chuàng)建 HashMap 對象 Sites HashMap<Integer, String> Sites = new HashMap<Integer, String>(); // 添加鍵值對 Sites.put(1, "Google"); Sites.put(2, "Runoob"); Sites.put(3, "Taobao"); Sites.put(4, "Zhihu"); //讀取 String val = Sites.get(1);//得到Google
為什么說可以用HashMap來改進性能呢?原因不是說HashMap這種數(shù)據(jù)結構存儲性能就比其他的,比如數(shù)組,集合先進多少。我主要看中的,是在知道Key的情況下,找到相應值得速度非常快。如果是用數(shù)組,最簡單的,用循環(huán);講究一點,排好序,用折半查找(二分查找)。都比不上用Key在HashMap里直接讀取。不知道為什么HashMap在查找方面為啥這么快,估計是存儲結構,使用了啥樹,并為Key建立了索引。這是另外一個課題,以后再了解。昨天,我只是利用了這個特性,將運行幾個小時都沒結束的問題,只耗費了十幾秒。
問題如下:
有25萬條記錄,每條記錄含經(jīng)緯度;存在不同記錄坐標相同情況。現(xiàn)在想將坐標相同的記錄歸并在一起。
如果數(shù)據(jù)是保存在數(shù)據(jù)庫里,那么用SQL進行坐標分組,應該能解決問題。然而并沒有數(shù)據(jù)庫,數(shù)據(jù)是從gdb文件里讀出來的。
好吧,將數(shù)據(jù)保存到數(shù)組里,再新建一個集合;然后循環(huán)數(shù)組,與新集合中的記錄逐個比較,坐標相同就歸并到新集合,不同就插入新集合。最簡單了。結果2個小時過去了,還沒有結束的跡象。
想想也對,新集合越來越大,比較的次數(shù)也越來越多,仿佛棋盤里的大米一樣,每格的大米數(shù)量是前一格的兩倍;最后即使是整個國家糧庫的大米都放進去,都填不滿整個棋盤。
將25萬條記錄先排好序再處理?單是排序就忙死了,不行吧。
將25萬條記錄先保存到數(shù)據(jù)庫里,再分組?應該也可以,但總覺得笨了一些,而且速度應該也是以分鐘算的。
最后決定用HashMap來做這個新集合。
如上所述,HashMap按照Key來寫入或讀取值。關鍵是這個Key怎么得來。上面的例子,是寫代碼的人自己給出了一些字符作為Key。而在我們項目中,可以用經(jīng)緯度之和的哈希值來作為Key。哈希值相同的,就認為是經(jīng)緯度相同,只需要判斷新集合中,是否存在這個Key對應的元素就可以了,根本無須循環(huán)比較。
由于存在兩個不同的經(jīng)緯度加起來,結果是一樣的可能性,因此先將經(jīng)度 乘以1000,再加緯度,這樣基本杜絕沖突的機會。
代碼如下:
private HashMap<Long,SimpleItem> recGeo(HashMap<Long, SimpleItem> map,String geo,int j){
/*
將相同坐標的記錄合成一條
HashMap<Long, SimpleItem> map, 新集合
String geo, 坐標字符串
int j 記錄ID
*/
try {
Point p = (Point)reader.read(geo);
/*
計算哈希值
因為如果采用循環(huán)來比較,數(shù)據(jù)量太大,速度太慢了
為避免不同坐標出現(xiàn)經(jīng)度+緯度結果相同的情況,將經(jīng)度 * 1000再相加
*/
//計算Key
long k = Long.valueOf(Double.doubleToLongBits(p.getX() * 1000 + p.getY())).hashCode();
SimpleItem si = map.get(k);
if(si != null){//新集合中該Key對應元素已存在,應該是相同坐標的記錄
si.getPointers().add(j);//歸并
} else {//否則插入
si = new SimpleItem();
si.setGeo(geo);
List<Integer> pointers = new ArrayList();
pointers.add(j);
si.setPointers(pointers);
map.put(k,si);
}
} catch (ParseException e) {
e.printStackTrace();
}
return map;
}
private static GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
private static WKTReader reader = new WKTReader( geometryFactory );
class SimpleItem{
private Point geo;
private List<Integer> pointers;
public Point getGeo() {
return geo;
}
public void setGeo(String geo) {
try {
this.geo = (Point)reader.read(geo);
} catch (ParseException e) {
e.printStackTrace();
}
}
public List<Integer> getPointers() {
return pointers;
}
public void setPointers(List<Integer> pointers) {
this.pointers = pointers;
}
}
短短幾秒,新集合即得到5萬個元素。
以上就是Java中使用HashMap改進查找性能的步驟的詳細內(nèi)容,更多關于Java HashMap改進查找性能的資料請關注腳本之家其它相關文章!
相關文章
SpringBoot使用Prometheus采集自定義指標數(shù)據(jù)的方法詳解
隨著微服務在生產(chǎn)環(huán)境大規(guī)模部署和應用,隨之而來也帶來了新的問題,其中比較關鍵的就是關于微服務的運維和監(jiān)控,本文將結合微服務運維監(jiān)控中的指標監(jiān)控進行詳細的說明,需要的朋友可以參考下2024-07-07
基于SpringBoot應用監(jiān)控Actuator安全隱患及解決方式
這篇文章主要介紹了SpringBoot應用監(jiān)控Actuator安全隱患及解決方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
詳解Java多線程編程中LockSupport類的線程阻塞用法
LockSupport類提供了park()和unpark()兩個方法來實現(xiàn)線程的阻塞和喚醒,下面我們就來詳解Java多線程編程中LockSupport類的線程阻塞用法:2016-07-07
springboot使用線程池(ThreadPoolTaskExecutor)示例
大家好,本篇文章主要講的是springboot使用線程池(ThreadPoolTaskExecutor)示例,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12

