hash_map分析

最近一直在使用hash_map,找時間來梳理一下html

 

幾句話道出map和hash_map的區別ios

1. STL map is an associative array where keys are stored in sorted order using balanced trees. While hash_map is a hashed associated container, where keys are not stored in an ordered way. Key, value pair is stored using a hashed function.
2. Insertion and lookup takes Ologn time in map, Also performance would degrade as the key size increases. Mainly balance operations on large key ranges would kill performance. while lookup is very efficient O(1) in hash_map.
3. Map is useful where you want to store keys in sorted order, hash_map is used where keys order is not important and lookup is very efficient.
4. One more difference is map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators.
Performance would mostly be o(lgn) due to the implementation of a balanced tree.
For Map custom objects you would need at the minimum the following operators to store data in a map "<" ">" "==" and of course the other stuff for deep copy.c++

原文地址:http://stlchina.huhoo.net/twiki/bin/view.pl/Main/STLDetailHashMap編程

    • 0 爲何須要hash_map
    • 1 數據結構:hash_map原理
    • 2 hash_map 使用
      • 2.1 一個簡單實例
      • 2.2 hash_map 的hash函數
      • 2.3 hash_map 的比較函數
      • 2.4 hash_map 函數
    • 3 相關hash容器
    • 4 其餘
      • 4.1 hash_map和map的區別在哪裏?
      • 4.2 何時須要用hash_map,何時須要用map?
      • 4.3 如何在hash_map中加入本身定義的類型?
      • 4.4 如何用hash_map替換程序中已有的map容器?
      • 4.5 爲何hash_map不是標準的?
      • 4.6 有學習使用hash_map的建議嗎?
    • 5 參考文章:

條條大路通羅馬,爲何你不隨便選一條?數組

0 爲何須要hash_map
用過map吧?map提供一個很經常使用的功能,那就是提供key-value的存儲和查找功能。例如,我要記錄一我的名和相應的存儲,並且隨時增長,要快速 查找和修改:
嶽不羣-華山派掌門人,人稱君子劍
張三丰-武當掌門人,太極拳創始人
東方不敗-第一高手,葵花寶典
...

這些信息若是保存下來並不複雜,可是找起來比較麻煩。例如我要找"張三丰"的信息,最傻的方法就是取得全部的記錄,而後按照名字一個一個比較。 若是要速度快,就須要把這些記錄按照字母順序排列,而後按照二分法查找。可是增長記錄的時候同時須要保持記錄有序,所以須要插入排序。考慮到效率,這就需 要用到二叉樹。講下去會沒完沒了,若是你使用STL 的map容器,你能夠很是方便的實現這個功能,而不用關心其細節。關於map的數據結構細節,感興趣的朋友能夠參看學習STL map, STL set之數據結構基礎。 看看map的實現: bash

#include <map>
#include <string>
using namespace std;
...
map<string, string> namemap;

//增長。。。
namemap["嶽不羣"]="華山派掌門人,人稱君子劍";
namemap["張三丰"]="武當掌門人,太極拳創始人";
namemap["東方不敗"]="第一高手,葵花寶典";
...

//查找。。
if(namemap.find("嶽不羣") != namemap.end()){
        ...
}

不以爲用起來很easy嗎?並且效率很高,100萬條記錄,最多也只要20次的string.compare的比較,就能找到你要找的記錄;200萬條記 錄事,也只要用21次的比較。 數據結構

速度永遠都知足不了現實的需求。若是有100萬條記錄,我須要頻繁進行搜索時,20次比較也會成爲瓶頸,要是能降到一次或者兩次比較是否有可能?並且當記 錄數到200萬的時候也是一次或者兩次的比較,是否有可能?並且還須要和map同樣的方便使用。 less

答案是確定的。這時你須要has_map. 雖然hash_map目前並無歸入C++ 標準模板庫中,但幾乎每一個版本的STL都提供了相應的實現。並且應用十分普遍。在正式使用hash_map以前,先看看hash_map的原理。 函數

1 數據結構:hash_map原理
這是一節讓你深刻理解hash_map的介紹,若是你只是想囫圇吞棗,不想理解其原理,你卻是能夠略過這一節,但我仍是建議你看看,多瞭解一些沒有壞處。

hash_map基於hash table(哈希表)。哈希表最大的優勢,就是把數據的存儲和查找消耗的時間大大下降,幾乎能夠當作是常數時間;而代價僅僅是消耗比較多的內存。然而在當 前可利用內存愈來愈多的狀況下,用空間換時間的作法是值得的。另外,編碼比較容易也是它的特色之一。 post

其基本原理是:使用一個下標範圍比較大的數組來存儲元素。能夠設計一個函數(哈希函數,也叫作散列函數),使得每一個元素的關鍵字都與一個函數值 (即數組下標,hash值)相對應,因而用這個數組單元來存儲這個元素;也能夠簡單的理解爲,按照關鍵字爲每個元素「分類」,而後將這個元素存儲在相應 「類」所對應的地方,稱爲桶。

可是,不可以保證每一個元素的關鍵字與函數值是一一對應的,所以極有可能出現對於不一樣的元素,卻計算出了相同的函數值,這樣就產生了「衝突」,換句話說,就 是把不一樣的元素分在了相同的「類」之中。 總的來講,「直接定址」與「解決衝突」是哈希表的兩大特色。

hash_map,首先分配一大片內存,造成許多桶。是利用hash函數,對key進行映射到不一樣區域(桶)進行保存。其插入過程是:

  1. 獲得key
  2. 經過hash函數獲得hash值
  3. 獲得桶號(通常都爲hash值對桶數求模)
  4. 存放key和value在桶內。
其取值過程是:
  1. 獲得key
  2. 經過hash函數獲得hash值
  3. 獲得桶號(通常都爲hash值對桶數求模)
  4. 比較桶的內部元素是否與key相等,若都不相等,則沒有找到。
  5. 取出相等的記錄的value。
hash_map中直接地址用hash函數生成,解決衝突,用比較函數解決。這裏能夠看出,若是每一個桶內部只有一個元素,那麼查找的時候只有一次比較。當 許多桶內沒有值時,許多查詢就會更快了(指查不到的時候).

因而可知,要實現哈希表, 和用戶相關的是:hash函數和比較函數。這兩個參數恰好是咱們在使用hash_map時須要指定的參數。

2 hash_map 使用
2.1 一個簡單實例 不要着急如何把"嶽不羣"用hash_map表示,咱們先看一個簡單的例子:隨機給你一個ID號和ID號相應的信息,ID號的範圍是1~2的31次方。如 何快速保存查找。
#include <hash_map>
#include <string>
using namespace std;
int main(){
        hash_map<int, string> mymap;
        mymap[9527]="唐伯虎點秋香";
        mymap[1000000]="百萬富翁的生活";
        mymap[10000]="白領的工資底線";
        ...
        if(mymap.find(10000) != mymap.end()){
                ...
        }

夠簡單,和map使用方法同樣。這時你或許會問?hash函數和比較函數呢?不是要指定麼?你說對了,可是在你沒有指定hash函數和比較函數的時候,你 會有一個缺省的函數,看看hash_map的聲明,你會更加明白。下面是SGI STL的聲明:

template <class _Key, class _Tp, class _HashFcn = hash<_Key>,
class _EqualKey = equal_to<_Key>,
class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class hash_map
{
        ...
}

也就是說,在上例中,有如下等同關係:

...
hash_map<int, string> mymap;
//等同於:
hash_map<int, string, hash<int>, equal_to<int> > mymap;

Alloc咱們就不要取關注太多了(但願深刻了解Allocator的朋友能夠參看標準庫 STL :Allocator能作什麼)

2.2 hash_map 的hash函數 hash< int>究竟是什麼樣子?看看源碼:
struct hash<int> {
        size_t operator()(int __x) const { return __x; }
};

原來是個函數對象。在SGI STL中,提供瞭如下hash函數:

struct hash<char*>
struct hash<const char*>
struct hash<char> 
struct hash<unsigned char> 
struct hash<signed char>
struct hash<short>
struct hash<unsigned short> 
struct hash<int> 
struct hash<unsigned int>
struct hash<long> 
struct hash<unsigned long> 

也就是說,若是你的key使用的是以上類型中的一種,你均可以使用缺省的hash函數。固然你本身也能夠定義本身的hash函數。對於自定義變量,你只能 如此,例如對於string,就必須自定義hash函數。例如:

struct str_hash{
        size_t operator()(const string& str) const
        {
                unsigned long __h = 0;
                for (size_t i = 0 ; i < str.size() ; i ++)
                __h = 5*__h + str[i];
                return size_t(__h);
        }
};
//若是你但願利用系統定義的字符串hash函數,你能夠這樣寫:
struct str_hash{
        size_t operator()(const string& str) const
        {
                return __stl_hash_string(str.c_str());
        }
};

在聲明本身的哈希函數時要注意如下幾點:

  1. 使用struct,而後重載operator().
  2. 返回是size_t
  3. 參數是你要hash的key的類型。
  4. 函數是const類型的。
若是這些比較難記,最簡單的方法就是照貓畫虎,找一個函數改改就是了。

如今能夠對開頭的"嶽不羣"進行哈希化了 smile . 直接替換成下面的聲明便可:

map<string, string> namemap; 
//改成:
hash_map<string, string, str_hash> namemap;

其餘用法都不用邊。固然不要忘了吧str_hash的聲明以及頭文件改成hash_map。

你或許會問:比較函數呢?彆着急,這裏就開始介紹hash_map中的比較函數。

2.3 hash_map 的比較函數 在map中的比較函數,須要提供less函數。若是沒有提供,缺省的也是less< Key> 。在hash_map中,要比較桶內的數據和key是否相等,所以須要的是是否等於的函數:equal_to< Key> 。先看看equal_to的源碼:
//本代碼能夠從SGI STL
//先看看binary_function 函數聲明,其實只是定義一些類型而已。
template <class _Arg1, class _Arg2, class _Result>
struct binary_function {
        typedef _Arg1 first_argument_type;
        typedef _Arg2 second_argument_type;
        typedef _Result result_type;
};
//看看equal_to的定義:
template <class _Tp>
struct equal_to : public binary_function<_Tp,_Tp,bool>
{
        bool operator()(const _Tp& __x, const _Tp& __y) const { return __x == __y; }
};

若是你使用一個自定義的數據類型,如struct mystruct, 或者const char* 的字符串,如何使用比較函數?使用比較函數,有兩種方法. 第一種是:重載==操做符,利用equal_to;看看下面的例子:

struct mystruct{
        int iID;
        int  len;
        bool operator==(const mystruct & my) const{
                return (iID==my.iID) && (len==my.len) ;
        }
};  

這樣,就可使用equal_to< mystruct>做爲比較函數了。另外一種方法就是使用函數對象。自定義一個比較函數體:

struct compare_str{
        bool operator()(const char* p1, const char*p2) const{
                return strcmp(p1,p2)==0;
        }
};  

有了compare_str,就可使用hash_map了。

typedef hash_map<const char*, string, hash<const char*>, compare_str> StrIntMap;
StrIntMap namemap;
namemap["嶽不羣"]="華山派掌門人,人稱君子劍";
namemap["張三丰"]="武當掌門人,太極拳創始人";
namemap["東方不敗"]="第一高手,葵花寶典";
2.4 hash_map 函數 hash_map的函數和map的函數差很少。具體函數的參數和解釋,請參看: STL 編程手冊:Hash_map,這裏主要介紹幾個經常使用函數。
  1. hash_map(size_type n) 若是講究效率,這個參數是必需要設置的。n 主要用來設置hash_map 容器中hash桶的個數。桶個數越多,hash函數發生衝突的機率就越小,從新申請內存的機率就越小。n越大,效率越高,可是內存消耗也越大。
  2. const_iterator find(const key_type& k) const. 用查找,輸入爲鍵值,返回爲迭代器。
  3. data_type& operator[](const key_type& k) . 這是我最經常使用的一個函數。由於其特別方便,可像使用數組同樣使用。不過須要注意的是,當你使用[key ]操做符時,若是容器中沒有key元素,這就至關於自動增長了一個key元素。所以當你只是想知道容器中是否有key元素時,你可使用find。若是你 但願插入該元素時,你能夠直接使用[]操做符。
  4. insert 函數。在容器中不包含key值時,insert函數和[]操做符的功能差很少。可是當容器中元素愈來愈多,每一個桶中的元素會增長,爲了保證效 率,hash_map會自動申請更大的內存,以生成更多的桶。所以在insert之後,之前的iterator有多是不可用的。
  5. erase 函數。在insert的過程當中,當每一個桶的元素太多時,hash_map可能會自動擴充容器的內存。但在sgi stl中是erase並不自動回收內存。所以你調用erase後,其餘元素的iterator仍是可用的。
3 相關hash容器
hash 容器除了hash_map以外,還有hash_set, hash_multimap, has_multiset, 這些容器使用起來和set, multimap, multiset的區別與hash_map和map的區別同樣,我想不須要我一一細說了吧。
4 其餘
這裏列幾個常見問題,應該對你理解和使用hash_map比較有幫助。 4.1 hash_map和map的區別在哪裏?
  • 構造函數。hash_map須要hash函數,等於函數;map只須要比較函數(小於函數).
  • 存儲結構。hash_map採用hash表存儲,map通常採用紅黑樹(RB Tree)實現。所以其memory數據結構是不同的。
4.2 何時須要用hash_map,何時須要用map? 整體來講,hash_map 查找速度會比map快,並且查找速度基本和數據數據量大小,屬於常數級別;而map的查找速度是log(n)級別。並不必定常數就比log(n) 小,hash還有hash函數的耗時,明白了吧,若是你考慮效率,特別是在元素達到必定數量級時,考慮考慮hash_map。但若你對內存使用特別嚴格, 但願程序儘量少消耗內存,那麼必定要當心,hash_map可能會讓你陷入尷尬,特別是當你的hash_map對象特別多時,你就更沒法控制了,並且 hash_map的構造速度較慢。

如今知道如何選擇了嗎?權衡三個因素: 查找速度, 數據量, 內存使用。

這裏還有個關於hash_map和map的小故事,看看:http://dev.csdn.net/Develop/article/14/14019.shtm

4.3 如何在hash_map中加入本身定義的類型? 你只要作兩件事, 定義hash函數,定義等於比較函數。下面的代碼是一個例子:
-bash-2.05b$ cat my.cpp
#include <hash_map>
#include <string>
#include <iostream>

using namespace std;
//define the class
class ClassA{
        public:
        ClassA(int a):c_a(a){}
        int getvalue()const { return c_a;}
        void setvalue(int a){c_a;}
        private:
        int c_a;
};

//1 define the hash function
struct hash_A{
        size_t operator()(const class ClassA & A)const{
                //  return  hash<int>(classA.getvalue());
                return A.getvalue();
        }
};

//2 define the equal function
struct equal_A{
        bool operator()(const class ClassA & a1, const class ClassA & a2)const{
                return  a1.getvalue() == a2.getvalue();
        }
};

int main()
{
        hash_map<ClassA, string, hash_A, equal_A> hmap;
        ClassA a1(12);
        hmap[a1]="I am 12";
        ClassA a2(198877);
        hmap[a2]="I am 198877";
        
        cout<<hmap[a1]<<endl;
        cout<<hmap[a2]<<endl;
        return 0;
}
-bash-2.05b$ make my
c++  -O -pipe -march=pentiumpro  my.cpp  -o my
-bash-2.05b$ ./my
I am 12
I am 198877
4.4如何用hash_map替換程序中已有的map容器? 這個很容易,但須要你有良好的編程風格。建議你儘可能使用typedef來定義你的類型:
typedef map<Key, Value> KeyMap;

當你但願使用hash_map來替換的時候,只須要修改:

typedef hash_map<Key, Value> KeyMap;

其餘的基本不變。固然,你須要注意是否有Key類型的hash函數和比較函數。

4.5爲何hash_map不是標準的? 具體爲何不是標準的,我也不清楚,有個解釋說在STL加入標準C++之時,hash_map系列當時尚未徹底實現,之後應該會成爲標準。若是誰知道更 合理的解釋,也但願告訴我。但我想表達的是,正是由於hash_map不是標準的,因此許多平臺上安裝了g++編譯器,不必定有hash_map的實現。 我就遇到了這樣的例子。所以在使用這些非標準庫的時候,必定要事先測試。另外,若是考慮到平臺移植,仍是少用爲佳。

下面先保存一個例子,之後備用

// UserRefer.h: interface for the UserRefer class.
//
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/// @file  userfefer.h
///
/// @brief
///        用戶基準數據管理類,根據基準數據對位置數據進行校訂
///
/// @author bruce
/// @date 26/04/2011
///
/// @version 1.0
///
///    @details
///        用戶基準數據管理類
//////////////////////////////////////////////////////////////////////////

#if !defined(AFX_USERREFER_H__C8175704_44CD_4D5C_94E3_7DD3D4A0BB9D__INCLUDED_)
#define AFX_USERREFER_H__C8175704_44CD_4D5C_94E3_7DD3D4A0BB9D__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <winbase.h>
#include <hash_map>
#include <list>
#include <algorithm> 
#include <string>
#include <iostream>
#include "Protocol.h"
using namespace std;
///hashmap 比較函數
struct equal_string_
{
    bool operator()(const string & a1, const  string & a2) const
    {
        return a1==a2 ;
    }
};
///hashmap hash函數
struct hash_string_
{
    size_t operator()(const string & A)const
    {
        return __stl_hash_string(A.c_str());
    }
};


///hash表,包含mcuid和基準信息
typedef hash_map<string,UserReferStruct* ,hash_string_, equal_string_> hmapUser;//用戶基準信息表
typedef hmapUser::iterator itrdUser;

//用戶基準信息類,用戶經過mcuid作爲檢索的條件,對用戶基準信息進行增長,查詢,修改。
class UserRefer 
{
private:
    CRITICAL_SECTION m_Section;
    hmapUser UserReferList;

    UserRefer(const UserRefer&);
    void operator =(const UserRefer&);

public:
    UserRefer();
    virtual ~UserRefer();

private:
     ///添加基準信息
    void AddRefer(string strMcuid,UserReferStruct*);

    ///刪除基準信息
    void DeleteRefer(string strMcuid);
   
    ///清理用戶基準信息
    void DeleteAllRefer();

    ///修改基準信息
    void UpdateDataRefer(string strMcuid,UserReferStruct* );

    ///hash表保護
    void InterLock();

    void LeaveLock();

    ///獲得hash表指針
    hmapUser* GetUserReferMap();

    ///獲得hash表長
    int GetUserReferSize();

    ///根據mcuid獲取基準信息
    UserReferStruct*  GetDataRefer(string strMcuid);
   
        //檢測經經度範圍
    int inline CheckGpsLon(const double dbLon)
    {
        if(dbLon>= 73.66667 && dbLon <= 135.04167)
        {
            return 0;
        }
        else
        {
            return -1;
        }
    };
   
    //檢測經緯度範圍
    int inline CheckGpsLat(const double dbLat)
    {
        if(dbLat >= 3.86667 && dbLat <= 53.55)
        {
            return 0;
        }
        else
        {
            return -1;
        }
    };

    //檢測數據是否在浙江

    int inline CheckZJGps(const double dbLon, const double dbLat)
    {

    };

    double inline rad(double d)
    {
        const double PI = 3.1415926535898;
        return d * PI / 180.0;
     };

    //計算兩點之間的距離
    int CalcDistance(double fLati1, double fLong1, double fLati2, double fLong2);

    //在全局基準表中增長基準信息
    int AddUserRefer(UserReferStruct *pUserTmp, char  *pszMcuid, char* pszSim, double dbLon, double dbLat, char* pszTime, int nType);


    //更新基準信息
    int UpdateRefer(UserReferStruct *pRefer, char* pszSim, double dbLon, double dbLat, char* pszTime, int nType);

    //更新基準信息,並返回可用數據
    //0 :當前位置信息可用
    //-2 當前位置信息不可用
    int UpdataCidGpsData(UserReferStruct *pRefer, char* pszSim, double dbLon, double dbLat, char* pszTime, int nType, double *pRtnLon, double *pRtnLat);


    //對2D位置數據進行處理, 不修改基準信息
    int Updata2DGpsData(UserReferStruct *pRefer, char* pszSim, double dbLon, double dbLat, char* pszTime, int nType, double dbCidLon,
                                  double dbCidLat, double *pRtnLon, double *pRtnLat);

    int UserRefer::Updata3DGpsData(UserReferStruct *pRefer, char* pszSim, double dbLon, double dbLat, char* pszTime,
                                int nType, double *pRtnLon, double *pRtnLat);


public:
    //位置檢驗
    int AuthGpsData(char* pszMcuid,            //mcuid
                    char* pszSim,            //電話號碼
                    double dbLon,            //gps經度
                    double dbLat,            //gps緯度
                    char* pszTime,            //gps時間
                    int nType,                //gps定位類型
                    double dbCidLon,        //基站轉換的經度
                    double dbCidLat,        //基站轉換的緯度
                    double *pRtnLon,        //校驗後的經度
                    double *pRtnLat);        //校驗後的緯度




};

#endif // !defined(AFX_USERREFER_H__C8175704_44CD_4D5C_94E3_7DD3D4A0BB9D__INCLUDED_)

// UserRefer.cpp: implementation of the UserRefer class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "UserRefer.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// #define CK_MIN(a,b) ((a)<(b)?(a):(b)) #define CK_MAX(a,b) ((a)>(b)?(a):(b)) #define CK_DIS (2) #define CK_3DIS (3) #define CK_ZERO (0.000001) #define CK_SUCCESS  (0) typedef enum {     GPS_HIS = 0,     GPS_CID,     GPS_2D,     GPS_3D, }GPS_TYPE; UserRefer::UserRefer() {     InitializeCriticalSection(&m_Section); } UserRefer::~UserRefer() {         DeleteAllRefer();     DeleteCriticalSection(&m_Section); } //清理結點 void UserRefer::DeleteAllRefer() {     itrdUser iter, itertemp;     EnterCriticalSection(&m_Section);     for(  iter = UserReferList.begin();iter!=UserReferList.end();)     {         itertemp = iter++; //先保存下一個節點                 UserReferStruct *pUser = (UserReferStruct*)(itertemp->second);         if(pUser != NULL)         {             free(pUser) ;             pUser = NULL;         }         UserReferList.erase(itertemp);     }     UserReferList.clear();     LeaveCriticalSection(&m_Section); } ///在hash表中根據mcuid增長基準信息 void UserRefer::AddRefer(string strMcuid,UserReferStruct *data) {     EnterCriticalSection(&m_Section);     UserReferList[strMcuid]=data;     LeaveCriticalSection(&m_Section); } //在hash表中根據mcuid刪除基準信息 void UserRefer::DeleteRefer(string strMcuid) {     EnterCriticalSection(&m_Section);     UserReferList.erase(strMcuid);     LeaveCriticalSection(&m_Section); } //根據mcuid獲取基準信息 UserReferStruct*  UserRefer::GetDataRefer(string strMcuid) {     UserReferStruct* temp = NULL;     EnterCriticalSection(&m_Section);     temp =UserReferList[strMcuid];     LeaveCriticalSection(&m_Section);     return temp; } //根據mcuid重設基準信息 void UserRefer::UpdateDataRefer(string strMcuid, UserReferStruct* pUserRefer) {     EnterCriticalSection(&m_Section);     UserReferList[strMcuid] = pUserRefer;     LeaveCriticalSection(&m_Section); } void UserRefer::InterLock() {     EnterCriticalSection(&m_Section); } void UserRefer::LeaveLock() {     LeaveCriticalSection(&m_Section); } //獲取整個hash表 hmapUser* UserRefer::GetUserReferMap() {       return &UserReferList; } //獲取hash表的大小 int UserRefer::GetUserReferSize() {     int len;     EnterCriticalSection(&m_Section);     len= UserReferList.size();     LeaveCriticalSection(&m_Section);     return len; } //計算兩點之間的距離,返回單位(KM) int UserRefer::CalcDistance(double fLati1, double fLong1, double fLati2, double fLong2) {   const double EARTH_RADIUS = 6378.137;   long lDis = 0;   double radLat1 = rad(fLati1);   double radLat2 = rad(fLati2);   double a = radLat1 - radLat2;   double b = rad(fLong1) - rad(fLong2);   double s = 2 * asin(sqrt(pow(sin(a/2),2) + cos(radLat1)*cos(radLat2)*pow(sin(b/2),2)));   s = s * EARTH_RADIUS;   s = (int)(s*10000) / 10000;   return (int)s; } ////////////////////////////////////////////////////////////// //在全局基準表中增長基準信息 int UserRefer::AddUserRefer(UserReferStruct *pUserTmp, char  *pszMcuid, char* pszSim, double dbLon, double dbLat, char* pszTime, int nType) {     if(NULL == pszMcuid || NULL == pszSim || NULL == pszTime)     {         return -1;     }     //新建一個結點     pUserTmp = (UserReferStruct*)malloc(sizeof(UserReferStruct));     memset(pUserTmp, 0, sizeof(UserReferStruct));     pUserTmp->dbLat = dbLat;     pUserTmp->dbLon = dbLon;     pUserTmp->nType = nType;     ///時間     memset(pUserTmp->szTime, 0, sizeof(pUserTmp->szTime));     memcpy(&pUserTmp->szTime[0], pszTime, CK_MIN(strlen(pszTime), sizeof(pUserTmp->szTime)));     ///mcuid     memset(pUserTmp->szMcuid, 0, sizeof(pUserTmp->szMcuid));     memcpy(&pUserTmp->szMcuid[0], pszMcuid, CK_MIN(strlen(pszMcuid), sizeof(pUserTmp->szMcuid)));     ///電話號碼     memset(pUserTmp->szTel, 0, sizeof(pUserTmp->szTel));     memcpy(&pUserTmp->szTel[0], pszSim, CK_MIN(strlen(pszSim), sizeof(pUserTmp->szTel)));         ///增長基準信息     std::string strMcuid(pszMcuid);     AddRefer(strMcuid, pUserTmp);     return 0; } //更新基準信息 int UserRefer::UpdateRefer(UserReferStruct *pRefer, char* pszSim, double dbLon, double dbLat, char* pszTime, int nType) {     if(NULL == pRefer || NULL == pszTime || NULL == pszSim)     {         return -1;     }     pRefer->dbLat = dbLat;     pRefer->dbLon = dbLon;     pRefer->nType = nType;     //更新時間     memset(pRefer->szTime, 0, sizeof(pRefer->szMcuid));     memcpy(&pRefer->szTime[0], pszTime, CK_MIN(strlen(pszTime), sizeof(pRefer->szTime)));     //更新電話號碼     memset(pRefer->szTel, 0, sizeof(pRefer->szTel));     memcpy(&pRefer->szTel[0], pszSim, CK_MIN(strlen(pszSim), sizeof(pRefer->szTel)));     return 0; } //當前終端的數據爲3D數據 //更新基準信息,並返回可用數據 int UserRefer::Updata3DGpsData(UserReferStruct *pRefer, char* pszSim, double dbLon, double dbLat, char* pszTime,                                 int nType, double *pRtnLon, double *pRtnLat) {     if(NULL == pRefer || NULL == pszTime || NULL == pszSim || NULL == pRtnLon || NULL == pRtnLat)     {         return -1;     }     else     {         if(CK_SUCCESS == CheckGpsLon(dbLon) && CK_SUCCESS == CheckGpsLat(dbLat))// 有效的基站數據         {             //更新基準信息             UpdateRefer(pRefer, pszSim, dbLon, dbLat, pszTime, nType);             //採用基站數據             *pRtnLon = dbLon;             *pRtnLat = dbLat;                            return 0;         }         else         {             ///採用基準信息             *pRtnLon = pRefer->dbLon;             *pRtnLat = pRefer->dbLat;             return -2;         }//基站數據不合法     }     } //當前終端的數據爲基站數據 //更新基準信息,並返回可用數據 //0 :當前位置信息可用 //-2 當前位置信息不可用 int UserRefer::UpdataCidGpsData(UserReferStruct *pRefer, char* pszSim, double dbLon, double dbLat, char* pszTime,                                 int nType, double *pRtnLon, double *pRtnLat) {     if(NULL == pRefer || NULL == pszTime || NULL == pszSim || NULL == pRtnLon || NULL == pRtnLat)     {         return -1;     }         if(CK_SUCCESS == CheckGpsLon(dbLon) && CK_SUCCESS == CheckGpsLat(dbLat))// 有效的基站數據     {         if(GPS_3D == pRefer->nType) //3D基準信息         {             //比較誤差             if(CalcDistance(pRefer->dbLat, pRefer->dbLon, dbLat, dbLon) > CK_DIS) //位置確實已經修改,須要更新基準信息             {                 //更新基準信息                 UpdateRefer(pRefer, pszSim, dbLon, dbLat, pszTime, nType);                 //採用基站數據                 *pRtnLon = dbLon;                 *pRtnLat = dbLat;             }             else//小於,說明基站數據與基準在同一範圍,但基準信息能夠不修改             {                 //採用基站數據                 *pRtnLon = dbLon;                 *pRtnLat = dbLat;             }         }         else if(GPS_2D != nType)//基站基準信息         {             //更新基準信息             UpdateRefer(pRefer, pszSim, dbLon, dbLat, pszTime, nType);             //採用基站數據             *pRtnLon = dbLon;             *pRtnLat = dbLat;         }         return 0;     }     else     {         ///採用基準信息         *pRtnLon = pRefer->dbLon;         *pRtnLat = pRefer->dbLat;         return -2;     }//基站數據不合法 } //對2D位置數據進行處理, 也能夠改基準信息 int UserRefer::Updata2DGpsData(UserReferStruct *pRefer, char* pszSim, double dbLon, double dbLat, char* pszTime, int nType, double dbCidLon,                                   double dbCidLat, double *pRtnLon, double *pRtnLat) {     if(NULL == pRefer || NULL == pszSim || NULL == pszTime || NULL == pRtnLon || NULL == pRtnLat)     {         return -1;     }     if(GPS_2D == nType) //2D定位     {         if(CK_SUCCESS == CheckGpsLon(dbCidLon) && CK_SUCCESS == CheckGpsLat(dbCidLat)            && CalcDistance(dbCidLat, dbCidLon, pRefer->dbLat, pRefer->dbLon) < CK_DIS) //基站轉換的數據可用         {             if(CalcDistance(dbCidLat, dbCidLon, dbLat, dbLon) > CK_DIS)//自身的基站與經緯度比較,漂移             {                 if((GPS_3D == pRefer->nType))//說明是3D基準信息,可使用                            {                     //採用3D基準信息                     *pRtnLon = pRefer->dbLon;                     *pRtnLat = pRefer->dbLat;                 }                 else//2D或基站基準信息                 {                     //採用基站數據做爲當前位置數據,而且更新基準點                     UpdateRefer(pRefer, pszSim, dbCidLon, dbCidLat, pszTime, nType);                     //採用基站數據                     *pRtnLon = dbCidLon;                     *pRtnLat = dbCidLat;                 }             }             else//2D數據可用             {                 //採用GPS數據更新基準點                 UpdateRefer(pRefer, pszSim, dbLon, dbLat, pszTime, nType);                 *pRtnLon = dbLon;                 *pRtnLat = dbLat;             }         }         else//基站轉換後的數據不合法         {             ///2D數據與基準信息相差太遠             if(CalcDistance(pRefer->dbLat, pRefer->dbLon, dbLat, dbLon) > CK_3DIS)//2D無效,漂移             {                 //採用基準信息                 *pRtnLon = pRefer->dbLon;                 *pRtnLat = pRefer->dbLat;             }             else   //當前數據近似可用             {                 //轉發2D數據                 *pRtnLon = dbLon;                 *pRtnLat = dbLat;             }         }         return 0;     }     else //不是2D定位     {         ///採用基準信息         *pRtnLon = pRefer->dbLon;         *pRtnLat = pRefer->dbLat;         return -2;     } }  //位置檢驗 int UserRefer::AuthGpsData(char* pszMcuid, char* pszSim, double dbLon, double dbLat, char* pszTime,int nType,                 double dbCidLon,double dbCidLat, double *pRtnLon, double *pRtnLat) {     UserReferStruct *pUserTmp = NULL;     if(NULL == pszMcuid || NULL == pszSim || NULL == pszTime || NULL == pRtnLon || NULL == pRtnLat)     {         return -1;     }     std::string strMcuid(pszMcuid);     pUserTmp = GetDataRefer(strMcuid);     if(NULL == pUserTmp)  //沒有基準信息     {         if(GPS_2D != nType)  //基站或3D         {             //新增基準信息             AddUserRefer(pUserTmp, pszMcuid, pszSim, dbLon, dbLat, pszTime, nType);                    }         //採用當前數據         *pRtnLon = dbLon;         *pRtnLat = dbLat;         return 0;             }//沒有基準信息     else     {         if(GPS_3D == nType)//3D數據         {             ///更新基準信息             return Updata3DGpsData(pUserTmp, pszSim, dbLon, dbLat, pszTime, nType, pRtnLon, pRtnLat);         }         else if(GPS_2D != nType) //基站數據         {             return UpdataCidGpsData(pUserTmp, pszSim, dbLon, dbLat, pszTime, nType, pRtnLon, pRtnLat);         }         else if(GPS_2D == nType)  //2D數據         {             return Updata2DGpsData(pUserTmp, pszSim, dbLon, dbLat, pszTime, nType, dbCidLon,                                    dbCidLat, pRtnLon, pRtnLat);         }     }//有基準信息     return 0; }

相關文章
相關標籤/搜索