Двоичный поисковый массив для отображения строки, содержащей строковое поле - PullRequest
0 голосов
/ 19 января 2020

У меня есть кнопка, которая должна принимать строку ввода «фамилия», искать в массиве каталогов структуру «запись», соответствующую этой фамилии, и выводить эту запись в список. Каталог состоит из множества строк из 3 структур записей: фамилия, имя, extcode.

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

private void SearchSurname()
    {
        Array.Sort(directory, (x, y) => String.Compare(x.surname, y.surname));

        ClearForm();
        int surnameIndex = Array.BinarySearch(directory, txtSurname.Text);

        if (directory[surnameIndex].surname.ToUpper().Substring(0, txtSurname.Text.Length).Contains(txtSurname.Text.ToUpper()))
        {
            ListViewItem record = new ListViewItem();

            // Send each field in current record to single listview item
            record.Text = (Convert.ToString(txtSurname.Text));
            record.SubItems.Add(Convert.ToString(txtForename.Text));
            record.SubItems.Add(Convert.ToString(txtExtCode.Text));

            // Display new record listview item in listview
            lvDirectory.Items.Add(record);
        }
    }

    public int BinarySearch(string[] directory, string searchTerm)
    {
        int first = 0;
        int last = directory.Length - 1;
        int position = -1;
        bool found = false;
        int compCount = 0;
        searchTerm = txtSurname.Text;

        while (found != true && first <= last)
        {
            int middle = (first + last) / 2;

            if (string.Compare(directory[middle], searchTerm, true) == 0)
            {
                found = true;
                position = middle;
                compCount++;
            }
            else if (string.Compare(directory[middle], searchTerm, true) > 0)
            {
                last = middle;
                compCount++;
            }
            else
            {
                first = middle;
                compCount++;
            }
        }
        return position;
    }

Редактировать: Обновленный код для ответа Оливье Жако-Дескомба:

private void SearchSurname()
    {
        // Sort directory alphabetically by surname
        Array.Sort(directory, (x, y) => String.Compare(x.surname, y.surname));

        ClearForm();

        // In directory, find line index of search term
        int surnameIndex = BinarySearch(directory, txtSurname.Text);

        ListViewItem record = new ListViewItem();

        // Send each field in current record to single listview item
        record.Text = (Convert.ToString(directory[surnameIndex].surname));
        record.SubItems.Add(Convert.ToString(directory[surnameIndex].forename));
        record.SubItems.Add(Convert.ToString(directory[surnameIndex].extCode));

        // Display new record listview item in listview
        lvDirectory.Items.Add(record);
    }

    private int BinarySearch(record[] directory, string searchTerm)
    {
        int first = 0;
        int last = directory.Length - 1;
        int surnameIndex = -1;
        bool indexFound = false;

        // While index not found and there are still points in the array to check
        while (indexFound != true && first < last)
        {
            int middle = (first + last) / 2;

            // If surname field in middle record of directory array matches the search term
            if (string.Compare(directory[middle].surname, searchTerm, true) == 0)
            {
                // Index found!
                indexFound = true;
                surnameIndex = middle;
                MessageBox.Show("If 1");
            }
            // If surname field in middle record of directory array is higher, alphabetically, than the search term
            else if(string.Compare(directory[middle].surname, searchTerm, true) > 0)
            {
                // The next search will be between the first and the current middle records of the array
                last = middle;
                MessageBox.Show("If 2");
            }
            // If surname field in middle record of directory array is lower, alphabetically, than the search term
            else
            {
                // The next search will be between the current middle and the highest records of the array
                first = middle;
                MessageBox.Show("If 3");
            }
        }
        return surnameIndex;
    }

1 Ответ

1 голос
/ 19 января 2020

Ваш SearchSurname метод вызывает Array.BinarySearch, что является методом c класса Array Class . Если вы хотите вызвать свой собственный метод, вам нужно будет написать:

int surnameIndex = BinarySearch(directory, txtSurname.Text); // Without "Array."

Вы используете сравнение без учета регистра через 3-й параметр String.Compare, являющийся true.

Вы можете использовать

if (string.StartsWith(directory[middle], searchTerm,
                      StringComparison.CurrentCultureIgnoreCase))

Для поиска только начала имен. Но есть проблема, если несколько имен совпадают. Например, вы ищете "smit", и у вас есть "Smith" и "Smithy" в массиве. Поэтому вам нужно будет проверить записи до и после найденного совпадения и вернуть все совпадающие в качестве возможных результатов.

...