C++ TrieTree(字典樹)容器的實現


最近研究了一下C++線程池,在網上看了一下別人的代碼,寫的很不錯,參見:http://www.cnblogs.com/lidabo/p/3328646.html

其中,他用了STL的set容器管理線程池中的線程,在線程池運行的過程中需要頻繁的進行插入、查找和刪除的操作,我個人覺得這些操作會是線程池中的很大的時間開銷,想起了大學老師講過的一個TireTree(字典樹)的數據結構,利用多叉樹

可以快速的實現元素的插入、查找和刪除,稍加改動也可以支持自動排序,唯一的缺點就是多叉樹的結構空間開銷較大,所以要控制好內存操作,防止內存泄露。

經測試,再插入元素和刪除元素的方面,TrieTree比set有明顯優勢,在相同的元素數量下,內存開銷也不過是set的1.5~2倍,時間卻是1/10左右。

  1 #ifndef _MY_TRIE_TREE
  2 #define _MY_TRIE_TREE
  3 
  4 template<class T,class K>
  5 class TrieTree{
  6 public:
  7     TrieTree();
  8     virtual ~TrieTree();
  9     bool insert(T *data,K key,bool overwrite = false);
 10     bool remove(K key,bool free_memory = false);
 11     bool find(K key,T *& pData);
 12 private:
 13     enum
 14     {
 15         Dimension = 10,
 16     };
 17     typedef struct tagNode 
 18     {
 19         tagNode *child[Dimension];
 20         T *data;
 21         tagNode()
 22         {
 23             for(int i = 0;i < Dimension;i++)
 24             {
 25                 child[i] = NULL;
 26             }
 27             data = NULL;
 28         }
 29         ~tagNode()
 30         {
 31             if(child == NULL)
 32             {
 33                 delete[] child;
 34             }
 35             if(data != NULL)
 36             {
 37                 delete data;
 38             }
 39         }
 40     }Node;
 41     Node *m_pHead;
 42     unsigned int m_nElementCnt;
 43     unsigned int m_nNodeCnt;
 44     void destory(Node *p_head);
 45 public:
 46     void free();
 47     void dump();
 48     void trival( Node *pNode,int &nodeCnt );
 49 };
 50 
 51 template<class T,class K>
 52 bool TrieTree<T, K>::find( K key,T *& pData )
 53 {
 54     int m = 0;
 55     Node **p_find = NULL;
 56     if(m_pHead == NULL)
 57     {
 58         return false;
 59     }
 60     p_find = &m_pHead;
 61     while( key > 0 )
 62     {
 63         m = key%10;
 64         if((*p_find) != NULL)
 65         {
 66             p_find = &(*p_find)->child[m];
 67         }
 68         else
 69         {
 70             break;
 71         }
 72         key /= 10;
 73     }
 74     if((*p_find) != NULL)
 75     {
 76         // 數據為空
 77         if((*p_find)->data == NULL)
 78         {
 79             return false;
 80         }
 81         pData = (*p_find)->data;
 82         return true;
 83     }
 84     else
 85     {
 86         return false;
 87     }
 88 }
 89 
 90 template<class T,class K>
 91 void TrieTree<T, K>::free()
 92 {
 93     destory(m_pHead);
 94 }
 95 
 96 template<class T,class K>
 97 void TrieTree<T, K>::destory( Node *p_head )
 98 {
 99     if(p_head != NULL)
100     {
101         for(int i = 0;i < Dimension;i++)
102         {
103             destory(p_head->child[i]);
104         }
105         delete p_head;
106         m_nNodeCnt--;
107     }
108 }
109 
110 
111 template<class T,class K>
112 void TrieTree<T, K>::trival( Node *pNode,int &nodeCnt )
113 {
114     if(pNode != NULL)
115     {
116         nodeCnt++;
117         if(pNode->data != NULL)
118         {
119             //cout<<*(pNode->data)<<" ";
120         }
121         for(int i = 0;i < Dimension;i++)
122         {
123             trival(pNode->child[i],nodeCnt);
124         }
125     }
126 }
127 
128 template<class T,class K>
129 void TrieTree<T, K>::dump()
130 {
131     int nodeCnt = 0;
132     trival(m_pHead,nodeCnt);
133     cout<<endl;
134     //cout<<endl<<"size = "<<sizeof(Node)<< " * "<<nodeCnt<<" = "<<sizeof(Node)*nodeCnt<<endl;
135     //cout<<endl<<"data = "<<sizeof(T)<< " * "<<m_nElementCnt<<" = "<<sizeof(T)*m_nElementCnt<<endl;
136     //cout<<endl<<"rate = "<<((double)sizeof(T) * m_nElementCnt)/(sizeof(Node)*nodeCnt)<<endl;
137     cout<<"m_nNodeCnt = "<<m_nNodeCnt;
138     cout<<",m_nElementCnt = "<<m_nElementCnt;
139     cout<<",nodeCnt = "<<nodeCnt<<endl;
140 }
141 
142 template<class T,class K>
143 TrieTree<T,K>::TrieTree()
144 {
145     m_pHead = new Node();
146     m_nElementCnt = 0;
147     m_nNodeCnt = 1;
148 }
149 
150 
151 template<class T,class K>
152 TrieTree<T,K>::~TrieTree()
153 {
154     destory(m_pHead);
155 }
156 
157 template<class T,class K>
158 bool TrieTree<T, K>::remove( K key ,bool free_memory)
159 {
160     int m = 0;
161     Node **p_find = NULL;
162     if(m_pHead == NULL)
163     {
164         return false;
165     }
166     p_find = &m_pHead;
167     while( key > 0 )
168     {
169         m = key%10;
170         if((*p_find) != NULL)
171         {
172             p_find = &(*p_find)->child[m];
173         }
174         else
175         {
176             break;
177         }
178         key /= 10;
179     }
180     if((*p_find) != NULL)
181     {
182         // 不釋放節點空間
183         if( free_memory == false )
184         {
185             if((*p_find)->data == NULL)
186             {
187                 return false;
188             }
189             delete (*p_find)->data;
190             (*p_find)->data = NULL;
191             m_nElementCnt--;
192             return true;
193         }
194         // 釋放節點空間
195         else
196         {
197             //並不是所有節點都能釋放,沒有子節點的節點才能釋放
198             bool hasChild  = false;
199             for(int i = 0;i < Dimension;i++)
200             {
201                 if((*p_find)->child[i] != NULL)
202                 {
203                     hasChild = true;
204                 }
205             }
206             // 釋放節點,直接delete
207             if(hasChild == false)
208             {
209                 delete (*p_find);
210                 (*p_find) = NULL;
211                 m_nElementCnt--;
212                 m_nNodeCnt--;
213             }
214             // 不能釋放節點,釋放data,data = NULL
215             else
216             {
217                 if((*p_find)->data == NULL)
218                 {
219                     return false;
220                 }
221                 T *pData = (*p_find)->data;
222                 (*p_find)->data = NULL;
223                 delete pData;
224                 pData = NULL;
225                 m_nElementCnt--;
226                 return true;
227             }
228         }
229     }
230     else
231     {
232         return false;
233     }
234 }
235 
236 template<class T,class K>
237 bool TrieTree<T, K>::insert( T *data,K key,bool overwrite)
238 {
239     int m = 0;
240     Node **p_find = NULL;
241     if(m_pHead == NULL)
242     {
243         return false;
244     }
245     p_find = &m_pHead;
246     while( key > 0 )
247     {
248         m = key%10;
249         if((*p_find) == NULL)
250         {
251             (*p_find) = new Node();
252             m_nNodeCnt++;
253         }
254         p_find = &(*p_find)->child[m];
255         key /= 10;
256     }
257     if((*p_find) == NULL)
258     {
259         (*p_find) = new Node();
260         (*p_find)->data = data;
261         m_nNodeCnt++;
262         m_nElementCnt++;
263         return true;
264     }
265     else
266     {
267         if((*p_find)->data == NULL)
268         {
269             (*p_find)->data = data;
270             m_nElementCnt++;
271             return true;
272         }
273         else
274         {
275             if(overwrite == false)
276             {
277                 return false;
278             }
279             else
280             {
281                 (*p_find)->data = data;
282                 m_nElementCnt++;
283                 return true;
284             }
285         }
286     }
287 }
288 
289 #endif

測試代碼:

void test1()
{
    int cnt = 0;
    time_t s,e;
    int n = 10,m = 0;
    TrieTree<R,int> a;
    set<R*> b;
    for(m = 1;m < 7;m++)
    {
        cout<<"item count:"<<n<<endl;
        s = clock();
        for(int i = 1;i < n;i++)
        {
            R *r = new R(i);
            a.insert(r,i);
        }
        //a.dump();
        for(int i = 1;i < n/2;i++)
        {
            a.remove(i,true);
        }
        e = clock();
        cout<<"TrieTree Use Time:"<<e-s<<endl;
        s = clock();
        for(int i = 1;i < n;i++)
        {
            R *r = new R(i);
            b.insert(r);
        }
        b.clear();
        e = clock();
        cout<<"Set Use Time:"<<e-s<<endl;
        cout<<"-------------------"<<endl;
        n*=10;
    }
}
int main()
{
    test1();
    system("pause");
    return 0;
}

測試結果:

以上僅是我個人的觀點,代碼也僅僅是練練手而已,不保證理論和實現完全正確,僅供參考。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM