Java实现80亿长字符串子串查找(多线程升级)

4 篇文章 0 订阅

前言

  • 本博客文章只有代码块,一些输出和 try…catch 等内容没有写在这里。
  • 本博客文章的目的是熟悉 多线程 的操作,Java新手,如有不妥之处请指正!
  • 本文的基础是我的这篇博客,改动了最后字符串查找部分。生成字符串文件、插入子串部分的瓶颈在于IO,就没改动了。

原版代码

long n = 0;  // n存放当前的文件的绝对位置
while (true) {
  int len; // len存放读取到的内容的长度,为-1时代表文件结束
  if (n == 0) {
      len = fr.read(cbuf);
  } else {
      // 保留上一个缓冲区的末尾作为这次缓冲区的头部。
      for (int i = 0; i < maxLen; ++i) {
          cbuf[i] = cbuf[bufLen - maxLen + i];
      }
      len = fr.read(cbuf, maxLen, bufLen - maxLen);
  }
  if (len == -1) break; // 文件结束

  // 遍历子字符串
  for (int i = 0; i < subStrBuf.length; ++i) {
      // 如果位置值不是-1就代表查找到了,不用再查
      if (indexs[i] == -1) {
          // 自己写的Find函数,获取子串在cbuf中的位置
          int tempIndex = Find(cbuf, subStrBuf[i]);
          if (tempIndex != -1) {
              // n为cbuf在整个文件中的位置
              indexs[i] = n + tempIndex;
          }
      }
  }
  n += len;
} // 文件结束

将16至26行代码重写为

for (int i = 0; i < subStrBuf.length; ++i) {
    // 如果位置值不是-1就代表查找到了,不用再查
    if (indexs[i] == -1) {
        // 创建一个查找线程,设置给定子串在整个文件中的位置
        finds[i] = new FindThread(cbuf, subStrBuf[i], indexs, i, n);
        finds[i].start();
    }
}
// 等待查找线程结束
for (int i = 0; i < finds.length; ++i) {
    if (finds[i].isAlive()) {
        finds[i].join();
    }
}

查找线程的定义

class FindThread extends Thread {
    private char[] str; // 母串(缓冲区)
    private char[] subStr; // 子串
    private long[] indexs; // 保存位置信息的数组
    private int p; // 保存位置到数组中的第p为
    private long baseIndex; // 缓冲区在文件中的位置

    public FindThread(char[] str, char[] subStr, long[] indexs, int p, long baseIndex) {
        this.str = str;
        this.subStr = subStr;
        this.indexs = indexs;
        this.p = p;
        this.baseIndex = baseIndex;
    }

    @Override
    public void run() {
        // 和原版一样的朴素字符串查找算法
        for (int i = 0; i < this.str.length; ++i) {
            int j;
            for (j = 0; j < this.subStr.length; ++j) {
                if (i + j >= this.str.length) {
                    this.indexs[this.p] = -1;
                    return;
                }
                if (this.str[i + j] != this.subStr[j]) break;
            }
            if (j == this.subStr.length) {
                this.indexs[this.p] = this.baseIndex + i;
                return;
            }
        }
        this.indexs[this.p] = -1;
        return;
    }
}

感言

  • 升级前查找需要11分钟,升级后只需6分钟,效率提升明显。
  • 这里用的查找算法仍然是朴素字符串查找算法,时间复杂度较高。然而我发现,时间复杂度更低的sunday算法所用时间比朴素字符串查找还要长很多。仔细分析才发现,原因是我的数据太极端。80亿长的字符串中,只有子串是字母,其它字符全是数字,这样一来,朴素字符串查找算法反而成为了速度最快的一种算法,呵呵。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值