Java 从未排序的输入返回唯一值的算法
我需要创建一个高效的算法,从未排序的输入返回唯一的值。我不知道输入的长度 由于调用此算法的函数可以随时中止读取,因此我认为使用定义良好的Java 从未排序的输入返回唯一值的算法,java,algorithm,unique,Java,Algorithm,Unique,我需要创建一个高效的算法,从未排序的输入返回唯一的值。我不知道输入的长度 由于调用此算法的函数可以随时中止读取,因此我认为使用定义良好的Iterable实现是正确的方法,因此我不会为非需要的输入浪费额外的处理能力 今天,我使用集合来跟踪我已经读取的值。但我不知道这是否是最有效的算法,因为我的输入长度可能很大 下面的代码是我今天的工作算法: import java.util.Iterator; import java.util.HashSet; import java.util.Set; impo
Iterable
实现是正确的方法,因此我不会为非需要的输入浪费额外的处理能力
今天,我使用集合
来跟踪我已经读取的值。但我不知道这是否是最有效的算法,因为我的输入长度可能很大
下面的代码是我今天的工作算法:
import java.util.Iterator;
import java.util.HashSet;
import java.util.Set;
import java.util.NoSuchElementException;
import java.io.BufferedReader;
import java.io.StringReader;
import java.io.IOException;
public class UniqueValues implements Iterable<String> {
private final Iterator<String> iterator;
public UniqueValues(BufferedReader r) {
this.iterator = new UniqueValuesIterator(r);
}
public Iterator<String> iterator() {
return iterator;
}
static class UniqueValuesIterator implements Iterator<String> {
private final BufferedReader r;
private final Set<String> values = new HashSet<>();
// When 'next' is null, need to get the next value
private String next;
public UniqueValuesIterator(BufferedReader r) {
this.r = r;
}
public boolean hasNext() {
// Good point from OldCurmudgeon
if(next != null) return true;
try {
String line;
while((line = r.readLine()) != null) {
if(values.add(line)) { // add() returns 'true' when it is not a duplicate value.
next = line;
return true;
}
}
} catch(IOException e) { }
return false;
}
public String next() {
if(next == null) {
if(! hasNext() ) throw new NoSuchElementException();
}
final String temp = next;
next = null;
return temp;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
// For testing
public static void main(String... args) {
final StringReader r = new StringReader("value1\nvalue6\nvalue1\nvalue3\nvalue3\nvalue6\nvalue1\nvalue6");
for(final String value : new UniqueValues(new BufferedReader(r)) ) {
System.out.println(value);
}
/* Output is (order is not important):
*
* line 1
* line 6
* line 3
*/
}
}
import java.util.Iterator;
导入java.util.HashSet;
导入java.util.Set;
导入java.util.NoSuchElementException;
导入java.io.BufferedReader;
导入java.io.StringReader;
导入java.io.IOException;
公共类UniqueValues实现了Iterable{
私有最终迭代器;
公共唯一值(BufferedReader r){
this.iterator=新的UniqueValuesIterator(r);
}
公共迭代器迭代器(){
返回迭代器;
}
静态类UniqueValuesIterator实现迭代器{
专用最终缓冲读取程序r;
私有最终集值=新HashSet();
//当“next”为空时,需要获取下一个值
私有字符串下一步;
公共唯一估值器(BufferedReader){
这个。r=r;
}
公共布尔hasNext(){
//OldCurmudgeon的观点很好
if(next!=null)返回true;
试一试{
弦线;
而((line=r.readLine())!=null){
if(values.add(line)){//add()在不是重复值时返回'true'。
下一个=行;
返回true;
}
}
}捕获(IOE){}
返回false;
}
公共字符串next(){
if(next==null){
如果(!hasNext())抛出新的NoSuchElementException();
}
最终字符串温度=下一个;
next=null;
返回温度;
}
公共空间删除(){
抛出新的UnsupportedOperationException();
}
}
//用于测试
公共静态void main(字符串…参数){
最终StringReader r=新StringReader(“值1\nvalue6\nvalue1\nvalue3\nvalue3\nvalue6\nvalue1\nvalue6”);
for(最终字符串值:新的唯一值(新的BufferedReader(r))){
系统输出打印项次(值);
}
/*输出为(顺序不重要):
*
*第1行
*第6行
*第3行
*/
}
}
它是否有更好的算法来实现这一点?这似乎很好,但是我很想让代码不那么通用,除非您经常这样做
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
Set<String> lines = new HashSet<>();
for(String line; (line = br.readLine()) != null;) {
if(lines.add(line)) {
// do something
}
}
}
try(BufferedReader br=new BufferedReader(new FileReader(file))){
Set line=new HashSet();
for(字符串行;(line=br.readLine())!=null;){
如果(行。添加(行)){
//做点什么
}
}
}
或者,如果您必须返回一个Iterable,您可以这样做
public static Set<String> uniqueLines(File file) {
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
Set<String> lines = new HashSet<>();
for(String line; (line = br.readLine()) != null;)
lines.add(line))
return lines;
}
}
公共静态设置唯一行(文件){
try(BufferedReader br=new BufferedReader(new FileReader(file))){
Set line=new HashSet();
for(字符串行;(line=br.readLine())!=null;)
行。添加(行))
回流线;
}
}
如果您的输入仅由字符串组成,您可以使用来跟踪它们。它具有O(字符串长度)查找和插入时间,并且比哈希映射更节省空间
不过有一点需要注意:trie在每个树节点上都有相当大的开销,因此只有当输入足够大且其元素足够相似时,它才会变得更加有效。例如,它不会给随机生成的字符串带来任何好处。如果(next!=null)您应该使用
if(next!=null)
保护您的hasNext
。用户可以随意调用hasNext
,而不调用next
。在这种情况下,您将转到下一项。@dudinha dedalus,Set has iterator()方法,它可以返回iterate ablecollection@dudinha-dedalus不清楚为什么这是一个要求,但您可以使用第二个示例。@PeterLawrey在第二个示例中,代码将读取所有输入(可能很大),主代码需要很长时间才能开始处理某些内容。使用我的方法,只要有唯一的数据,主代码就可以处理,如果不需要更多的数据,就可以停止使用迭代器。这有意义吗?@dudinha dedalus这是有意义的,但是线程完成的工作量可能是相同的,并且它可能会使用一种或另一种方法提前完成,这取决于它的使用方式。