c# - Sorting Multiple String arrays with Quicksort

时间:2016-04-15 11:06:04

标签: c# arrays sorting quicksort

Sorry for the vague title but I'll try and describe what my problem as best as I can below.

Basically I have 5 string arrays that all hold data relevant to the same index in the other arrays. For example, element 5 in array 1 corresponds to element 5 in arrays 2, 3, 4 and 5.

What I have done is used the Quicksort algorthim to sort array 1 into alphabetical order. The problem is that when the array is sorted, no longer do elements in the other arrays correspond since the other arrays haven't been sorted.

What I need is some way to swap the same elements around in the other 4 arrays as has been down to array 1. For example, if element 2 in array 1 is swapped to element 55, then element 2 in the other 4 arrays need to be swapped to element 55 in their array and vice versa.

The end goal is to display all the data in a specific element across all 5 arrays.

Below I have added the quicksort algorithm I'm using and added 3 example arrays that need sorting:

   string[] array1 = {"z","y","x","a"};
   string[] array2 = {"26","25","24","1"}; 
   string[] array3 = { "black","yellow","white","red" };


   // The first 2 arrays should clarify my point further. 

  // I use Quicksort to sort array 1 


   public static void QuicksortSTRING(IComparable[] elements, int left, int right)  
   {        
         int i = left, j = right;  
         IComparable pivot = elements[(left + right) / 2];  

         while (i <= j)  
         {  
            while (elements[i].CompareTo(pivot) < 0)  
            {  
              i++;  
            }

            while (elements[j].CompareTo(pivot) > 0)
            {
              j--;
            }

            if (i <= j)
            {
                // Swap
                IComparable tmp = elements[i];
                elements[i] = elements[j];
                elements[j] = tmp;

                i++;
                j--; 
            }
        }

        // Recursive calls

        if (left < j)
        {
           QuicksortSTRING(elements, left, j);
        }

        if (i < right)
        {     
           QuicksortSTRING(elements, i, right); 
        }
    } 

If you need any other info just ask.

4 个答案:

答案 0 :(得分:2)

最好将三个相关的字符串放在一个对象中:

sealed class RelatedInformation     // or struct, you decide
{
    public string First;
    public string Second;
    public string Third;
}

然后对这些对象的列表进行排序:

var myList = new List<RelatedInformation>();
// insert code that populates the list here
myList.Sort((a, b) => a.First.CompareTo(b.First));

或者,如果它需要是一个数组:

var myArray = /* obtain the RelatedInformation[] here */;
Array.Sort(myList, (a, b) => a.First.CompareTo(b.First));

此外,您不需要自己实施Quicksort(除非这是家庭作业?:))。您只需将Array.SortList<T>.Sort与lambda表达式一起使用即可指定排序标准。

如果您使用上述代码,则甚至不需要实现IComparable<T>接口。但是,如果RelatedInformation类(或结构)用于许多与其排序有关的地方,那么无论如何都要明智地实施它;然后你可以抛弃lambdas:

sealed class RelatedInformation : IComparable<RelatedInformation>
{
    public string First;
    public string Second;
    public string Third;

    public int CompareTo(RelatedInformation other)
    {
        return First.CompareTo(other.First);
    }
}

// ...

var myList = new List<RelatedInformation>();
// insert code that populates the list
myList.Sort();

但是,由于您明确询问三阵列情况,这里是一个可以在该约束下工作的解决方案。而不是排序任何一个数组,我们的想法是排序索引列表。我将使用LINQ,因为它非常简洁易读:

var sortedIndexes = Enumerable.Range(0, array1.Length)
                        .OrderBy(i => array1[i])
                        .ToArray();

var sortedArray1 = sortedIndexes.Select(i => array1[i]).ToArray();
var sortedArray2 = sortedIndexes.Select(i => array2[i]).ToArray();
var sortedArray3 = sortedIndexes.Select(i => array3[i]).ToArray();

很短,嗯?当然,在调用OrderBy时,您可以指定要排序的任何其他数组。

请注意,如果任何数组的更短,此代码将抛出异常,并且如果任何数组更长,它将静默地丢弃项目< / em>比第一个。对象列表解决方案的一个主要好处是您无需担心这一点。

作为补充信息,LINQ的OrderBy稳定排序;这意味着array1具有相同字符串的项目保持相同的顺序。 Array.SortList<T>.Sort没有稳定的排序。

您甚至可以使用此方法按多个条件进行排序;例如,假设您要按array1中的字符串排序,但只要array1对某些项具有相同的字符串,您就希望这些项按array2中的任何内容排序。您可以使用ThenBy

执行此操作
var sortedIndexes = Enumerable.Range(0, array1.Length)
                        .OrderBy(i => array1[i])
                        .ThenBy(i => array2[i])
                        .ToArray();

答案 1 :(得分:1)

您已经对这三项信息进行了排序。尝试创建一个类来保存它们。如果你愿意,它可以是你的一个程序类中的内部类。

   struct MyThing :IComparable {
      char a;
      int b;
      string c;
   }

然后制作List<MyThing>。然后用您的数据填充它。

您需要为您的班级实施IComparable interface (requiring your own CompareTo method),因此它知道对a或您想要排序的任何内容进行排序。

然后使用内置的List.Sort()函数或您自己的快速排序方法。

答案 2 :(得分:0)

我认为如果将所有相关信息存储在一个数组中会更有意义,例如:

var array = new[] { Tuple.Create("z", "26", "black"),
                    Tuple.Create("y", "25", "yellow"),
                    Tuple.Create("x", "24", "white"),
                    Tuple.Create("a", "1", "red") };

然后,您可以使用您喜欢的任何键对数组进行排序,并在相应的位置保留其他元素。

答案 3 :(得分:0)

您可以通过将所有相关字符串放入单个类来实现此目的,而不是将它们全部保存在单独的数组中。

例如:

public class Demo
{
    public string Key;
    public string S1;
    public string S2;

    public override string ToString()
    {
        return string.Format("Key: {0}, S1: {1}, S2: {2}", Key, S1, S2);
    }
}

然后,当您想要对其进行排序时,您需要一种方法来确定比较元素时要使用的属性。做这件事有很多种方法;一个是制作类型工具IComparable<T>

然而,还有另一种更灵活的方法。您可以为sort方法提供可用于比较元素的IComparer<T>对象。

使用此功能,您可以选择&#34;比较时要使用的类的成员。

以下是一个完整的例子:

using System;
using System.Collections.Generic;

namespace Demo
{
    public class Demo
    {
        public string Key;
        public string S1;
        public string S2;

        public override string ToString()
        {
            return string.Format("Key: {0}, S1: {1}, S2: {2}", Key, S1, S2);
        }
    }

    static class Program
    {
        static void Main()
        {
            var list = new List<Demo>
            {
                new Demo {Key = "Z", S1 = "Z1", S2 = "Z2"},
                new Demo {Key = "Y", S1 = "Y1", S2 = "Y2"},
                new Demo {Key = "X", S1 = "X1", S2 = "X2"},
                new Demo {Key = "W", S1 = "W1", S2 = "W2"},
                new Demo {Key = "V", S1 = "V1", S2 = "V2"}
            };

            // Rather than write your own IComparer<Demo> implementation, you can
            // leverage a built-in .Net implementation by using 
            // Comparer<Demo>.Create() as follows:

            var keyComparer = Comparer<Demo>.Create((x, y) => string.Compare(x.Key, y.Key, StringComparison.Ordinal));

            QuicksortSTRING(list, 0, list.Count-1, keyComparer);

            Console.WriteLine(string.Join("\n", list));
        }

        public static void QuicksortSTRING<T>(IList<T> elements, int left, int right, IComparer<T> comparer)
        {
            int i = left, j = right;
            var pivot = elements[(left + right)/2];

            while (i <= j)
            {
                while (comparer.Compare(elements[i], pivot) < 0)
                {
                    i++;
                }

                while (comparer.Compare(elements[j], pivot) > 0)
                {
                    j--;
                }

                if (i <= j)
                {
                    // Swap
                    T tmp = elements[i];
                    elements[i] = elements[j];
                    elements[j] = tmp;

                    i++;
                    j--;
                }
            }

            // Recursive calls

            if (left < j)
            {
                QuicksortSTRING(elements, left, j, comparer);
            }

            if (i < right)
            {
                QuicksortSTRING(elements, i, right, comparer);
            }
        }
    }
}