T树(字典树的插入和删除以及查找)C++
2016-08-25 18:31
351 查看
简单的实现了Trie树的常用操作,有点简陋,但是思想能够体现出来,第一次写可能会有bug,目前我没有查到….没有内存泄漏.
如有错误欢迎斧正!
如有错误欢迎斧正!
#include<iostream> #include<stack> using namespace std; #define maxsize 256 #define azsize 27 //值类型 struct keytype { char *data; unsigned size; int count;//这个字段没有用上,出发点是用来统计同一个单词的重复数量 //而这个T树的插入是将重复的直接丢掉了....所以恒为1;; //可以稍加修改下插入就可以起作用了. }; enum tnodetype { branch, leaf }; struct tnode { tnodetype utype; union nodetype { struct { tnode * link[azsize]; int num; } bra; struct { keytype value; // char *recode; }node; } nodet; }; class Tree { public: tnode *root = NULL; tnode * current = nullptr;//查找时有用.. int insert(const keytype &key); int delnode(const keytype &key); tnode* search(const keytype &key); void insert(tnode * prev, tnode *old, char *toinser, unsigned i); void destroy(tnode * &node) { if (node != nullptr && (node->utype == leaf || node->nodet.bra.num == 0)) { delete node; node = nullptr; } for (int i = 0; i < azsize && node != nullptr; i++) { if (node->nodet.bra.num == 0) { delete node; node = nullptr; return; } if (node->nodet.bra.link[i] != nullptr) { destroy(node->nodet.bra.link[i]); node->nodet.bra.num--; } } } ~Tree() { if (root != nullptr) destroy(root); } }; /* *前提是添加的内容一定不会在树中. *如果是old叶子和新叶子一直有相同的字符那么就一直创建一个分支直到出现不同的字符 *出现了不同的字符,可能有一些情况,原来的比较短,在创建分支中达到了末尾,那么应该将它 放在link[0]上.当然也可能是新叶子达到了末尾也是如此处理放在link[0]上; */ void Tree::insert(tnode * prev, tnode *old, char *toinser, unsigned i) { char * oldstr = old->nodet.node.value.data; tnode * _leaf = new tnode; _leaf->utype = leaf; _leaf->nodet.node.value.data = toinser; _leaf->nodet.node.value.size = strlen(toinser); prev->nodet.bra.num--;//这里是因为要将old 从prev上拆下来所以要减,如果没有这句,会造成销毁时的内存泄漏 //当两者都有相同的字符就一直创建分支 --i; do { tnode * _bran = new tnode; _bran->utype = branch; _bran->nodet.bra.num = 0; memset(_bran->nodet.bra.link, NULL, sizeof(tnode *)*azsize); prev->nodet.bra.link[toinser[i] - 'a' + 1] = _bran; prev->nodet.bra.num++; prev = _bran; i++; } while (oldstr[i] == toinser[i]); //可能出现的情况有,其中有一个达到了末尾而退出 int pos1 = toinser[i] - 'a' > 0 ? toinser[i] - 'a' + 1 : 0; int pos2 = oldstr[i] - 'a' > 0 ? oldstr[i] - 'a' + 1 : 0; prev->nodet.bra.link[pos1] = _leaf; prev->nodet.bra.link[pos2] = old; prev->nodet.bra.num += 2; } int Tree::insert(const keytype &key) { auto res = search(key);//如果添加的在树中了,那么就直接退出了 if (res != nullptr) { //res->nodet.node.value.count++; return 0; } tnode * stmp = root; tnode * prev = root; char *k = key.data; unsigned i = 0; unsigned len = key.size; int pos = k[i] - 'a' + 1; /*首先要找到插入的位置...有下列情况 * 这个分支下没有内容,stmp是分支且对应的link == null; 那么就构造一个叶子节点直接插入... * 如果是在查找的过程中达到了key的末尾,那么就是需要插在link[0] *如果是找到的是分支下的一个叶子节点,那么就是插入到叶子上的情况 */ while (i < len && nullptr != stmp) { if (stmp->utype == branch) { pos = k[i] - 'a' + 1; prev = stmp; stmp = stmp->nodet.bra.link[pos]; ++i; continue; } //查找到了一个叶子节点需要进行插入 insert(prev, stmp, k, i); return 0; } tnode * _leaf = new tnode; _leaf->utype = leaf; _leaf->nodet.node.value.data = k; _leaf->nodet.node.value.size = key.size; if (stmp == nullptr) { if (root == nullptr) { tnode * _bran = new tnode; _bran->utype = branch; _bran->nodet.bra.num = 0; memset(&_bran->nodet.bra.link[0], NULL, sizeof(tnode *)*azsize); _bran->nodet.bra.link[pos] = _leaf; _bran->nodet.bra.num++; root = _bran; } else { prev->nodet.bra.link[k[i - 1] - 'a' + 1] = _leaf; prev->nodet.bra.num++; } } else { stmp->nodet.bra.link[0] = _leaf; stmp->nodet.bra.num++; } return 0; } int Tree::delnode(const keytype &key) { auto res = search(key); tnode * stnode = root; tnode * prev = root; if (res == nullptr) return -1; unsigned i = 0; //既然存 c1d9 在那么肯定是以下两种情况 //key在叶子上,删除后可能引起级联删除 //key在link[0]上 直接删除,因为肯定至少有一个叶子节点或者分支节点挂在上面...不用级联删除 stack<tnode*> nodesta; while (i < key.size && stnode->utype != leaf) { if (stnode->utype == branch) { nodesta.push(stnode); stnode = stnode->nodet.bra.link[key.data[i] - 'a' + 1]; i++; } } if (stnode->utype == leaf) { prev = nodesta.top(); nodesta.pop(); prev->nodet.bra.link[key.data[--i] - 'a' + 1] = nullptr; prev->nodet.bra.num--; delete stnode; while (prev->nodet.bra.num == 0) { stnode = prev; prev = nodesta.top(); nodesta.pop(); prev->nodet.bra.link[key.data[--i] - 'a' + 1] = nullptr; prev->nodet.bra.num--; delete stnode; } } else { delete stnode->nodet.bra.link[0]; stnode->nodet.bra.link[0] = nullptr; stnode->nodet.bra.num--; } return 0; } tnode * Tree::search(const keytype &key) { if (root == nullptr) return nullptr; char *k = key.data; unsigned len = strlen(k); current = root; unsigned int i = 0; int pos = 0; /*如果查找的目标在分支的0下标处, 分支在叶子上, 没有这个元素 */ for (; i < len && current != nullptr; ++i) { pos = k[i] - 'a' + 1; if (current->utype == branch) { current = current->nodet.bra.link[pos]; } else if (current->utype == leaf) { int r = strcmp(k, current->nodet.node.value.data); if (0 == r) { return current; } else { return nullptr; } } } if (i >= len && current->utype == branch && current->nodet.bra.link[0] != nullptr) { int r = strcmp(k, current->nodet.bra.link[0]->nodet.node.value.data); if (0 == r) { return current; } } return nullptr; } int main() { Tree tri; keytype tmp[] = { "hello",5,1,"hi",2,1,"alone",5,1,"alive",5,1,"hell",4,1,"he",2,1,"he",2,1 }; for (int i = 0; i < 7; ++i) tri.insert(tmp[i]); for (int i = 0; i < 7; ++i) tri.delnode(tmp[i]); return 0; }
相关文章推荐
- [置顶] 二叉树的建立、节点查找以及节点删除C和C++实现
- C++ 单链表操作 插入、删除、查找、排序、合并
- C++实现B-树插入删除查找
- 单链表的创建、插入、删除、销毁以及查找中间结点
- HDU 5687 字典树插入查找删除
- [zz]跳表(Skip List)的介绍以及查找插入删除等操作
- 链表的相关操作查找插入删除(c++ 数据结构)
- C++实现红黑树建立,销毁,查找,插入和删除
- C++单链表的动态创建,查找,遍历,删除,插入,添加,排序
- Problem C (字典树的查找删除和插入)2016"百度之星" - 资格赛(Astar Round1)
- 跳表(Skip List)的介绍以及查找插入删除等操作
- C++单链表的创建插入删除以及逆序操作
- 跳表(Skip List)的介绍以及查找插入删除等操作
- C/C++学习(六)线性表的插入、删除和查找
- 跳表(Skip List)的介绍以及查找插入删除等操作
- C++ 二叉树(创建,遍历,查找,插入,删除)『菜鸟版』
- C++链表的创建、插入、删除、查找、合并、排序、修改等操作的实现
- 二叉树的建立、节点查找以及节点删除C和C++实现
- 二叉树的遍历、查找、插入以及删除
- 字典树Trie 之 基础模板(插入,查找,删除)