基于数组的二进制搜索超出范围

时间:2019-05-23 02:20:06

标签: java arrays file-io binary-search-tree

问题是我有一个基于数组的二进制搜索树,该树需要从从文件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文件。

1 个答案:

答案 0 :(得分:0)

主要问题是您正在使用的数据似乎已排序。

通过遍历值的有序数组来填充树数据结构,将导致树降级为列表,这就是得到索引的那些巨大要求的原因;每个新项目都会添加到树的右侧,从而使索引不断加倍。

解决此问题的最有效方法是通过将元素放在数据集的中间来填充树,然后用剩余的两半递归地重复该过程;下面的元素和上面的元素。这样,数组将完全填充。

另一种选择是从数据集中以随机顺序获取元素。通常,您可能需要比提供的2000容量更多的容量,但这实际上是可行的。

最后一种选择是保留相同的代码并重新整理数据。

由于您使用流来读取CSV,因此前两种解决方案可能太复杂了,因此最好的解决方案是重新排列文本文件的行并增加数组的容量。您可以在线找到各种文本文件洗牌器。