二进制搜索数组以显示包含字符串字段的行
Binary searching array to display row containing string field
我有一个按钮,它应该接受 'surname' 字符串输入,在目录数组中搜索与该姓氏相关的 'record' 结构,并将该记录输出到列表视图。该目录由多行 3 个字符串记录结构组成:姓氏、名字、分机号。
经过数天搜索类似的 SO 问题和其他来源,我拼凑了似乎最适合我的问题的方法,但出于某种原因,我的主要搜索方法并没有引用我的辅助方法。你能告诉我你为什么这么认为吗?如果我设法使参考有效,你认为它是否有效?如果不行,还有其他建议吗?
仅供参考,我的 if 语句有点不守规矩,因为我的项目要求姓氏不区分大小写并接受部分字符串匹配。
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;
}
编辑:根据 Olivier Jacot-Descombes 的回答更新了代码:
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;
}
您的 SearchSurname
方法调用 Array.BinarySearch
,这是 Array Class 的静态方法。如果你想调用你自己的方法,你必须这样写:
int surnameIndex = BinarySearch(directory, txtSurname.Text); // Without "Array."
您正在使用不区分大小写的比较,因为 String.Compare
的第三个参数是 true
。
你可以使用
if (string.StartsWith(directory[middle], searchTerm,
StringComparison.CurrentCultureIgnoreCase))
只搜索名字的开头。但是如果几个名字匹配就会有问题。例如。您正在搜索 "smit"
并且数组中有 "Smith"
和 "Smithy"
。因此,您必须测试找到的匹配项之前和之后的条目,并且 return 所有匹配项作为可能的结果。
我有一个按钮,它应该接受 'surname' 字符串输入,在目录数组中搜索与该姓氏相关的 'record' 结构,并将该记录输出到列表视图。该目录由多行 3 个字符串记录结构组成:姓氏、名字、分机号。
经过数天搜索类似的 SO 问题和其他来源,我拼凑了似乎最适合我的问题的方法,但出于某种原因,我的主要搜索方法并没有引用我的辅助方法。你能告诉我你为什么这么认为吗?如果我设法使参考有效,你认为它是否有效?如果不行,还有其他建议吗?
仅供参考,我的 if 语句有点不守规矩,因为我的项目要求姓氏不区分大小写并接受部分字符串匹配。
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;
}
编辑:根据 Olivier Jacot-Descombes 的回答更新了代码:
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;
}
您的 SearchSurname
方法调用 Array.BinarySearch
,这是 Array Class 的静态方法。如果你想调用你自己的方法,你必须这样写:
int surnameIndex = BinarySearch(directory, txtSurname.Text); // Without "Array."
您正在使用不区分大小写的比较,因为 String.Compare
的第三个参数是 true
。
你可以使用
if (string.StartsWith(directory[middle], searchTerm,
StringComparison.CurrentCultureIgnoreCase))
只搜索名字的开头。但是如果几个名字匹配就会有问题。例如。您正在搜索 "smit"
并且数组中有 "Smith"
和 "Smithy"
。因此,您必须测试找到的匹配项之前和之后的条目,并且 return 所有匹配项作为可能的结果。