首页新闻找找看学习计划

一个二分查找的问题(逐字二分查找)

0
悬赏园豆:20 [已解决问题] 解决于 2018-03-30 17:15

是这样的:一个中文数组, 一个key, 要求是在数组中用二分查找找到key.当然这不难
但是要求还有:在数组中找到以key为前缀的所有词, 要求一个字一个字的用二分,比如"大白兔" 数组排序后,二分找到第一个字是"大"的范围,在这个范围继续二分找第二个字是"白"这样. 这样逐字二分查找最终找到,key为前缀的 所有词.

接下来要求是 key是一句话,用上述方法找出这句话中的最长的词(数组中的词)

我真是一脸懵逼了.

问题来源如下:

https://wenku.baidu.com/view/f749b351f01dc281e53af094.html

燃烧的小腿毛的主页 燃烧的小腿毛 | 初学一级 | 园豆:166
提问于:2018-03-29 12:33
< >
分享
最佳答案
1

汉字的字典树还真没写过。不过可以试试。你这个问题也太复杂了吧?有三个要求?

1.查找中文数组中的key

2.在数组中找到所有key为前缀的词

3.在key中找到一个最长的词(出现在数组中)  

这三个要求其实是独立的三个问题,对吧

 

如果你愿意等,我下班后去写一写。

 

——————————————————————2018.3.30更新——————————————————

一开始使用c语言,后来发现char数组和指针再结合汉字是一个让你脑袋能炸掉的组合。所以用了c++。时间复杂度时间复杂度O((logn)^2) 。实现的比较简单,仅有几个功能函数,各种变量也是有点随意。测试结果如下:

 

//
//  main.cpp
//  sss
//
//  Created by 小康 on 29/03/2018.
//  Copyright © 2018 小康. All rights reserved.
//

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <map>

using namespace std;

//字典树,根节点为1
struct Node
{
    
    int length=0;
    string lines="";
    map<string,int> words;
    map<string,int> count;
}tree[1005];
//表示字典树的节点数
int len;
string res[105];

/*char* word(char *aw,int j)
{
    char w[105]={'\0'};
    int p=0;
    for(int i=j*3;i<j*3+3;i++)
    {
        w[p++]=aw[i];
    }
    return w;
}
void strcatt(char *as,char *bs,int j)
{
    int l=strlen(as);
    
    for(int i=l;i<l+3;i++)
    {
        as[i]=bs[j*3+i-l];
    }
}*/
//往字典树立插入字符串
void insert(string a,int i,int j)
{
  
    if(i==a.length()/3)
    {
        
        return;
    }
    if(tree[j].words[a.substr(i*3,3)]!=0)
    {
        insert(a,i+1,tree[j].words[a.substr(i*3,3)]);
    }
    else
    {
        tree[j].words[a.substr(i*3,3)]=++len;
        tree[j].lines+=a.substr(i*3,3);
        tree[j].length+=3;
        if(i==a.length()/3-1)
            tree[j].count[a.substr(i*3,3)]++;
        insert(a,i+1,len);
    }
}
/*
bool equal(char *ae,char *be)
{
    if(strlen(ae)!=strlen(be))
        return false;
    else
    {
        for(int i=0;i<strlen(ae);i++)
        {
            if(ae[i]!=be[i])
                return false;
        }
        return true;
    }
        
}*/
void remove(Node &s,string x)
{
    int y=0;
    for(int i=0;i<s.length/3;i++)
    {
        if(s.lines.substr(i*3,3)==x)
        {
            y=i;break;
        }
    }
    for(int i=y*3;i<s.length;i++)
    {
        s.lines[i]=s.lines[i+3];
    }
    s.length-=3;
}
//删除字符串
bool del(string a,int i,int j)
{
    if(tree[j].words[a.substr(i*3,3)]==0)
        return false;
    else
    {
        int x=tree[j].words[a.substr(i*3,3)];
        tree[j].words[a.substr(i*3,3)]=0;
        remove(tree[j],a.substr(i*3,3));
        return del(a,i+1,x);
    }
}

//查询某个字符串为前缀的所有词

void QueryPrefix(string a,int i,int j,string str,int &l2)
{
    if(i>=a.length()/3)
    {
        if(tree[j].length==0)
        {
          
            return;
        }
        
        for(int k=0;k<tree[j].length/3;k++)
        {
           
            str+=tree[j].lines.substr(k*3,3);
          
            if(tree[j].count[tree[j].lines.substr(k*3,3)]!=0)
                res[l2++]=str;
            QueryPrefix(a, i+1, tree[j].words[tree[j].lines.substr(k*3,3)],str,l2);
            
        }
    }
    else if(tree[j].words[a.substr(i*3,3)]==0)
        return;
    else
    {
        //strcatt(str,aq,i);
        str+=a.substr(i*3,3);
      
        if(i==a.length()/3-1)
            res[l2++]=str;
        QueryPrefix(a, i+1, tree[j].words[a.substr(i*3,3)],str,l2);
    }
}
//查询某个字符串是否存在
bool IsExist(string a,int i,int j)
{
    if(i==a.length()/3)
    {
        return false;
    }
 
    if(tree[j].words[a.substr(i*3,3)]==0)
        return false;
    else
    {
        if(i==a.length()/3-1&&tree[j].count[a.substr(i*3,3)]!=0)
        {
            return true;
        }
        return IsExist(a, i+1,tree[j].words[a.substr(i*3,3)]);
    }
}
string input[1005];
int n;
string output;

int main()
{
    printf("请输入要插入字典树的字符串数组的长度\n");
    scanf("%d",&n);
    printf("请输入要插入字典树的字符串数组\n");
    len=1;
    for(int i=0;i<n;i++)
    {
        cin>>input[i];
        insert(input[i],0,1);
    }
    
    printf("请输入key\n");
    cin>>output;
    printf("查找key是否存在\n");
    IsExist(output,0, 1);
    if(IsExist(output,0,1))
        printf("key存在\n");
    else
        printf("key不存在\n");
    
    printf("找出所有以key为前缀的字符串\n");
    

    string str="";
    int l1=0;int l2=0;
    QueryPrefix(output, 0, 1,str, l2);
    for(int i=0;i<l2;i++)
        cout<<res[i]<<endl;
    
    
    
    printf("key为一句话,找出key中存在的最长词\n");
    printf("输入key\n");
    cin>>output;
    int le=output.length();
    string xx="";
    string ans="";
    int res2=0;
    for(int i=0;i<le/3;i++)
    {
        for(int l=3;i*3+l<=le;l+=3)
        {
            xx=output.substr(i*3,l);
            
            if(IsExist(xx, 0, 1))
            {
                if(res2<l)
                {
                    res2=l;
                    ans=xx;
                }
            }
        }
    }
    if(res2==0)
    {
        printf("不存在\n");
    }
    else
    {
        cout<<ans<<endl;
    }
    return 0;
    
}
View Code

 

收获园豆:20
Shendu.CC | 小虾三级 |园豆:1914 | 2018-03-29 13:11

是的  后边的链接是个论文,其实我是想实现里边的 第三个方法:基于逐字二分的XXXX,,像里边提到的例子一样实现,但是也一直是懵逼状态, 自己对java的理解也不足 没找到好的办法;

先谢谢你了,麻烦了.

燃烧的小腿毛 | 园豆:166 (初学一级) | 2018-03-29 13:22

@燃烧的小腿毛: 我写的是基于TRIE索引树的汉字字典树哦~

Shendu.CC | 园豆:1914 (小虾三级) | 2018-03-29 13:26

@Shendu.cc: 那也很好,正好论文里边提到的都想学一下,我描述的可能有不大准确的,方便的话你看下论文里边那个例子,那个说的就很明白

燃烧的小腿毛 | 园豆:166 (初学一级) | 2018-03-29 13:29

@燃烧的小腿毛: 好的👌

Shendu.CC | 园豆:1914 (小虾三级) | 2018-03-29 13:30

@燃烧的小腿毛: 在不在。今天上午有事情,刚才补好了。

Shendu.CC | 园豆:1914 (小虾三级) | 2018-03-30 16:45
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册