文章目錄
- 對雜湊表的使用者一一人來說,這是一瞬間的事。雜湊表運算得非常快,在電腦程式中,如果需要在一秒種內尋找上千條記錄通常使用雜湊表(例如拼字檢查器)雜湊表的速度明顯比樹快,樹的操作通常需要O(N)的時間級。雜湊表不僅速度快,編程實現也相對容易。
- 雜湊表也有一些缺點它是基於數組的,數組建立後難於擴充某些雜湊表被基本填滿時,效能下降得非常嚴重,所以程式雖必須要清楚表中將要儲存多少資料(或者準備好定期地把資料轉移到更大的雜湊表中,這是個費時的過程)。
- 而且,也沒有一種簡便的方法可以以任何一種順序〔例如從小到大〕遍曆表中資料項目。如果需要這種能力,就只能選擇其他資料結構。
- 然而如果不需要有序遍曆資料,井且可以提前預測資料量的大小。那麼雜湊表在速度和易用性方面是無與倫比的。
- 下面在雜湊表在SIP電話中用於儲存當前在前使用者的資訊(使用者資訊已經在初始化是儲存在全域變數的一個鏈表中,文中有說明,線上使用者需要時刻和控制台進行互動(比如通話、佔線)所有要求速度快),廢話不多說直接分析代碼吧~
雜湊表是種資料結構,它可以提供快速的插入操作和尋找操作。第一次接觸雜湊表時,它的優點多得讓人難以置信。不論雜湊表中有多少資料,插入和刪除(有時包括側除)只需要接近常量的時間即0(1)的時間級。實際上,這隻需要幾條機器指令。 對雜湊表的使用者一一人來說,這是一瞬間的事。雜湊表運算得非常快,在電腦程式中,如果需要在一秒種內尋找上千條記錄通常使用雜湊表(例如拼字檢查器)雜湊表的速度明顯比樹快,樹的操作通常需要O(N)的時間級。雜湊表不僅速度快,編程實現也相對容易。 雜湊表也有一些缺點它是基於數組的,數組建立後難於擴充某些雜湊表被基本填滿時,效能下降得非常嚴重,所以程式雖必須要清楚表中將要儲存多少資料(或者準備好定期地把資料轉移到更大的雜湊表中,這是個費時的過程)。 而且,也沒有一種簡便的方法可以以任何一種順序〔例如從小到大〕遍曆表中資料項目。如果需要這種能力,就只能選擇其他資料結構。然而如果不需要有序遍曆資料,井且可以提前預測資料量的大小。那麼雜湊表在速度和易用性方面是無與倫比的。 下面在雜湊表在SIP電話中用於儲存當前在前使用者的資訊(使用者資訊已經在初始化是儲存在全域變數的一個鏈表中,文中有說明,線上使用者需要時刻和控制台進行互動(比如通話、佔線)所有要求速度快),廢話不多說直接分析代碼吧~
標頭檔:
#ifndef _HASH_H#define _HASH_H#define OK 1#define ERROR 0#define HASH_SIZE 256typedef struct _hashNode /*採用雙向鏈表格儲存體*/{struct _hashNode * next;struct _hashNode * prev;} tHashNode;tHashNode * vSipUserLocation[ HASH_SIZE ];/*槽*/#endif
雜湊表演算法(字串處理)
int hashString (const char *str){ unsigned int h=0; int len; int i; len = strlen(str); if (len <= 0 || len > HASH_SIZE) return -1; for (i = 0; i < len; i++) { h = ( h << 5 ) - h + *(str + i); } return h % HASH_SIZE;}雜湊槽的初始化int hashInit(tHashNode **pList, unsigned int size){ if ( !pList ) return ERROR; memset(pList, '\0', size); return OK;}
插入節點int hashAddNode ( tHashNode ** pList, tHashNode * pNode, char *hash, func pCmpFunc ) { int index; tHashNode *tempNode = NULL; int ret; if ( !pList || !pNode || !hash ) return ERROR; index = hashString( hash ) ; if ( index < 0 ) return ERROR; /* 首個節點 */ tempNode = pList [ index ] ; if( !tempNode ) { pList [ index ] = pNode; pNode->next = NULL ; pNode->prev = NULL; return OK ; } /* 遍曆是否有相同的節點 函數Pcmpfunc()是比較指標是否指向相同的記憶體位址*/ if( pCmpFunc ) { for( ; tempNode != NULL ; tempNode = tempNode->next ) { if((ret = pCmpFunc(tempNode, pNode, 0)) == 0) break; } if ( ret == 0 ) return OK ; } /*為找到相同的節點,插入到第一個節點位置 */ tempNode = pList [ index ] ; pList [ index ] = pNode ; pNode->next = tempNode; pNode->prev = NULL; tempNode->prev = pNode; return OK ;} 關於插入節點中的參數應用,在代碼中調用函數如下:
typedef struct _Callee { tHashNode pNode; char name[24]; struct _Callee *next;}Callee Callee *p ;p 是指向一個全域變數 (鏈表,存放系統設定的所有使用者的資訊)中的一個節點,儲存使用者資訊(我這裡進行了修改,只顯示一部分內容)。而雜湊表存放的是當前線上使用者,當使用者註冊是需要加入雜湊表中。hashAddNode(vSipUserLocation, (tHashNode *)p, p->name, issamecallee)
下面是和別人溝通:
A:
這個問題我也遇到了,因為tSipCallee *p ,這個p指向的是儲存tSipCalle結構的記憶體位址,這個地址指向的記憶體是一塊連續的空間,比如大小是n,那麼我們可以很隨意的取這n個位元組中的一段內容,也就是說sizeof(tHashNode)<=sizeof(Callee),把n中的前m(<=n)個位元組當成tHashNode 的內容,也就是說可以把這m個位元組當成一個tHashNode結構體
但是如果sizeof(tHashNode)>sizeof(Callee),那就不行了,會造成訪問越界的情況B:定義這個結構體的時候已經包含這個 tHasgNode pNode;
太抽象了~
A:對哈,我給你畫個圖你就明白了B:看來你看得挺多了,剛開始我迷糊在(tHashNode *)p ,強制類型轉換,不就把P中前2個位元組內容覆蓋掉了!A:你看看這個結構,tSipCallee在記憶體中的存放方法,強制轉換的意思就是“我”只想使用前一段位元組:sizeof(tHashNode),後面是什麼我不管。通過data尋找節點
tHashNode * hashGetNode(tHashNode ** pList, char *hash, func pCmpFunc, void * cmpArg){ int index; tHashNode *tempNode = NULL; if ( !pList || !hash || !pCmpFunc ) return NULL; index = hashString( hash ) ; if ( index < 0 ) return NULL; tempNode = pList [ index ] ; while (tempNode ) {/*尋找參數 cmoArg是否在節點tempNode中儲存) if ( pCmpFunc ( tempNode, NULL, cmpArg ) == 0 ) { break; } tempNode = tempNode->next; } return tempNode;}
獲得當前列內容:
tHashNode * hashGetSlot(tHashNode ** pList, const char *hash ){ int index; if ( !pList || !hash ) return NULL; index = hashString( hash ); if( index < 0 ) return NULL; return pList[ index ];}
刪除節點
int hashRemoveNode(tHashNode ** pList, tHashNode * pNode, char *hash){ int index; if ( !pList || !pNode || !hash ) return ERROR ; index = hashString( hash ) ; if ( index < 0 ) return ERROR; if(!pNode->prev) { /* 第一個節點 */ pList[index] = pNode->next; if(pNode->next) pNode->next->prev = NULL; }else if ( !pNode->next ) { /* 下一個節點 */ pNode->prev->next = NULL; }else { pNode->prev->next = pNode->next; pNode->next->prev = pNode->prev; } return OK;}
雜湊表是處理大量資料中因處理速度比較快,應用非常廣泛。但是也不難理解,只有認真閱讀代碼,