码迷,mamicode.com
首页 > 其他好文 > 详细

看数据结构写代码(60 ) 键树的多重链表表示(Trie树)

时间:2015-04-29 13:35:48      阅读:386      评论:0      收藏:0      [点我收藏+]

标签:键树的多重链表表示法   trie树   trie树c语言描述   

trie树,是用 树的 多重链表来表示 树的。每个节点 有 d 个指针域。若从键树中的某个节点到叶子节点的路径上每个节点都只有一个孩子,则可以把 路径上的所有节点压缩成一个叶子节点,且在叶子节点中 存储 关键字 以及 根关键字相关的信息。

当节点的度 比较大时,选择 Trie树,要比 双链表树更为合适。

tire树的 数据 压缩 是 挺与众不同的。

下面 给出 具体的 代码:

源代码工程文件网盘地址:http://pan.baidu.com/s/1cyTg6

// TrieTree.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <cstdlib>
#include <cstring>
#include "stack.h"


#define BRANCH_MAX_SIZE  27//分支节点最大指针数
#define MAX_SIZE 16
#define LEAF_END_CHAR '$'
enum E_Kind{
	E_Kind_Branch,
	E_Kind_Leaf,
};

struct KeyType{
	char k [MAX_SIZE];
	int len;
};

void initKey(KeyType * kt,char *k){
	kt->len = strlen(k);
	strncpy(kt->k,k,kt->len+1);
}

typedef struct TrieNode{
	E_Kind kind;
	union {
		struct {
			TrieNode * ptr[BRANCH_MAX_SIZE];
			int num;
		}branch;
		struct {
			char record[MAX_SIZE];
		}leaf;
	};
}* TrieTree;

TrieNode * makeNode(E_Kind kind){
	TrieNode * node = (TrieNode*) malloc(sizeof(TrieNode));
	node->kind = kind;
	if (kind == E_Kind_Branch){
		for (int i = 0; i < BRANCH_MAX_SIZE; i++){
			node->branch.ptr[i] = NULL;
		}
		node->branch.num = 0;
	}
	return node;
}

TrieNode * makeLeafNode(char * key){
	TrieNode * leaf = makeNode(E_Kind_Leaf);
	strncpy(leaf->leaf.record,key,strlen(key)+1);
	return leaf;
}

void initTree(TrieTree* t){
	*t = NULL;
}

void destoryTree(TrieTree * t){
	if (*t != NULL)
	{
		TrieTree p = *t;
		if (p->kind == E_Kind_Branch){
			for (int i = 0; i < BRANCH_MAX_SIZE; i++){
				if (p->branch.ptr[i] != NULL){
					destoryTree(&p->branch.ptr[i]);
				}
			}
		}
		free(*t);
		*t = NULL;
	}
}

int getIndex(char * k,int i){
	KeyType kt;
	initKey(&kt,k);
	int index = 0;
	if(i != kt.len){
		index = kt.k[i] - 'a' + 1;
	}
	return index;

}

struct Result{
	bool isFind;
	TrieNode * t;
	int index;
};
//找到了返回 保存记录的 叶子节点;
//否则返回插入位置
Result search(TrieTree t,char * k){
	KeyType kt;
	initKey(&kt,k);
	Result r;
	for (int i = 0; t && t->kind == E_Kind_Branch && i<= kt.len; i++){
		int index = getIndex(k,i);
		r.t = t;
		r.index = i;
		t = t->branch.ptr[index];
	}
	if (t &&  t->kind == E_Kind_Leaf  && strcmp(t->leaf.record,k) == 0){//节点可以压缩,所以没有 == kt.len的条件.
		r.isFind = true;
		r.t = t;
	}
	else{
		r.isFind = false;
	}
	return r;
}



void insertTree(TrieTree *t,char * key){
	if (*t == NULL){
		*t = makeNode(E_Kind_Branch);
	}
	Result r = search(*t,key);
	if (r.isFind == false){
		int index = getIndex(key,r.index);
		TrieTree p = r.t->branch.ptr[index];
		TrieNode * leaf = makeLeafNode(key);
		if (p == NULL){
			r.t->branch.ptr[index] = leaf;
			r.t->branch.num ++;
		}
		else{
			TrieTree q = r.t;
			int times = r.index+1;
			int len = strlen(key);
			while (times <= len){//为字符 相同的节点 建立 分支
				int  index1 = getIndex(key,times);
				int index2= getIndex(p->leaf.record,times);
				TrieNode * branch = makeNode(E_Kind_Branch);
				q->branch.ptr[index] = branch;
				if (index1 != index2){
					branch->branch.ptr[index1] = leaf;
					branch->branch.ptr[index2] = p;
					branch->branch.num += 2;
					break;
				}
				else{
					branch->branch.num = 1;
					q = branch;
					index = index1;
					times++;
				}
			}
		}
	}
	
}

void deleteTrie(TrieTree * t,char * k){
	if(*t != NULL){
		linkStack stack;
		stackInit(&stack);
		stackPush(&stack,*t);
		KeyType kt;
		initKey(&kt,k);
		TrieTree p = *t;
		int i = 0;
		for (; p && p->kind == E_Kind_Branch && i <= kt.len; i++){
			int index = getIndex(k,i);
			stackPush(&stack,p);
			p = p->branch.ptr[index];
		}
		if (p && p->kind == E_Kind_Leaf && strcmp(p->leaf.record,k) == 0){
			TrieTree brotherNode = NULL;
			while (!stackEmpty(stack)){
				TrieTree f;
				stackPop(&stack,&f);
				free(p);
				int index = getIndex(k,i);
				f->branch.ptr[i] = NULL;
				f->branch.num --;
				if (f->branch.num == 0){
					p = f;
					i--;
					if (f == *t){//空树了..
						free(*t);
						*t = NULL;
					}
				}
				else{
					break;
				}
			}
		}
		else{//没找到
			return;
		}
	}
}

static char testArray[][MAX_SIZE] = {//18 个  
    "cao","cai","chang","chao","cha","chen",//6  
    "wen","wang","wu",//3  
    "zhao",//1  
    "li","lan","long","liu",//4  
    "yun","yang",//2  
    "zha","l",  
};  

int _tmain(int argc, _TCHAR* argv[])
{
	TrieTree root;
	initTree(&root);
	for (int i = 0; i < 18; i++){
		insertTree(&root,testArray[i]);
	}
	for (int i = 0; i < 18; i++){
		char * s = testArray[i];
		Result r = search(root,s);
		if (r.isFind){
			printf("查找%s ,结果为:%s\n",s,r.t->leaf.record);
		}
		else{
			printf("查找%s ,未找到\n",s);
		}
	}
	destoryTree(&root);
	return 0;
}
运行截图:

技术分享

看数据结构写代码(60 ) 键树的多重链表表示(Trie树)

标签:键树的多重链表表示法   trie树   trie树c语言描述   

原文地址:http://blog.csdn.net/fuming0210sc/article/details/45364983

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!