通过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 Collections工具类sort()排序方法
主要分析内容: 一.Collections工具类两种sort()方法 二.示例 一.Collections工具类两种sort()方法 格式一: public static <T extends ...
- Java--缓存热点数据,最近最少使用算法
1.最近最少使用算法LRU (Least recently used,最近最少使用) [实现]:最常见的是使用一个链表保存缓存数据 1.新数据插入到链表头部: 2.每当缓存命中(即缓存数据被访问),将 ...
- Lind.DDD.Manager里菜单权限的设计
回到目录 对于一个后台管理系统来说,你的权限设计与安全是重中之重,当你为一个权限分配一些菜单后,当这个权限的用户没有菜单权限时,这个菜单的URL是不可以被用户访问的,而在之前的设计中,没有考虑到这点, ...
- JavaScript调试 - debugger语句
语法: debugger 作用: 启动调试器 备注: 1. 可以将debugger语句放在过程的任何地方以中止执行.2. 使用debugger语句类似于在代码中设置断点. 3. debugger语句中 ...
- js for循环中i++ 和 ++i有什么区别?
平时都是这样写的for循环, for(var i = 0; i < 20 ; i++){ .... } 但我看有的人这样写 for (var i = 0; i < 20 ; ++i) { ...
- NSString 的常用操作
NSString *testStr01=@"HelloWord"; NSString *testStr02=[testStr01 substringToIndex:];//取头(从 ...
- Linux-1:安装&忘记密码&CRT连接centos 6.5
我是在虚拟机VM安装的centos 6.5 一.Linux安装 Ctrl + Alt:鼠标退出LINUX界面 安装我是参考,当然也可以根据网上教程安装:http://oldboy.blog.51cto ...
- LinkedList 浅析示例
package com.smbea.demo; import java.util.Iterator; import java.util.LinkedList; import java.util.Lis ...
- wireshark 实用过滤表达式(针对ip、协议、端口、长度和内容)
首先说几个最常用的关键字,"eq" 和 "=="等同,可以使用 "and" 表示并且,"or"表示或者."!& ...
- 【转】JavaScript中的原型和继承
请在此暂时忘记之前学到的面向对象的一切知识.这里只需要考虑赛车的情况.是的,就是赛车. 最近我正在观看 24 Hours of Le Mans ,这是法国流行的一项赛事.最快的车被称为 Le Mans ...