通过trie树单词自动补全(二)
经常使用iciba进行单词查询, 关于他的搜索建议是通过单词前缀做的索引, 所以自己想动手实现下, 当然如果借助mysql的话,一条sql语句就能实现, 网上查询了下trie正适合做这个,所以通过C语言自己做了个demo
sug.c
/*
* 单词自动补全功能
* File: search.c
* Author: baijianmin
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <time.h> #include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h> #define MAX_CHILD 26
#define LISTEN_PORT 8080
#define LOG_DEBUG_PATH "./logs/debug.log"
#define LOG_ERROR_PATH "./logs/error.log"
#define DATA_PATH "one.txt" /**
* define log level
*/
enum log_level {
DEBUG = ,
ERROR =
}; #define error(...) \
logger(ERROR, __LINE__, __VA_ARGS__) #define debug(...) \
logger(DEBUG, __LINE__, __VA_ARGS__) #define assert(expr, rc) \
if(!(expr)){ \
error(#expr"is null or 0"); \
return rc; \
} /**
* trie node
*/
typedef struct node_s {
int count;
struct node_s *child[MAX_CHILD];
char words[];
} node_t; /**
* global var
*/
node_t *global_root; /**
* get now timestr
*/
static void get_time(char *time_str, size_t len) {
time_t tt;
struct tm local_time;
time(&tt);
localtime_r(&tt, &local_time);
strftime(time_str, len, "%m-%d %H:%M:%S", &local_time);
} /**
* log
*/
static void logger(int flag, int line, const char *fmt, ...) {
FILE *fp = NULL;
char time_str[ + ];
va_list args;
get_time(time_str, sizeof(time_str)); switch (flag) {
case DEBUG:
fp = fopen(LOG_DEBUG_PATH, "a");
if (!fp) {
return;
}
fprintf(fp, "%s DEBUG (%d:%d) ", time_str, getpid(), line);
break;
case ERROR:
fp = fopen(LOG_ERROR_PATH, "a");
if (!fp) {
return;
}
fprintf(fp, "%s ERROR (%d:%d) ", time_str, getpid(), line);
break;
default:
return;
} va_start(args, fmt);
vfprintf(fp, fmt, args);
va_end(args);
fprintf(fp, "\n"); fclose(fp);
return;
} /**
* listen fro connections on a specified port
*/
int startup() {
int sockfd = -;
struct sockaddr_in addr;
memset(&addr, , sizeof (addr));
sockfd = socket(AF_INET, SOCK_STREAM, );
if (sockfd < ) {
error("socket fail: %s", strerror(errno));
return -;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(LISTEN_PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *) &addr, sizeof (addr))) {
error("bind fail: %s", strerror(errno));
return -;
}
if (listen(sockfd, )) {
error("listen fail: %s", strerror(errno));
return -;
}
return sockfd;
} /**
* create node
*/
node_t *createNode() {
node_t *node = (node_t *) calloc(, sizeof (node_t));
if (node == NULL) {
error("createNode fail: %s", strerror(errno));
}
} /**
* insert words
*/
int insert(node_t *root, char *words) {
if (!root || words[] == '\0') {
error("insert fail, root or words is null");
return -;
}
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));
return ;
err:
return -;
} void search_child(node_t *node, int client_sock) {
if (!node) {
error("search_child fail, node is null");
return;
}
int i;
if (node->count) {
send(client_sock, node->words, strlen(node->words), );
send(client_sock, "|", , );
}
for (i = ; i < MAX_CHILD; i++) {
if (node->child[i]) {
search_child(node->child[i], client_sock);
}
}
} /**
* search
*/
int search(node_t *root, char *words, int client_sockfd) {
//--------------------------------fixme-------------------------------------
char *ps = words;
while (*ps != '\0') {
if (*ps < 'a' || *ps > 'z') {
*ps = '\0';
break;
}
ps++;
}
//--------------------------------------------------------------------------
if (!root || words[] == '\0') {
error("search fail, root or words is null");
return -;
}
debug("request query: %s", words);
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 0
if (node->count == ) {
printf("没有搜索到这个字符串,但是它是某个字符串的前缀\n");
} else {
printf("搜索到此字符串,出现次数为:%d\n", node->count);
}
#endif
search_child(node, client_sockfd); } else {
#if 0
printf("没有搜索到这个字符串:%s, %d\n", words, strlen(words));
#endif
}
close(client_sockfd);
} /**
* free mem
*/
void del(node_t *root) {
if (!root) {
error("del fail, root is null");
return;
} int i;
for (i = ; i < MAX_CHILD; i++) {
if (root->child[i]) {
del(root->child[i]);
}
}
free(root); } /**
* load data from file
*/
int load_data() {
global_root = createNode();
if(!global_root){
return -;
}
FILE *fp = fopen(DATA_PATH, "r");
if (!fp) {
error("open fail fail: %S", strerror(errno));
return -;
}
char words[];
while (!feof(fp) && fgets(words, sizeof (words), fp)) {
words[strlen(words) - ] = '\0';
insert(global_root, words);
memset(words, , sizeof (words));
}
debug("load_data success");
return ;
} /**
* response the request
*/
void accept_request(int client_sockfd){
char buf[];
memset(buf, , sizeof(buf));
recv(client_sockfd, buf, sizeof(buf), );
search(global_root, buf, client_sockfd);
//close client connection
close(client_sockfd);
} int main(void) {
int server_sockfd = -, client_sockfd = -;
struct sockaddr_in client_addr;
memset(&client_addr, , sizeof (client_sockfd));
int addr_len = sizeof (client_sockfd); server_sockfd = startup();
if (server_sockfd < ) {
return -;
} //load data from file
load_data(); //waitting for client
while () {
client_sockfd = accept(server_sockfd,
(struct sockaddr *) &client_addr, &addr_len);
if(client_sockfd < ){
error("accept fail, %s", strerror(errno));
return -;
}
accept_request(client_sockfd);
} close(server_sockfd);
return ;
}
sug.php
<?php if($_GET['query']){
$query = $_GET['query'];
}else{
exit(json_encode(array()));
} $host = "127.0.0.1";
$port = "8080"; $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Unable to create socket\n");
@socket_connect($socket, $host, $port) or die("Connect error.\n"); if ($err = socket_last_error($socket)){ socket_close($socket);
die(socket_strerror($err) . "\n");
} $len = socket_write ($socket , $query, strlen($query));
$querys = "";
$ret = socket_read($socket, 100);
while($ret){
$querys.=$ret;
$ret = socket_read($socket, 100);
}
socket_close($socket); $querysArr = explode("|", $querys);
array_pop($querysArr); echo json_encode($querysArr);
效果:
http://www.idoushuo.com/sug.php?query=a
通过trie树单词自动补全(二)的更多相关文章
- 通过trie树实现单词自动补全
/** * 实现单词补全功能 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #incl ...
- 关于在php中变量少写了一个$和页面不断转圈的问题排查和vim的自动补全方式
php中的所有变量都是页面级的, 即任何一个页面, 最多 都只能在一个文件 : 当前页面内使用, 不存在跨 文件/ 跨页面的 作用域的变量! 因此, 即使是 $GLOBALS 这个变量, 虽然叫全局 ...
- Xcode括号自动补全以及二次编译后不显示输入
今天遇到了一个大坑,在使用栈来进行计算表达式的时候,发现输入括号就报错,以及二次编译后不显示. 测试了好久,经过无数次debug后. 二次编译不显示还是没搞明白,不过输入倒是没什么问题,就是不显示出来 ...
- 我的Vim配置(自动补全/树形文件浏览)
配置文件的下载路径在这里 http://files.cnblogs.com/files/oloroso/vim.configure.xz.gz 这实际上是一个 xz 格式的文件,添加的 gz 文件后 ...
- IntelliJ IDEA 设置代码提示或自动补全的快捷键 (附IntelliJ IDEA常用快捷键)
修改方法如下: 点击 文件菜单(File) –> 点击 设置(Settings- Ctrl+Alt+S), –> 打开设置对话框. 在左侧的导航框中点击 KeyMap. 接着在右边的树型框 ...
- [LeetCode] Design Search Autocomplete System 设计搜索自动补全系统
Design a search autocomplete system for a search engine. Users may input a sentence (at least one wo ...
- 【Qt编程】基于Qt的词典开发系列<十四>自动补全功能
最近写了一个查单词的类似有道词典的软件,里面就有一个自动补全功能(即当你输入一个字母时,就会出现几个候选项).这个自动补全功能十分常见,百度搜索关键词时就会出现.不过它们这些补全功能都是与你输入的进行 ...
- shell自动补全功能:bash和zsh
首要一点:shell有多种,比如bash.zsh.csh.ksh.sh.tcsh等 因此,制作自动补全功能时,要先搞清楚,你使用的是哪种shell,各个shell制作方法是不同的,网上大部分介绍的是关 ...
- [LeetCode] 642. Design Search Autocomplete System 设计搜索自动补全系统
Design a search autocomplete system for a search engine. Users may input a sentence (at least one wo ...
随机推荐
- JAVA 入门第一章(语法基础)
本人初学java 博客分享记录一下自己的学习历程 java我的初步学习分为六章,有c和c++的基础学起来也简便了很多. 第一章 语法基础 第二章 面向对象 第三章 常用工具类 第四章 文件操纵 第五章 ...
- jquery给div的innerHTML赋值
$("#id").html()=""; //或者 $("#id").html("test");
- jquery插件图片延时加载实例详解
效果预览:http://keleyi.com/keleyi/phtml/image/index.htm 使用方法:1.导入JS插件 <script src="http://keleyi ...
- 彻底解决mysql中文乱码的办法 ???
MySQL会出现中文乱码的原因不外乎下列几点:1.server本身设定问题,例如还停留在latin12.table的语系设定问题(包含character与collation)3.客户端程式(例如p ...
- golang官网可以打开了 go语言
golang.org之前国内一直打不开,今天看了一下居然可以打开了,除了页面上youtube的视频加载不了.页面自动识别中文. 再也不用为下载go的源码发愁了.http://www.cnblogs.c ...
- SharePoint 2013 托管导航及相关配置
设计完善的导航可告诉您网站的用户大量有关网站所提供业务.产品和服务的信息.通过更新导航背后的分类法,可以推动业务并保持更新,而不必在过程中重新创建其网站导航.在 SharePoint 2013 中,可 ...
- iOS程序破解——ARM汇编基础
原文在此:http://www.cnblogs.com/mddblog/p/4951650.html 一.Thumb指令与ARM指令 Thumb指令为16位,因此存储代码的密度高,节省存储空间.但是功 ...
- jQuery对表单的操作
表单应用 一个表单有3个基本组成部分: 表单标签:包含处理表单数据所用的服务器端程序URL以及数据提交到服务器的方法 表单域:包含文本框.密码框.隐藏域.多行文本框.复选框.单选框.下拉选择框和文件上 ...
- CLR垃圾回收的设计
作者: Maoni Stephens (@maoni0) - 2015 附: 关于垃圾回收的信息,可以参照本文末尾资源章节里引用的垃圾回收手册一书. 组件架构 GC包含的两个组件分别是内存分配器和垃圾 ...
- ORA-02429: cannot drop index used for enforcement of unique /primary key
相信不少人遇到过ORA-02429: cannot drop index used for enforcement of unique /primary key 这个错误,对应的中文提示"O ...