通过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 ...
随机推荐
- spring-stutrs求解答
这里贴上applicationContext里的代码: <?xml version="1.0" encoding="UTF-8"?> <bea ...
- 从零开始学 Java - Spring 支持 CORS 请求踩的坑
谁没掉进过几个大坑 记得好久之前,总能时不时在某个地方看到一些标语,往往都是上面一个伟人的头像,然后不管是不是他说的话,下面总是有看起来很政治正确且没卵用的屁话,我活到目前为止,最令我笑的肚子痛得是下 ...
- 如何使用jQuery 制作全屏幕背景的嵌入视频
实际效果查看:http://keleyi.com/keleyi/phtml/jqtexiao/28.htm 请使用支持HTML5的浏览器查看本效果. 完整代码如下: <!doctype html ...
- Google LOGO现代舞舞蹈动画
效果预览:http://hovertree.com/texiao/js/5.htm 截图: HTML文件代码: <!DOCTYPE html> <html xmlns="h ...
- jQuery基础知识总结
1. jQuery基本概念介绍 1.1 什么是jQuery 一个javascript库,把常用方法写到一个js文件中,需要的时候直接调用即可 学习jQuery就是学习一些方法 ...
- DatatableToJson JsonToDatatable
using Newtonsoft.Json;using Newtonsoft.Json.Converters; /// <summary> /// 将DataTable类型转为JSON类型 ...
- JavaScript基本语法(二)
上篇博文写到JavaScript的数据类型.JavaScript包括了字符串(String).数字(Number).布尔(Boolean).数组(Array).对象(Object).空(Null).未 ...
- iOS 学习 - 16.绘制虚线
//绘制虚线 -(void)set{ UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(, , , )]; [ ...
- iOS8 tableview separatorInset cell分割线左对齐,ios7的方法失效了
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 -(void)viewDidLayoutSubviews { if ([self.m ...
- Linux磁盘空间监控告警
Linux系统中需要监控磁盘各分区的使用情况,避免由于各种突发情况,造成磁盘空间被消耗殆尽的情况,例如某个分区被Oracle的归档日志耗尽,导致后续的日志文件无法归档,这时ORACLE数据库就会出现错 ...