Бинарный поиск на основе массива вне границ - PullRequest
0 голосов
/ 23 мая 2019

Проблема в том, что у меня есть дерево двоичного поиска на основе массива, которое должно принимать почти 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");
            }
    }
}

Я ожидаю, что файл будет прочитан без сообщения о каком-либо массиве вне границ, и в нем может содержаться весь int-файл 2000 года.

1 Ответ

0 голосов
/ 23 мая 2019

Основная проблема заключается в том, что используемые вами данные, похоже, упорядочены.

Заполнение древовидной структуры данных путем итерации по упорядоченному массиву значений приведет к тому, что дерево будет преобразовано в список, которыйявляется причиной того, что вы получаете эти огромные требования к показателям;каждый новый элемент добавляется в правую часть дерева, в результате чего индексы непрерывно удваиваются.

Самый эффективный способ решения этой проблемы - заполнить дерево, поместив элемент в середину набора данных.и затем рекурсивно повторять процесс с оставшимися двумя половинами;элементы ниже и те, что над ним.Таким образом, массив будет заполняться точно.

Другая альтернатива - брать элементы в случайном порядке из набора данных.В среднем случае вам может потребоваться больше емкости, чем предоставляется 2000, но на самом деле это возможно.

Одна из последних альтернатив - сохранить тот же код и перемешать данные.

Поскольку вы используете поток для чтения CSV, первые два решения могут быть слишком сложными, поэтому лучшее решение - это перемешать строки текстового файла и увеличить емкость массива.Вы можете найти различные текстовые файловые перетасовки онлайн.

...