通过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 ...
随机推荐
- json-lib的使用《二》
上篇文章主要集中在了使用json-lib来实现JSON字符串和java中的对象的互转上,忽视了json-lib本身的功能,json-lib中有两个类比较重要:JSONObject和JSONArray, ...
- AbstractFactoryPattern(抽象工厂)
/** * 抽象工厂模式 * 分为四部分 * 1.产品接口 * 2.产品实例 * 3.工厂接口(生产同一个产品的不同等级,这里是主要区别) * 4.工厂实例 * 工厂类最好用单例模式,但在这里主要是说 ...
- 帆布指纹识别(canvas fingerprinting)
广告联盟或许网站运营者都希望能够精准定位并标识每一个个体,通过对用户行为的分析(浏览了哪些页面?搜索了哪些关键字?对什么感兴趣?点了哪些按钮?用了哪些功能?看了哪些商品?把哪些放入了购物车等等),为用 ...
- entityframework学习笔记--003-使用model first
首先,我个人觉得这(model first 即模型优先)是一个鸡肋似的功能.当赞扬着他的强大的功能的同时,你也会觉得这个功能好像是不是不怎么需要,也很少使用. 1.右键你的项目,选择"添加& ...
- 30行代码搞定WCF并发性能测试
[以下只是个人观点,欢迎交流] 30行代码搞定WCF并发性能 轻量级测试. 1. 调用并发测试接口 static void Main() { List< ...
- h5曲线滑动确认
h5项目需根据几条弯曲的线条让用户进行曲线式滑动,滑动时需实时响应某些样式,于是就有了下面这个实例.(可自定义多个子对象大小分别放在线条各处,以增加曲线滑动确认精度.) <!doctype ht ...
- python操作CouchDB
安装python couchDb库: https://pypi.python.org/pypi/CouchDB/0.10 连接服务器 >>> import couchdb >& ...
- Windows on Device 项目实践 1 - PWM调光灯制作
在前一篇文章<Wintel物联网平台-Windows IoT新手入门指南>中,我们讲解了Windows on Device硬件准备和软件开发环境的搭建,以及Hello Blinky项目的演 ...
- MVP ComCamp & GCR MVP Openday 2014
今年的MVP Openday与往年不一样,加入了Community Camp环节,即社区大课堂.其主要形式是由MVP作为讲师提供包括Developer和IT Pro方向的课程,地点是在北京国际会议中心 ...
- PHP笔记(HTML篇)
学过很多语言,最近终于决定要学PHP了. 学习PHP,首先总要学习HTML,那么,我也从HTML开始吧! 首先学习任何编程语言,看再多书,都离不开它——帮助文档 HTML帮助文档:http://pan ...