bai_jimmy

导航

通过trie树实现单词自动补全

/**
 * 实现单词补全功能
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>

#define MAX_CHILD 26

#define error(...) \
        logger(stderr, __LINE__, __VA_ARGS__)

#define notice(...) \
        logger(stdout, __LINE__, __VA_ARGS__)

/**
 * 定义trie树节点
 */
typedef struct node_s{
        int count;
        struct node_s *child[MAX_CHILD];
        char words[20];
} node_t;

/**
 * 日志
 */
void logger(FILE *fp, int line, const char *fmt, ...){
        fprintf(fp, "[line]:%d | ", line);
        va_list ap;
        va_start(ap, fmt);
        vfprintf(fp, fmt, ap);
        va_end(ap);
        fprintf(fp, "\n");
}

/**
 * 创建节点
 */
node_t *createNode(){
        node_t *node = (node_t *)calloc(1, sizeof(node_t));
        if(node == NULL){
                error("createNode fail, errno[%d]", errno);
        }
}

/**
 * 添加
 */
int insert(node_t *root, char *words){
        if(!root || words[0] == '\0'){
                error("insert fail, root or words is null");
                return -1;
        }
        node_t *node = root;
        node_t *tmp;
        char *s = words;
        while(*s != '\0'){
                if(node->child[*s - 'a'] == NULL){
                        tmp = createNode();
                        if(tmp == NULL){
                                goto err;
                        }
                        node->child[*s - 'a'] = tmp;
                }
                node = node->child[*s - 'a'];
                s++;
        }
        node->count++;
        memcpy(node->words, words, strlen(words));
        notice("insert success, words = %s", words);
        return 0;
err:
        return -1;
}

/**
 * 搜索指定单词
 */
int search(node_t *root, char *words){
        if(!root || words[0] == '\0'){
                error("search fail, root or words is null");
                return -1;
        }
        char *s = words;
        node_t *node = root;
        while(*s != '\0'){
                if(node->child[*s - 'a'] == NULL){
                        break;
                }
                node = node->child[*s - 'a'];
                s++;
        }
        if(*s == '\0'){
                if(node->count == 0){
                        printf("没有搜索到这个字符串,但是它是某个字符串的前缀\n");
                }else{
                        printf("搜索到此字符串,出现次数为:%d\n", node->count);
                }

                searchChild(node);
        }else{
                printf("没有搜索到这个字符串\n");
        }
}

/**
 * 遍历出来的子节点是排序后的
 */
void searchChild(node_t *node){
        if(!node){
                error("searchChild fail, node is null");
                return;
        }
        int i;
        if(node->count){
                printf("%s\n", node->words);
        }
        for(i = 0; i < MAX_CHILD; i++){
                if(node->child[i]){
                        searchChild(node->child[i]);
                }
        }
}

/**
 * 递归回收内存
 */
void del(node_t *root){
        if(!root){
                error("del fail, root is null");
                return;
        }

        int i;
        for(i = 0; i < MAX_CHILD; i++){
                if(root->child[i]){
                        del(root->child[i]);
                }
        }
        free(root);

}

int main(){
        char *str = "jimmy";
        node_t *root = createNode();
        if(!root){
                return -1;
        }

        //insert(root, str);
        //search(root, "j");
        FILE *fp = fopen("one.txt", "r");
        if(!fp){
                perror("open file fail");
        }
        char words[20];
        while(!feof(fp)){
                fgets(words, sizeof(words), fp);
                //去掉回车符
                words[strlen(words) - 1] = '\0';
                insert(root, words);
                memset(words, 0, sizeof(words));
        }

        while(scanf("%s", words)){
                search(root, words);
        }


        del(root);
}

 

运行效果如下:

posted on 2016-04-24 00:25  bai_jimmy  阅读(648)  评论(0编辑  收藏  举报