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

看数据结构写代码(59) 键树的双链表示法

时间:2015-04-29 10:07:39      阅读:284      评论:0      收藏:0      [点我收藏+]

标签:键树   键树的双链表表示法   键树的双链表表示法c语言描述   

杂谈; 打败自己的 往往不是敌人,而是自己。坚持不易,且行且珍惜。


键树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高

键树的根节点不包含字符,除根节点外的非叶子节点都只包含一个字符,叶子节点存储具体信息。; 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串; 每个节点的所有子节点包含的字符都不相同。并且 兄弟节点 按 按 字符大小 排序。


例如:

技术分享 

它的 键树形式如下:

技术分享


键树的应用:(摘自百度)

串的快速检索

给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。
在这道题中,我们可以用数组枚举,用哈希,用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。

串”排序

给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出
用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可。

最长公共前缀

对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为当时公共祖先问题。




键树 有 两种 表示 方法:1. 双链表 表示法 ,就是 树的 孩子链表 表示法   2.多重链表表示法(Trie树)


下面给出 键树的 双链表 表示法的 插入,删除,查找  等功能 代码:


完整源代码网盘地址http://yun.baidu.com/share/link?shareid=582619924&uk=1208029266



// DSTree.cpp : 定义控制台应用程序的入口点。
//键树的双链树表示法

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

#define MAX_KEY_LEN	16
#define LEAF_END_CHAR '$'//叶子节点结束符
struct KeyType{
	char key[MAX_KEY_LEN];
	int len;
};

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

enum E_Kind{
	E_Kind_Leaf,
	E_Kind_Branch,
};
typedef struct DLNode{
	char data;
	DLNode * nextSibling;//下一个兄弟节点
	E_Kind kind;;
	union
	{
		char * record;//叶子节点的信息
		DLNode * firstChild;//第一个孩子节点(分支节点)
	};
}*DLTree;

DLNode * makeNode(E_Kind kind){
	DLNode * node = (DLNode *)malloc(sizeof(DLNode));
	node->kind = kind;
	node->nextSibling = NULL;
	if (node->kind == E_Kind_Branch){
		node->firstChild = NULL;
	}
	else{
		node->record = (char *)malloc(sizeof(char)*MAX_KEY_LEN);
		node->data = LEAF_END_CHAR;
	}
	return node;
}

void initTree(DLTree * tree){
	*tree = NULL;
}

void destoryTree(DLTree * tree){
	DLTree p = *tree;
	if (p != NULL){
		if (p->kind == E_Kind_Leaf){
			free(p->record);
		}
		else{
			destoryTree(&p->firstChild);
		}
		destoryTree(&p->nextSibling);
		free(p);
		*tree = NULL;
	}
}

DLTree  search(DLTree t,char * k){
	if (t != NULL)
	{
		KeyType kt;
		initKey(&kt,k);
		int times = 0;
		t = t->firstChild;
		while (t && times < kt.len){
			while (t && t->data < kt.key[times]) t = t->nextSibling;
			if (t && t->data == kt.key[times]){
				t = t->firstChild;
				times++;
			}
			else{
				return NULL;
			}
		}
		if (times == kt.len && t->kind == E_Kind_Leaf){
			return t;
		}
	}
	return NULL;
}

//搜索结果.为插入 关键字 服务
//是第一个孩子节点:tree:返回 父亲节点 ,不是 返回 兄弟节点.
struct Result{
	bool isFind;//是不是找到了
	bool isFirst;//是不是第一个孩子节点
	DLTree tree;//插入位置
	int index;//需要插入的节点 的位置.
};

Result searchForInsert(DLTree tree,KeyType key){
	int times = 0;
	Result result;
	result.isFirst = false;
	result.isFind = false;
	while (tree && times < key.len){
		DLTree fatherNode = tree;
		result.index = times;
		tree = tree->firstChild;
		while (tree){
			if (tree->data > key.key[times]){
				if (fatherNode->firstChild == tree){
					result.isFirst = true;
					result.tree = fatherNode;
				}
				return result;
			}
			else if(tree->data == key.key[times]){
				result.tree = tree;
				times ++;
				break;
			}
			else{// $ 比 a ~ z 小
				result.tree = tree;
				tree = tree->nextSibling;
			}
		}
	}
	if ( times == key.len){//全部都相等
		if (tree && tree->firstChild && tree->firstChild->kind == E_Kind_Leaf){
			result.isFind = true;
			result.tree = tree->firstChild;
		}
		else{
			result.isFirst = true;
			result.index = times;
		}
	}
	return result;
	
}

void insert(DLTree t,KeyType kt,int index){
	for (int i = index; i < kt.len; i++){
		DLNode * node = makeNode(E_Kind_Branch);
		node->data = kt.key[i];
		t->firstChild = node;
		t = node;
	}
	//最后插入叶子节点
	DLNode * leaf = makeNode(E_Kind_Leaf);
	strncpy(leaf->record,kt.key,kt.len+1);
	t->firstChild = leaf;
}

void insertTree(DLTree * tree,char * key){
	KeyType kt;
	initKey(&kt,key);
	if (*tree == NULL){//空树,需要设置一个根节点
	    *tree = makeNode(E_Kind_Branch);
		insert(*tree,kt,0);
		return;
	}
	Result result = searchForInsert(*tree,kt);
	if (result.isFind == false){//没找到,再插入.
		if (result.isFirst){//插入在头部
			DLTree fatherNode = result.tree;
			DLTree oldFirst = fatherNode->firstChild;
			insert(fatherNode,kt,result.index);
			fatherNode->firstChild->nextSibling = oldFirst;
		}
		else{
			DLTree leftBrother = result.tree;
			DLNode * node = makeNode(E_Kind_Branch);
			node->data = kt.key[result.index];
			node->nextSibling = leftBrother->nextSibling;
			leftBrother->nextSibling = node;
			insert(node,kt,result.index+1);
		}
	}
}

void deleteTree(DLTree * t,char * k){
	if (*t != NULL)
	{
		KeyType kt;
		initKey(&kt,k);
		DLTree p = (*t)->firstChild;
		int times = 0;
		linkStack stack;
		stackInit(&stack);
		stackPush(&stack,*t);
		while (p && times < kt.len){
			while (p && p->data < kt.key[times]) p = p->nextSibling;
			if (p && p->data == kt.key[times]){
				stackPush(&stack,p);
				p = p->firstChild;
				times++;
			}
			else{
				return;//没找到
			}
		}
		if (p && p->kind == E_Kind_Leaf){
			DLTree f = NULL;
			while (!stackEmpty(stack)){
				stackPop(&stack,&f);
				if (f->firstChild == p && p->nextSibling == NULL){//父亲只有 一个孩子
					free(p);
					p = f;
					if (*t == f){//所有关键字都被删除了,空树..
						free(*t);
						*t = NULL;
						return;
					}
				}
				else{
					break;
				}
			}
			if (f->firstChild == p){
				f->firstChild = p->nextSibling;
			}
			else{
				DLTree pre = f->firstChild;
				while (pre != NULL && pre->nextSibling != p) pre = pre->nextSibling;
				pre->nextSibling = p->nextSibling;
			}
			free(p);
		}
		stackDestory(&stack);
	}
}

//层序遍历
void levelTraverse(DLTree tree){
	if (tree != NULL){
		if (tree->firstChild != NULL){
			printf("----------------层序遍历----------------\n");
			LinkQueue queue;
			queueInit(&queue);
			enqueue(&queue,tree->firstChild);
			int count = 1;
			int level = 1;
			int nextCount = 0;
			while (!queueEmpty(queue)){
				printf("%d 层数据:",level);
				for (int i = 0; i < count; i++){
					DLTree t;
					dequeue(&queue,&t);
					while (t){
						printf("%c   ",t->data);
						if (t->kind == E_Kind_Branch &&  t->firstChild != NULL){
							enqueue(&queue,t->firstChild);
							nextCount++;
						}
						t = t->nextSibling;
					}
				}
				printf("\n");
				count = nextCount;
				nextCount = 0;
				level++;
			}
			queueDestory(&queue);
			printf("\n");
		}
	}
}


static char testArray[][MAX_KEY_LEN] = {//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[])
{
	DLTree root;
	initTree(&root);
	for (int i = 0; i < 16; i++){
		insertTree(&root,testArray[i]);
	}
	levelTraverse(root);
	for (int i = 0; i < 18; i++){
		char  * s = testArray[i];
		DLTree t = search(root,s);
		if (t){
			printf("查找 %s后,记录为:%s\n",s,t->record);
		}
		else{
			printf("查找 %s,没找到\n",s);
		}
	}
	for (int i = 0; i < 18; i++){
		char * s = testArray[i];
		deleteTree(&root,s);
		printf("-------------删除%s后--------------\n",s);
		levelTraverse(root);
	}
	destoryTree(&root);
	return 0;
}




看数据结构写代码(59) 键树的双链表示法

标签:键树   键树的双链表表示法   键树的双链表表示法c语言描述   

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

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