基於GEOHASH演算法的附近點搜尋實現(一)

2021-08-21 07:41:09 字數 2583 閱讀 9770

最近在參加學校的計算機**大賽,時間好像有點不夠,所以只完成了前面的一部分最基礎的功能,中途還是選擇了放棄。但是之前的部分的確覺得完成得還不錯,在這裡分享一下。題目是要完成乙個宇宙飛船加油點的分配排程系統。完成的部分是給定座標附近點的搜尋。

我們要完成的乙個是二維附近點搜尋的演算法。就是在給出若干個加油點的二維座標,然後再給你乙個當前座標,你要搜尋出距離當前座標最近的乙個加油站的座標點。在考慮二維的附近點搜尋時,最原始的方法肯定是將所有的加油點的座標都加入到list中.然後遍歷所有的節點,判斷哪個節點的座標距離自己最近。但是這樣操作的話,由於我們要進行多次的附近點搜尋,這樣每次搜尋的成本就會相當大,比如我們搜尋 n次,一共有 m 個加油點,複雜度將達到 n*m ,降低搜尋效率。

所以我們應該降低每次的搜尋效率。然後想過要使用建立雜湊表進行搜尋,這樣成本基本花在了建表上,搜尋所花費的時間就會少很多。但是按照自己的想法,去建乙個雜湊表的確比較困難,而且當地圖比較大時,空間複雜度會十分的高,因此這種方法還是需要改進。然後我查閱了一些資料,參閱到一些附近點搜尋的經典演算法,也就是將要介紹的geohash演算法。能夠將座標變成特定的編碼,然後進行對應雜湊,還能夠根據編碼的字首,來進行判斷兩點是否在附近。

此部落格中,簡要地說明geohash演算法的思想:

將地圖四分,也就是分成左上、右上、左下、右下四個部分,然後對應的地圖塊的編碼後面追加"01","11","00","10"

|01|11|

|---|---|

|00|10|

然後再將四分後的各個地圖塊,重複步驟1,不斷地進行四分,編碼也會兩位兩位地進行增加。直到地圖塊不能再進行四分。

得到對應的每個座標的編碼。

這就是geohash最基礎的演算法,能夠將地圖上的每個座標點都進行編碼。然後根據這些編碼,很快就可以發現乙個規律,因為是按著每個地圖4分的,所以這地圖四分前的編碼是相同的,即使4分之後,這4塊地圖還是有著相同的字首,因此,我們可以根據編碼的最長相同字首,去找出距離最近的加油站的座標。

但是!這個演算法還是有很大的缺點的:

由於geohash是將區域劃分為乙個個規則矩形,並對每個矩形進行編碼,會導致以下問題,比如紅色的點是我們的位置,綠色的兩個點分別是附近的兩加油點,但是在查詢的時候會發現距離較遠加油站的geohash編碼與我們一樣(因為在同乙個geohash區域塊上),而較近加油站的geohash編碼與我們不一致。這個問題往往產生在邊界處。

因此,我們需要對演算法進行改進,解決的思路很簡單,我們查詢時,除了使用定位點的geohash編碼進行匹配外,還使用周圍8個區域的geohash編碼,這樣可以避免這個問題。

座標值轉化為geohash編碼值

根據當前區域的geohash,推算出周圍8個方位區域塊的的geohash值。

將這8個區域塊中所有加油點進行儲存,並且一一計算它們到當前座標的距離,並且計算出最短距離的點。

考慮儲存結構,以及演算法實現。

因為專案開發的時候要視覺化,所以當時就選擇了使用c#。接下來的實現**,都是c#編寫的。

首先我們要知道當前地圖大小為多少,取橫座標、縱座標的中值,然後區分出4個區域,然後按照座標所落到的區域,將對應的兩位編號追加到地圖的編碼後,然後再將當前地圖橫座標、縱座標、都除以二,加上根據分塊後地圖改變的編號,以及座標改變值,作為引數繼續遞迴。遞迴結束的條件為地圖的精度都已經減少為1的座標的。

以下為實現**:

//xb,yb分別為地圖的橫座標和總座標大小

//a,b,分別為給定點的橫座標、以及縱座標

//code,為儲存編碼的字串

public

static

void encode(stringbuilder code, int xb, int yb, int a, int b)

else

if (a < xb / 2 && b >= yb /

2)

else

if (a >= xb / 2 && b < yb /

2)

else

if (a >= xb / 2 && b >= yb /

2)

return;

}

public static void findright(stringbuilder code, int

len)

else

return;

}public static void findleft(stringbuilder code, int

len)

else

return;

}public static void finddown(stringbuilder code, int

len)

else

return;

} public static void findup(stringbuilder code, int

len)

else

return;

}

GeoHash演算法獲取附近店鋪和距離

geohash演算法將二維經緯度座標直接轉換成字串,每乙個字串代表乙個矩形區域,也就是說,這個矩形區域內所有的點 經緯度座標 都共享相同的geohash字串,字串的長度越大,矩形的區域就越小,經度也就越高。字串相似的表示距離相近,這樣可以利用字串的字首匹配來查詢附近的poi資訊。地球緯度區間是 90...

geohash的應用 附近位址搜尋

url 簡單使用 geohash,redis,bottle,python geohash 來實現 restful api的地理位置附近人搜素 依賴的redis封裝class import redis class redis object pool none r none def init self,...

GeoHash演算法的學習

將二維的經度緯度轉化成字串 字串越長代表的精度越高 5位的編碼能表示10平方千公尺,而6位的編碼約0.34平方千公尺 字串的相似表示距離的遠近。查詢指定位置的附近的商店等,只需要將所在位置的經緯度轉化為geohash字串,並於各個商店的geohash字串進行字首匹配,匹配越多的越接近 地球緯度區間是...