快速搜索超出数组范围和混乱的数组行为

时间:2013-05-05 01:49:56

标签: c# quicksort parallel-arrays

我的程序(C#.NET)存在多个问题,并且不知道导致它们的原因。

该程序旨在按名字,姓氏和生日按升序和降序对名称和生日(格式为first name,last name,DD/MM/YYYY)的列表进行排序。它还有其他尚未实现的功能。

第一个问题出在quikSortStr方法中。程序在第一个if块中崩溃,说明j超出了数组的范围。无论是否mode == "asc",都会发生这种情况。

第二个也是更令人困惑的问题是,当从文本文件加载值时,firstlast的每个奇数索引值都将为空,而每个奇数索引值为bDay将为1/1/0001

我已经在下面提供了完整的程序供参考,快速排序方法和并行数组的使用是必需的。我对缺乏评论表示歉意。

提前感谢您的帮助。我完全难过了。

namespace Names_Arrays
{
public partial class frmNamArrays : Form
{
    System.Globalization.CultureInfo culture = new System.Globalization.CultureInfo("en-CA");
    string[] first;
    string[] last;
    DateTime[] bDay;
    string order = "asc";
    string format = "d/M/yyyy";

    public frmNamArrays()
    {
        InitializeComponent();
    }
    private void write()
    {
        string[] lines = new string[first.Length];

        for (int i = 0; i < lines.Length; i++)
            lines[i] = first[i] + ',' + last[i] + ',' + bDay[i].ToString(format);

        txtbxNames.Clear();
        txtbxNames.Lines = lines;
    }

    private void load()
    {
        string[] lines = txtbxNames.Lines;

        first = new string[lines.Length];
        last = new string[lines.Length];
        bDay = new DateTime[lines.Length];

        int i = 0;
        foreach (string line in lines)
        {
            string[] data = line.Split(',');

            //There aren't any lines that split to a string[] of length less than three,
            //but for some reason the program kept believing there are.
            //patched that leak.

            if (data.Length == 3)
            {
                first[i] = data[0];
                last[i] = data[1];
                bDay[i] = Convert.ToDateTime(data[2], culture);
            }
            i++;
        }
    }
    public DateTime[] quikSortTim(DateTime[] primary, string mode, int left, int right)
    {
        if (primary.Length > 1)
        {
            int i = left, j = right;
            DateTime pivot = primary[left + (right - left) / 2];

            while (i <= j)
            {
                if (mode == "asc")
                {
                    while (DateTime.Compare(primary[i], pivot) < 0)
                        i++;
                    while (DateTime.Compare(primary[j], pivot) > 0)
                        j--;
                }
                else
                {
                    while (DateTime.Compare(primary[i], pivot) > 0)
                        i++;
                    while (DateTime.Compare(primary[j], pivot) < 0)
                        j--;
                }
                if (i <= j)
                {
                    DateTime holdoverB = primary[i];
                    primary[i++] = primary[j];
                    primary[j--] = holdoverB;

                    string holdover = last[i - 1];
                    last[i] = last[j + 1];
                    last[j] = holdover;

                    holdover = first[i - 1];
                    first[i] = first[j + 1];
                    first[j] = holdover;

                }
            }
            if (j > left)
                primary = quikSortTim(primary, mode, left, j);
            if (i < right)
                primary = quikSortTim(primary, mode, i, right);
        }
        return primary;
    }

    public string[] quikSortStr(string[] primary, string type, string mode, int left, int right)
    {
        if (primary.Length > 1)
        {
            int i = left, j = right;
            string pivot = primary[left + (right - left) / 2];

            while (i <= j)
            {
                if (mode == "asc")
                {
                    while (String.Compare(primary[i], pivot) < 0)
                        i++;
                    while (String.Compare(primary[j], pivot) > 0)
                        j--;
                }
                else
                {
                    while (String.Compare(primary[i], pivot) > 0)
                        i++;
                    while (String.Compare(primary[j], pivot) < 0)
                        j--;
                }
                if (i <= j)
                {
                    string holdover = primary[i];
                    primary[i] = primary[j];
                    primary[j] = holdover;
                    if (type == "first")
                    {
                        holdover = last[i];
                        last[i] = last[j];
                        last[j] = holdover;
                    }
                    else
                    {
                        holdover = first[i];
                        first[i] = first[j];
                        first[j] = holdover;
                    }
                    DateTime holdoverBeta = bDay[i];
                    bDay[i] = bDay[j];
                    bDay[j] = holdoverBeta;
                    i++;
                    j++;
                }
            }
            if (j > left)
                primary = quikSortStr(primary, type, mode, left, j);
            if (i < right)
                primary = quikSortStr(primary, type, mode, i, right);
        }
        return primary;
    }

    private void frmNamArrays_SizeChanged(object sender, EventArgs e)
    {
        txtbxNames.Width = this.Width - 40;
        txtbxNames.Height = this.Height - 157;
    }

    private void btnSort_Click(object sender, EventArgs e)
    {
        load();

        switch (cbobxCategory.Text)
        {
            case ("First Name"):
                first = quikSortStr(first, "first", order, 0, first.Length - 1);
                break;
            case ("Last Name"):
                last = quikSortStr(last, "last", order, 0, last.Length - 1);
                break;
            case ("Birthday"):
                bDay = quikSortTim(bDay, order, 0, bDay.Length - 1);
                break;
            default:
                break;
        }

        write();
    }

    private void cbobxOrder_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (cbobxOrder.Text == "Ascending")
            order = "asc";
        else
            order = "desc";
    }

    private void displayfile(string name)
    {
        StreamReader fileData = new StreamReader(name);

        txtbxNames.Lines = fileData.ReadToEnd().Split('\n');

    }

    private void mnuOpen_Click(object sender, EventArgs e)
    {
        OpenFileDialog open = new OpenFileDialog();
        open.Filter = "Text Files|*.txt";
        open.Title = "Select a text file...";

        if (open.ShowDialog() == DialogResult.OK && open.FileName != "")
            displayfile(open.FileName);
    }

    private void mnuExit_Click(object sender, EventArgs e)
    {
        this.Close();
    }
}
}

2 个答案:

答案 0 :(得分:1)

您必须在quikSortStr循环内的if (i <= j)方法中更改以下代码

    DateTime holdoverBeta = bDay[i];
    bDay[i] = bDay[j];
    bDay[j] = holdoverBeta;
    i++;
    j--;//was: j++;

这将解决问题。

答案 1 :(得分:0)

感谢saravanan指出我的第一个错误。超出范围错误是由j在错误方向上意外增加引起的。固定方法是

    public DateTime[] quikSortTim(DateTime[] primary, string mode, int left, int right)
    {
        if (primary.Length > 1)
        {
            int i = left, j = right;
            DateTime pivot = primary[left + (right - left) / 2];

            while (i <= j)
            {
                if (mode == "asc")
                {
                    while (DateTime.Compare(primary[i], pivot) < 0)
                        i++;
                    while (DateTime.Compare(primary[j], pivot) > 0)
                        j--;
                }
                else
                {
                    while (DateTime.Compare(primary[i], pivot) > 0)
                        i++;
                    while (DateTime.Compare(primary[j], pivot) < 0)
                        j--;
                }
                if (i <= j)
                {
                    DateTime holdoverB = primary[i];
                    primary[i] = primary[j];
                    primary[j] = holdoverB;

                    string holdover = last[i];
                    last[i] = last[j];
                    last[j] = holdover;

                    holdover = first[i];
                    first[i] = first[j];
                    first[j] = holdover;

                    i++;
                    j--;
                }
            }
            if (j > left)
                primary = quikSortTim(primary, mode, left, j);
            if (i < right)
                primary = quikSortTim(primary, mode, i, right);
        }
        return primary;
    }

    public string[] quikSortStr(string[] primary, string type, string mode, int left, int right)
    {
        if (primary.Length > 1)
        {
            int i = left, j = right;
            string pivot = primary[left + (right - left) / 2];

            while (i <= j)
            {
                if (mode == "asc")
                {
                    while (String.Compare(primary[i], pivot) < 0)
                        i++;
                    while (String.Compare(primary[j], pivot) > 0)
                        j--;
                }
                else
                {
                    while (String.Compare(primary[i], pivot) > 0)
                        i++;
                    while (String.Compare(primary[j], pivot) < 0)
                        j--;
                }
                if (i <= j)
                {
                    string holdover = primary[i];
                    primary[i] = primary[j];
                    primary[j] = holdover;
                    if (type == "first")
                    {
                        holdover = last[i];
                        last[i] = last[j];
                        last[j] = holdover;
                    }
                    else
                    {
                        holdover = first[i];
                        first[i] = first[j];
                        first[j] = holdover;
                    }
                    DateTime holdoverBeta = bDay[i];
                    bDay[i] = bDay[j];
                    bDay[j] = holdoverBeta;
                    i++;
                    j--;
                }
            }
            if (j > left)
                primary = quikSortStr(primary, type, mode, left, j);
            if (i < right)
                primary = quikSortStr(primary, type, mode, i, right);
        }
        return primary;
    }

我找不到第二个问题本身的解决方案。但是,我确实发现所有读取",,1/1/0001"的元素都已添加,并且没有替换任何名称。使用这个,我只向数组lines添加了不包含"1/1/0001"的索引值。然后,我使用lines = lines.Where(s => s != null).ToArray();通过消除所有现在的null类型值来缩短lines。修改后的功能如下。

private void write()
    {
        string[] lines = new string[first.Length];

        for (int i = 0; i < lines.Length; i++)
            if (bDay[i].ToString(format) != "1/1/0001")
                lines[i] = first[i] + ',' + last[i] + ',' + bDay[i].ToString(format);

        lines = lines.Where(s => s != null).ToArray();

        txtbxNames.Clear();
        txtbxNames.Lines = lines;
    }

感谢您的帮助。我找到了解决方案的资源here

编辑:问题似乎是StreamReader.ReadToEnd()中固有的问题。我不确定原因,但使用System.IO.File.ReadAllLines(filepath)可以完全避免。在原始代码中,我将替换

StreamReader file = new StreamReader(name);
lines = file.ReadToEnd().Split('\n');

lines = File.ReadAllLines(name);

并添加using System.IO;