在一个嵌入式项目中,要存储100万条电话号码,同时电话号码的长度最长为11位,为了提高查找的速度,笔者采用11叉树的方式进行存储电话号码,并且支持电话号码的包含关系,所谓包含关系,即要支持1234, 12345这种包含关系。
#pragma once #include <string> #include <stack> using namespace std; #define MAX_WAY 11 #define HAS_CHILDREN_NO 0x01 #define HAS_CHILDREN_YES 0x02 #define HASNO_CHILDREN_NO 0x03 #define HASNO_CHILDREN_YES 0x04 class Threewaytree { public: Threewaytree(void); ~Threewaytree(void); private: Threewaytree* m_ptree[MAX_WAY]; unsigned char m_symbol; static int m_nodecount; public: void output(int indent = -1); bool insertphonenumber(string phonenumber); bool deletephonenumber(string phonenumber); void generatephonelist(string& prefix); void getphonecount(int& count); bool findphonenumber(string phonenumber); private: void destroy(); int wetherornotdelete(); bool islegalphonenumber(string phonenumber); }; #include "Threewaytree.h" #include "stdio.h" int Threewaytree::m_nodecount = 0; Threewaytree::Threewaytree(void) { //printf("new %08x\n", this); m_nodecount++; m_symbol = 0x00; for(int i = 0; i < MAX_WAY; i++) { m_ptree[i] = NULL; } } Threewaytree::~Threewaytree(void) { printf("delete %08x\n", this); m_nodecount--; destroy(); } void Threewaytree::getphonecount(int& count) { for(int i = 0; i < MAX_WAY; i++) { if (m_ptree[i] != NULL) { if (m_ptree[i]->m_symbol == 1) { count++; } m_ptree[i]->getphonecount(count); } } } void Threewaytree::generatephonelist(string& prefix) { for(int i = 0; i < MAX_WAY; i++) { string temp = prefix; if (m_ptree[i] != NULL) { temp += i + 48; if (m_ptree[i]->m_symbol == 1) { printf("%s\n", temp.c_str()); } m_ptree[i]->generatephonelist(temp); } } } void Threewaytree::output(int indent) { indent++; for(int i = 0; i < MAX_WAY; i++) { if (m_ptree[i] != NULL) { for(int j = 0; j < indent; j++) { printf("|--"); } printf("%d [0x%08x] [%d] \n", i, m_ptree[i], m_ptree[i]->m_symbol); m_ptree[i]->output(indent); } } } bool Threewaytree::insertphonenumber(string phonenumber) { bool result = false; if (!islegalphonenumber(phonenumber)) return false; const char *pchar = phonenumber.c_str(); int index = 0; int length = phonenumber.length(); Threewaytree *parenttreenode = this; int order = 0; while(index < length) { order = *pchar - 48; if (parenttreenode->m_ptree[order] == NULL) { Threewaytree *treenode = new Threewaytree; parenttreenode->m_ptree[order] = treenode; parenttreenode = treenode; } else { parenttreenode = parenttreenode->m_ptree[order]; } index++; pchar++; } if (parenttreenode->m_symbol == 1) { return result; } else if(parenttreenode->m_symbol == 0) { result = true; parenttreenode->m_symbol = 1; } return result; } bool Threewaytree::islegalphonenumber(string phonenumber) { bool result = true; int length = phonenumber.length(); if (length > MAX_WAY) { result = false; return result; } const char *pchar = phonenumber.c_str(); int index = 0; while(index < length) { if ((*pchar) < '0' || (*pchar > '9')) { result = false; break; } index++; pchar++; } return result; } int Threewaytree::wetherornotdelete() { int result = 0x00; bool haschildren = false; for(int i = 0; i < MAX_WAY; i++) { if (m_ptree[i] != NULL) { haschildren = true; break; } } if(haschildren == true && m_symbol == 1) { result = HAS_CHILDREN_YES; } else if(haschildren == false && m_symbol == 1) { result = HASNO_CHILDREN_YES; } else if(haschildren == true && m_symbol == 0) { result = HAS_CHILDREN_NO; } else if(haschildren == false && m_symbol == 0 ) { result = HASNO_CHILDREN_NO; } return result; } bool Threewaytree::findphonenumber(string phonenumber) { bool result = false; if (!islegalphonenumber(phonenumber)) return result; const char *pchar = phonenumber.c_str(); int length = phonenumber.length(); int index = 0; Threewaytree *node = this; while(index < length) { int order = *pchar - 48; //不存在号码退出, 号码还没有遍历完,但指针已经到头了。 if (node->m_ptree[order] == NULL) return result; //为下次循环准备 node = node->m_ptree[order]; pchar++; index++; } if (node->m_symbol == 1) { result = true; } return result; } bool Threewaytree::deletephonenumber(string phonenumber) { typedef struct { int index; Threewaytree* ptree; }ELEM; typedef stack<ELEM> STACK; STACK mystack; bool result = false; if (!islegalphonenumber(phonenumber)) return result; const char *pchar = phonenumber.c_str(); int length = phonenumber.length(); int index = 0; Threewaytree *node = this; //都元素入栈 ELEM elem; elem.index = 0xFFFFFFFF; elem.ptree = node; mystack.push(elem); while(index < length) { int order = *pchar - 48; //不存在号码退出, 号码还没有遍历完,但指针已经到头了。 if (node->m_ptree[order] == NULL) return result; //普通元素开始入栈 ELEM elem; elem.index = order; elem.ptree = node->m_ptree[order]; mystack.push(elem); //为下次循环准备 node = node->m_ptree[order]; pchar++; index++; } printf("----------------------------- stack size = %d ---------------------------------\n", mystack.size()); for(int i= 0; i < length; i++) { ELEM elem1 = mystack.top(); mystack.pop(); int result = elem1.ptree->wetherornotdelete(); printf("pop order=%d elem=%08x symbol=%d result=%d\n", elem1.index, elem1.ptree, elem1.ptree->m_symbol, result); if (result == HAS_CHILDREN_NO) { break; } else if(result == HAS_CHILDREN_YES) { if (i == 0) { elem1.ptree->m_symbol = 0; printf("set symbol = 0\n"); break; } } else if(result == HASNO_CHILDREN_NO) { delete elem1.ptree; elem1.ptree = NULL; ELEM elem2 = mystack.top(); elem2.ptree->m_ptree[elem1.index] = NULL; } else if(result == HASNO_CHILDREN_YES) { if (i== 0) { delete elem1.ptree; elem1.ptree = NULL; ELEM elem2 = mystack.top(); elem2.ptree->m_ptree[elem1.index] = NULL; } else { break; } } } result = true; printf("------------------------------------------------------------------------------\n"); return result; } void Threewaytree::destroy() { for(int i = 0; i < MAX_WAY; i++) { if (m_ptree[i] != NULL) { m_ptree[i]->destroy(); delete m_ptree[i]; m_ptree[i] = NULL; } } }
主函数测试:
// Tree.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "Threewaytree.h" #include "math.h" int _tmain(int argc, _TCHAR* argv[]) { Threewaytree tree; tree.insertphonenumber("123"); tree.insertphonenumber("123"); tree.insertphonenumber("12"); tree.insertphonenumber("1234"); tree.insertphonenumber("123567"); tree.insertphonenumber("125"); tree.insertphonenumber("18"); tree.insertphonenumber("2"); tree.output(); string phonelist = ""; tree.generatephonelist(phonelist); bool result = tree.deletephonenumber("2"); if (result) { printf("delete true\n"); } else { printf("delete false\n"); } tree.generatephonelist(phonelist); tree.output(); /*tree.output(); printf("-------------- phone number count ----------------\n"); int count = 0; tree.getphonecount(count); printf("count=%d\n", count); printf("-------------- phone number list ----------------\n"); string phonelist = ""; tree.generatephonelist(phonelist); printf("-------------- find phone number ----------------\n"); string phonenumber = "18"; if (tree.findphonenumber(phonenumber)) { printf("find\n"); } else { printf("not find\n"); }*/ getchar(); return 0; }