问题是我有一个基于数组的二进制搜索树,该树需要从从文件IO读取的文本文件中吸收近2000行信息。
但是,我不断得到java.lang.ArrayIndexOutOfBoundsException: 3012
。
我试图在不超出Java VM限制的情况下,使数组尽可能地大。但这还不足以存储文件。
我用较小的文件进行了测试,效果很好。
可以在以下位置找到文本文件的示例:https://www.asxhistoricaldata.com/
public class ArrayBinary implements Serializable
{
private class Entry implements Serializable
{
private int key;
private Object element;
public Entry (int k, Object e)
{
this.key = k;
this.element = e;
}
}
private Entry [] tree;
private int size;
private int height;
private int left;
private int right;
private static final int MAXCAPACITY = 2000;
public ArrayBinary()
{
size = 0;
height = 1;
left = 0;
right = 0;
tree = new Entry[MAXCAPACITY];
for (int i = 0; i < MAXCAPACITY; i++)
{
tree[i] = null;
}
}
public void insert(int key, Object value)
{
size++;
insert(key, value, 0);
}
public void insert (int key, Object value, int index)
{
boolean added = false;
//System.out.println(key);
if (tree[index] == null)
{
Entry node = new Entry(key, value);
tree[index] = node;
added = true;
}
else if (key < tree[index].key)
{
insert(key, value, index * 2 + 1);
}
else if (key == tree[index].key)
{
insert(key, value, index * 2 + 2);
}
else
{
insert(key, value, index * 2 + 2);
}
}
}
这就是将文件读入树中的内容(只是忽略其他两棵树)。
import java.io.*;
import java.util.*;
public class TreeFileIO
{
private BTree4 tempBt;
private BinarySearchTree tempBst;
private ArrayBinary tempArraybst;
public Object read(String fileName, int type, int degree)
{
switch(type)
{
case 1:
//degree is only needed for b-tree
tempBt = new BTree4(degree);
break;
case 2:
tempBst = new BinarySearchTree();
break;
case 3:
tempArraybst = new ArrayBinary();
break;
}
Scanner sc = new Scanner(System.in);
FileInputStream fileStrm = null;
String line;
int key;
try
{
//open the file
fileStrm = new FileInputStream (fileName + ".txt");
InputStreamReader rdr = new InputStreamReader(fileStrm);
BufferedReader bufRdr = new BufferedReader (rdr);
line = bufRdr.readLine();
while (line != null)
{
switch(type)
{
case 1:
tempBt.insert(getKey(line), line);
break;
case 2:
tempBst.insert(getKey(line), line);
break;
case 3:
tempArraybst.insert(getKey(line), line);
break;
}
line = bufRdr.readLine();
}
//Closes the file once we're done
fileStrm.close();
}
catch (IOException e)
{
if (fileStrm != null)
{
try
{
fileStrm.close();
}
catch (IOException ex2)
{
}
}
System.out.println("Error");
}
//Now send this tree to TreeProfiler for use
switch(type)
{
case 1:
return tempBt;
case 2:
return tempBst;
case 3:
return tempArraybst;
}
return null;
}
//create a key using value from each line to avoid degenerate
public int getKey(String csvRow)
{
StringTokenizer strTok = new StringTokenizer(csvRow, ",");
int key = 0;
try
{
strTok.nextToken();
strTok.nextToken();
strTok.nextToken();
strTok.nextToken();
strTok.nextToken();
strTok.nextToken();
//Skip to last value to use as a key
return key = Integer.parseInt(strTok.nextToken());
}
catch (Exception e)
{
System.out.println(e);
throw new IllegalStateException("CSV row had invalid format");
}
}
}
我希望读取文件时不会报告任何超出范围的数组,并且可以容纳整个2000 int文件。
答案 0 :(得分:0)
主要问题是您正在使用的数据似乎已排序。
通过遍历值的有序数组来填充树数据结构,将导致树降级为列表,这就是得到索引的那些巨大要求的原因;每个新项目都会添加到树的右侧,从而使索引不断加倍。
解决此问题的最有效方法是通过将元素放在数据集的中间来填充树,然后用剩余的两半递归地重复该过程;下面的元素和上面的元素。这样,数组将完全填充。
另一种选择是从数据集中以随机顺序获取元素。通常,您可能需要比提供的2000容量更多的容量,但这实际上是可行的。
最后一种选择是保留相同的代码并重新整理数据。
由于您使用流来读取CSV,因此前两种解决方案可能太复杂了,因此最好的解决方案是重新排列文本文件的行并增加数组的容量。您可以在线找到各种文本文件洗牌器。