按最大距离排序数组

时间:2013-10-06 11:53:46

标签: arrays algorithm sorting

我有一个唯一整数的列表,我想对它们进行排序,以便下一个整数总是远离所有其余整数,这是可能的。

例如,{1,2,3,4,5,6,7,8,9} => {1,9,6,2,8,3,7,4,5}

我需要做得非常快。

目前,我这样做:

    static double GetDistanceIndex(int value, List<int> others)
    {
        double result=0;
        foreach (var other in others)
        {
            result += Math.Sqrt(Math.Abs(other - value));
        }

        return result;
    }

    static List<int> Sort(List<int> items, int initialValue)
    {
        items = items.ToList();
        List<int> result=new List<int>();


        lock (rnd)
        {
            while (true)
            {
                result.Add(initialValue);
                items.Remove(initialValue);
                if (items.Count == 0)
                {
                    break;
                }
                Dictionary<double, List<int>> distances = new Dictionary<double, List<int>>();
                foreach (var item in items)
                {
                    var d = GetDistanceIndex(item, result);
                    if (!distances.ContainsKey(d))
                    {
                        distances[d] = new List<int>();
                    }
                    distances[d].Add(item);
                }

                var max = distances.Keys.Max();
                var l = distances[max];
                //if (l.Count == 1)
                //{
                //    initialValue = l[0];
                //}
                //else
                //{
                initialValue = l[rnd.Next(l.Count)];
                //} 
            } 
        }

        return result;
    }

但问题是,像这样实现的算法对于大型数组来说算法效果会非常慢。

有人能告诉我一个更好的方法吗?

更新

这里有一个更好的描述:

{1,2,3,4,5,6,7,8,9} =&GT;

  1. 初始种子:1。真的,它可以是任何数字。我们可以选择5,得到{5,9,1,2,8,3,7,6,4}
  2. 之类的东西
  3. 从提供的数组中,9距离1最远
  4. 因为在列表中所有数字都是1和9的等距,我们可以选择其中任何一个。我用rand来选择6。
  5. 现在我们正在寻找离{1,9,6}最远的数字。 选择2是因为abs(2-1)+abs(2-9)+abs(2-6)=12且大于abs(3-1)+abs(3-9)+abs(3-6)=11abs(4-1)+abs(4-9)+abs(4-6)=10abs(8-1)+abs(8-9)+abs(8-6)=10abs(7-1)+abs(7-9)+abs(7-6)=9abs(5-1)+abs(5-9)+abs(5-6)=9
  6. 更新1

    我正在使用此算法从固定数量的替代品中选择尽可能彼此不同的数字

    更新2

    Dukeling在他的回答中指出,{1,9,2,8,3,7,4,6​​,5}也符合我的要求。这是真的,这是我的错。我希望数字尽可能远,并且3d数字非常接近第一个不是我想要的。所以我正在更新距离函数以反映这个

2 个答案:

答案 0 :(得分:1)

{1,9,2,8,3,7,4,6,5}似乎符合您的要求,并且相当容易生成。

只需按升序/降序对数字进行排序(如果尚未完成)。

然后从后面和前面迭代,在它们之间交替,直到我们到达中间。此步骤以线性时间运行。

答案 1 :(得分:1)

[编辑符合新的距离功能]

您正在通过重复调用GetDistanceIndex()来完成不必要的工作。请注意,您不需要每次都从头开始对所有内容求和。如果您有这样的数组:

[a,b,c,d,............,x]

在a,b,c和d已经排序的情况下,当你插入一个新元素'e'时,未排序集合中任何位置'x'的距离函数与所有其他数字的总和排序集仅增加sqrt(abs(xe))。您无需从头开始重新计算全部金额。

所以这里是你如何优化它:使用某种方法来存储一对(数字,距离)。例如,如果您使用C,则可以创建一个包含两个整数的结构数组,值本身以及到有序集的距离。在每一步中,您将浏览不在已排序集中的每对(数字,距离)并更新其距离属性。您可以同时跟踪最大值。一些伪代码:

  • 创建辅助缓冲区S,以保持(数字,距离)对;

  • 在S中插入与initialValue不同的每个数字x,其中distance = sqrt(abs(initialValue - x))。跟踪最大值m,同时;

  • 在每个步骤中,选择m并将其移动到数组的已排序部分。 从S中删除它。然后,转到S中的每个元素并添加 sqrt(abs(y.number-m.number))到y的距离。同样,你需要跟踪 你这样做的最大值。不断重复,直到每一个 元素已排序。

这不是一个出色的解决方案;它以O(n ^ 2)运行,但是您当前的算法在O(n ^ 3)中运行,因为GetDistanceIndex()总是从头开始。此外,我不会使用列表和词典,尝试使用一个简单的数组,以便您可以在恒定的时间内访问和删除元素。从列表中删除可能效率低下,它永远不会比O(log(n))更好。

目前,这是我能想到的唯一优化,也许有人会有更好的主意。