c++对排序的日期进行二分搜索 ->我需要一个范围(cca)

发布于 2024-12-06 12:34:51 字数 2429 浏览 3 评论 0原文

我对文件进行二分搜索。该文件充满日志消息,其中每行以日期开头(日期或根据事件发生排序)

示例:

  • 2011-09-18 09.38.20.123
  • 2011-09-18 09.38.20.245
  • 2011-09-18 09.38.20.393
  • 2011 -09-18 09.38.20.400
  • 2011-09-18 09.38.20.785

如果我需要找到这个日期,例如:2011-09-18 09.38.20.390 我的二分搜索将找不到完全匹配 - 但我不需要完全匹配,我需要找到最接近的日期(这是我的位置)。

当前代码将在 2011-09-18 09.38.20.245 和 2011-09-18 09.38.20.393 之间跳转。

我需要一些帮助如何修改下面的代码,以便获得最接近的数字。在上述情况下我想要: 2011-09-18 09.38.20.245 (多比少好)

BinarySearch::BinarySearch(QString strFileName,QDateTime dtFrom_target,QDateTime dtTo_target)
{

    QFile file(strFileName);
    qint64 nFileSize = file.size();

    int nNewFromPos;
    int nNewToPos;

    nNewFromPos = Search(file, dtFrom_target, nFileSize);
    nNewToPos  = Search(file, dtFrom_target, nFileSize);

    if(nNewFromPos!=-1 && nNewToPos!=-1){
        // now parse the new range

    }
    else{
        // dates out of bound

    }   
}

int BinarySearch::Search(QFile &file, QDateTime dtKey, int nMax) 
{  
    file.open(QIODevice::ReadOnly);
    char lineBuffer[1024];  
    qint64 lineLength;
    QDateTime dtMid;        
    int mid;
    int min; 
    if(!min) min = 0;


   while (min <= nMax) 
   {
       mid=(min+nMax)/2;    // compute mid point.                               
       file.seek(mid);  // seek to middle of file (position based on bytes)
       qint64 lineLength=file.readLine(lineBuffer,sizeof(lineBuffer)); // read until \n or error

       if (lineLength != -1) //something is read
       {
           // validate string begin (pos = 0) starts with date

           lineLength = file.readLine(lineBuffer, 24); //read exactly enough chars for the date from the beginning of the log file


           if(lineLength == 23)
           {
            dtMid = QDateTime::fromString(QString(lineBuffer),"yyyy-MM-dd HH.mm.ss.zzz"); //2011-09-15 09.38.20.192

                if(dtMid.isValid())
                {
                    if(dtKey > dtMid){
                        min = mid + 1; 
                    }
                    else if(dtKey < dtMid){
                        max = mid - 1; // repeat search in bottom half.
                    }
                    else{
                        return mid;     // found it. return position
                    }
                }
            }
       }
   }
   return -1;    // failed to find key
}

I have a binary search on a file. The file is filled with log messages where each line begins with a date (dates or sorted based on event occurs)

example:

  • 2011-09-18 09.38.20.123
  • 2011-09-18 09.38.20.245
  • 2011-09-18 09.38.20.393
  • 2011-09-18 09.38.20.400
  • 2011-09-18 09.38.20.785

If i need to find this date for example: 2011-09-18 09.38.20.390 my binary search will not find an exact match - but i don't need exact match, i need to find the closest date to it (there is my position).

The current code will jump between 2011-09-18 09.38.20.245 and 2011-09-18 09.38.20.393.

I need some help how to modify the below code so that i get the closest number. In the above situation i would like to have: 2011-09-18 09.38.20.245 (better more than less)

BinarySearch::BinarySearch(QString strFileName,QDateTime dtFrom_target,QDateTime dtTo_target)
{

    QFile file(strFileName);
    qint64 nFileSize = file.size();

    int nNewFromPos;
    int nNewToPos;

    nNewFromPos = Search(file, dtFrom_target, nFileSize);
    nNewToPos  = Search(file, dtFrom_target, nFileSize);

    if(nNewFromPos!=-1 && nNewToPos!=-1){
        // now parse the new range

    }
    else{
        // dates out of bound

    }   
}

int BinarySearch::Search(QFile &file, QDateTime dtKey, int nMax) 
{  
    file.open(QIODevice::ReadOnly);
    char lineBuffer[1024];  
    qint64 lineLength;
    QDateTime dtMid;        
    int mid;
    int min; 
    if(!min) min = 0;


   while (min <= nMax) 
   {
       mid=(min+nMax)/2;    // compute mid point.                               
       file.seek(mid);  // seek to middle of file (position based on bytes)
       qint64 lineLength=file.readLine(lineBuffer,sizeof(lineBuffer)); // read until \n or error

       if (lineLength != -1) //something is read
       {
           // validate string begin (pos = 0) starts with date

           lineLength = file.readLine(lineBuffer, 24); //read exactly enough chars for the date from the beginning of the log file


           if(lineLength == 23)
           {
            dtMid = QDateTime::fromString(QString(lineBuffer),"yyyy-MM-dd HH.mm.ss.zzz"); //2011-09-15 09.38.20.192

                if(dtMid.isValid())
                {
                    if(dtKey > dtMid){
                        min = mid + 1; 
                    }
                    else if(dtKey < dtMid){
                        max = mid - 1; // repeat search in bottom half.
                    }
                    else{
                        return mid;     // found it. return position
                    }
                }
            }
       }
   }
   return -1;    // failed to find key
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情泪▽动烟 2024-12-13 12:34:51

尝试实现相当于 std::equal_range 的算法它返回一对 std::lower_boundstd::upper_bound

  1. 查找排序范围内第一个不小于该值(下界)的元素的位置
  2. 查找排序范围内第一个元素的位置比较大于值(上限)

--

template<typename OutIter>
void ReadLogsInRange(
    std::istream& logStream, Log::Date from, Log::Date to, OutIter out)
{
    Log l = LowerBound(logStream, from);
    *out++ = l;
    while(logStream >> l && l.date < to)
        *out++ = l;
}

完整示例:http://ideone.com/CvIYm

Try to implement an algorithm equivalent to std::equal_range which returns a pair of result of std::lower_bound and std::upper_bound

  1. Find the position of the first element in the sorted range which does not compare less than the value (lower bound)
  2. Find the position of the first element in the sorted range which compares greater than the value (upper bound)

--

template<typename OutIter>
void ReadLogsInRange(
    std::istream& logStream, Log::Date from, Log::Date to, OutIter out)
{
    Log l = LowerBound(logStream, from);
    *out++ = l;
    while(logStream >> l && l.date < to)
        *out++ = l;
}

Full example: http://ideone.com/CvIYm

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文