字符串 C# 的桶排序问题
Issue with bucket sort for strings C#
我正在编写一个程序,该程序使用学生 ID # 字段、学生名字字段和学生姓氏字段接收学生信息数据。用户将为每个学生(最多 20 个学生)输入数据,或者直到用户在学生 ID 字段中输入“999”。接下来我想根据姓氏字段将学生信息分类到两个单独的桶中。
我在正确分离水桶时遇到问题。我将使用 CompareTo 方法来比较学生姓氏数组的姓氏字符串,但是当我打印存储桶时,它们会混淆。例如,以 A-K 开头的姓氏应放入 'low values' 存储桶,以 J-Z 开头的姓氏应放入 'high values' 存储桶。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _123_Assignment2
{
using System;
using static System.Console;
class Program
{
struct student
{
public int studentId;
public string firstName;
public string lastName;
};
static void Main(string[] args)
{
student[] studentInfo = new student[20];
string[] bucketLow = new string[20];
string[] bucketHigh = new string [20];
int x = 0;
int y = 0;
int z = 1;
WriteLine("Enter student ID number:");
studentInfo[x].studentId = Convert.ToInt32(ReadLine());
while (studentInfo[x].studentId != 999)
{
WriteLine("Enter first name:");
studentInfo[x].firstName = ReadLine();
WriteLine("Enter last name:");
studentInfo[x].lastName = ReadLine();
x++;
WriteLine("Enter student ID number:");
studentInfo[x].studentId = Convert.ToInt32(ReadLine());
}
for (int j = 0; j < x; j++)
{
if(studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0)
bucketLow[y] = studentInfo[j].lastName;
else
bucketHigh[y] = studentInfo[j].lastName;
y++;
z++;
}
WriteLine("Unsorted Table:");
for (int j = 0; j < studentInfo.Length; j++)
{
WriteLine("{0}{1}{2}",studentInfo[j].studentId,studentInfo[j].firstName,
studentInfo[j].lastName);
}
WriteLine("Bucket 1:");
for (int j = 0; j < x; j++)
{
WriteLine(bucketLow[j]);
}
WriteLine("Bucket 2:");
for (int j = 0; j < x; j++)
{
WriteLine(bucketHigh[j]);
}
}
}
}
我认为我没有正确编写 CompareTo 方法,我尝试分别从数组的开头和结尾进行排序,并始终得到相同的结果?
由于这似乎是家庭作业,所以我不会实际为您编写正确的代码。但这里至少有一些问题:
- 直接解决您的问题,您必须对数组元素进行排序的代码使用了错误的比较。如果您有两个桶,并且您希望一个桶代表从
A
到 K
开头的姓氏,另一个代表从 L
到 Z
开头的姓氏,那么您需要与 K
或 L
进行比较以确定正确的桶。与其他名称进行比较只会使数据随机化。 string.Compare(studentInfo[j].lastName, "L", StringComparison.CurrentCultureIgnoreCase) < 0
之类的东西应该可以工作。
- 您需要维护两个索引,一个用于每个存储桶,并且只有在您实际将学生记录复制到该存储桶时才增加该存储桶的索引。
- 如果您实际尝试输入 20 个学生的数据,您当前的代码将崩溃并显示
IndexOutOfRangeException
,因为您递增 x
并将 ID 值存储到数组中而没有检查您是否已输入 20 个学生的数据。输入 20 个学生后,即使用户输入 999
,while
条件也不会检查,直到为时已晚并且代码已经尝试将值存储到数组中。
可能还有其他问题;这些是我第一眼就注意到的。
为了将来参考,在 Stack Overflow 上提问时,您应该确保提供良好的 Minimal, Complete, and Verifiable code example。你接近了;至少代码是完整的。但不要让其他 SO 用户输入您的测试数据。编写一个单独的程序,其中包含所有内置数据,没有用户提示,并且不做 任何 不是重现您遇到的问题所必需的事情.
我不认为你排序有效(j 和 z 比较):
studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0
尝试简化您的桶排序 - 如果您知道您的桶是 A-K 和 J-Z,也许您应该替换以下部分:
for (int j = 0; j < x; j++)
{
if(studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0)
bucketLow[y] = studentInfo[j].lastName;
else
bucketHigh[y] = studentInfo[j].lastName;
y++;
z++;
}
}
试试这样的东西:
for (var i = 0; i < studentInfo.Length; i++)
{
if (studentInfo[i].lastName[0] <= 'K')
bucketLow[y] = studentInfo[i].lastName;
else
bucketHigh[y] = studentInfo[i].lastName;
y++;
}
(当然还要检查您是否输入了至少 1 个字符的有效内容等等...)
如果您必须使用结构和数组,那么您可以考虑使用下面的代码将名称分隔到适当的存储桶中。正如我评论的那样,您需要两个索引,每个存储桶一个。因为你固定数组大小为20,如果小于20,输出结果时会出现空行。
x = studentInfo.Length;
int lowIndex = 0;
int highIndex = 0;
for (int j = 0; j < x; j++) {
if (String.CompareOrdinal(studentInfo[j].lastName, "L") < 0) {
bucketLow[lowIndex] = studentInfo[j].lastName;
lowIndex++;
} else {
bucketHigh[highIndex] = studentInfo[j].lastName;
highIndex++;
}
}
我正在编写一个程序,该程序使用学生 ID # 字段、学生名字字段和学生姓氏字段接收学生信息数据。用户将为每个学生(最多 20 个学生)输入数据,或者直到用户在学生 ID 字段中输入“999”。接下来我想根据姓氏字段将学生信息分类到两个单独的桶中。
我在正确分离水桶时遇到问题。我将使用 CompareTo 方法来比较学生姓氏数组的姓氏字符串,但是当我打印存储桶时,它们会混淆。例如,以 A-K 开头的姓氏应放入 'low values' 存储桶,以 J-Z 开头的姓氏应放入 'high values' 存储桶。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _123_Assignment2
{
using System;
using static System.Console;
class Program
{
struct student
{
public int studentId;
public string firstName;
public string lastName;
};
static void Main(string[] args)
{
student[] studentInfo = new student[20];
string[] bucketLow = new string[20];
string[] bucketHigh = new string [20];
int x = 0;
int y = 0;
int z = 1;
WriteLine("Enter student ID number:");
studentInfo[x].studentId = Convert.ToInt32(ReadLine());
while (studentInfo[x].studentId != 999)
{
WriteLine("Enter first name:");
studentInfo[x].firstName = ReadLine();
WriteLine("Enter last name:");
studentInfo[x].lastName = ReadLine();
x++;
WriteLine("Enter student ID number:");
studentInfo[x].studentId = Convert.ToInt32(ReadLine());
}
for (int j = 0; j < x; j++)
{
if(studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0)
bucketLow[y] = studentInfo[j].lastName;
else
bucketHigh[y] = studentInfo[j].lastName;
y++;
z++;
}
WriteLine("Unsorted Table:");
for (int j = 0; j < studentInfo.Length; j++)
{
WriteLine("{0}{1}{2}",studentInfo[j].studentId,studentInfo[j].firstName,
studentInfo[j].lastName);
}
WriteLine("Bucket 1:");
for (int j = 0; j < x; j++)
{
WriteLine(bucketLow[j]);
}
WriteLine("Bucket 2:");
for (int j = 0; j < x; j++)
{
WriteLine(bucketHigh[j]);
}
}
}
}
我认为我没有正确编写 CompareTo 方法,我尝试分别从数组的开头和结尾进行排序,并始终得到相同的结果?
由于这似乎是家庭作业,所以我不会实际为您编写正确的代码。但这里至少有一些问题:
- 直接解决您的问题,您必须对数组元素进行排序的代码使用了错误的比较。如果您有两个桶,并且您希望一个桶代表从
A
到K
开头的姓氏,另一个代表从L
到Z
开头的姓氏,那么您需要与K
或L
进行比较以确定正确的桶。与其他名称进行比较只会使数据随机化。string.Compare(studentInfo[j].lastName, "L", StringComparison.CurrentCultureIgnoreCase) < 0
之类的东西应该可以工作。 - 您需要维护两个索引,一个用于每个存储桶,并且只有在您实际将学生记录复制到该存储桶时才增加该存储桶的索引。
- 如果您实际尝试输入 20 个学生的数据,您当前的代码将崩溃并显示
IndexOutOfRangeException
,因为您递增x
并将 ID 值存储到数组中而没有检查您是否已输入 20 个学生的数据。输入 20 个学生后,即使用户输入999
,while
条件也不会检查,直到为时已晚并且代码已经尝试将值存储到数组中。
可能还有其他问题;这些是我第一眼就注意到的。
为了将来参考,在 Stack Overflow 上提问时,您应该确保提供良好的 Minimal, Complete, and Verifiable code example。你接近了;至少代码是完整的。但不要让其他 SO 用户输入您的测试数据。编写一个单独的程序,其中包含所有内置数据,没有用户提示,并且不做 任何 不是重现您遇到的问题所必需的事情.
我不认为你排序有效(j 和 z 比较):
studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0
尝试简化您的桶排序 - 如果您知道您的桶是 A-K 和 J-Z,也许您应该替换以下部分:
for (int j = 0; j < x; j++)
{
if(studentInfo[j].lastName.CompareTo(studentInfo[z].lastName)<= 0)
bucketLow[y] = studentInfo[j].lastName;
else
bucketHigh[y] = studentInfo[j].lastName;
y++;
z++;
}
}
试试这样的东西:
for (var i = 0; i < studentInfo.Length; i++)
{
if (studentInfo[i].lastName[0] <= 'K')
bucketLow[y] = studentInfo[i].lastName;
else
bucketHigh[y] = studentInfo[i].lastName;
y++;
}
(当然还要检查您是否输入了至少 1 个字符的有效内容等等...)
如果您必须使用结构和数组,那么您可以考虑使用下面的代码将名称分隔到适当的存储桶中。正如我评论的那样,您需要两个索引,每个存储桶一个。因为你固定数组大小为20,如果小于20,输出结果时会出现空行。
x = studentInfo.Length;
int lowIndex = 0;
int highIndex = 0;
for (int j = 0; j < x; j++) {
if (String.CompareOrdinal(studentInfo[j].lastName, "L") < 0) {
bucketLow[lowIndex] = studentInfo[j].lastName;
lowIndex++;
} else {
bucketHigh[highIndex] = studentInfo[j].lastName;
highIndex++;
}
}