Arrays 按最大距离排序数组

Arrays 按最大距离排序数组,arrays,algorithm,sorting,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)

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

例如,{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;
    }
静态双GetDistanceIndex(int值,列出其他)
{
双结果=0;
foreach(var other in others)
{
结果+=Math.Sqrt(Math.Abs(其他值));
}
返回结果;
}
静态列表排序(列表项,int initialValue)
{
items=items.ToList();
列表结果=新列表();
锁(rnd)
{
while(true)
{
结果。添加(初始值);
项目。删除(初始值);
如果(items.Count==0)
{
打破
}
字典距离=新字典();
foreach(项目中的var项目)
{
var d=GetDistanceIndex(项目、结果);
如果(!距离.ContainsKey(d))
{
距离[d]=新列表();
}
距离[d]。添加(项目);
}
var max=距离.Keys.max();
var l=距离[最大值];
//如果(l.Count==1)
//{
//初始值=l[0];
//}
//否则
//{
初始值=l[rnd.Next(l.Count)];
//} 
} 
}
返回结果;
}
但问题是,像这样实现的算法对于大型阵列的工作速度非常慢

有人能给我建议一个更好的方法吗

更新

下面是对所做工作的更好描述:

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

  • 初生种子:1。真的,它可以是任何数字。我们可以选择5,得到类似{5,9,1,2,8,3,7,6,4}
  • 从提供的阵列中,9距离1最远
  • 因为在列表中,所有数字与1和9的距离相等,所以我们可以选择其中任何一个。我用兰德选择了6
  • 现在我们正在寻找一个离{1,9,6}最远的数字。 选择2是因为
    abs(2-1)+abs(2-9)+abs(2-6)=12
    ,并且大于
    abs(3-1)+abs(3-9)+abs(3-6)=11
    abs(4-1)+abs(4-9)+abs(4-6)=10
    abs 8-1)+abs 10
    abs 7-1)+abs 7-6)=9
  • 更新1

    我使用这个算法从固定数量的备选方案中选择尽可能不同的数字

    更新2


    杜克林在答复中向我指出{1,9,2,8,3,7,4,6,5}也符合我的要求。这是真的,这是我的错。我希望数字的间距尽可能远,而3d数字非常接近第一个数字并不是我想要的。因此,我正在更新距离函数,以反映这个

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

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


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

    [编辑以符合新的距离函数]

    重复调用GetDistanceIndex()会造成不必要的工作。请注意,您不需要每次都从头开始求和。如果您有这样一个数组:

        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;
        }
    
    [a,b,c,d,…,x]

    如果a、b、c和d已经排序,那么当插入新元素“e”时,未排序集合中任意位置“x”与排序集合中所有其他数字的距离函数之和仅增加sqrt(abs(x-e))。你不必从头开始重新计算全部金额

    下面是如何优化它:使用某种方法存储一对(数字、距离)。例如,如果您使用的是C,您可以创建一个包含两个整数的结构数组,即值本身和到排序集的距离。在每一步中,您都会遍历不在排序集中的每一对(数字、距离),并更新其“距离”属性。您可以同时跟踪最大值。一些伪代码:

    • 创建一个辅助缓冲区S,以容纳(数量、距离)对

    • 在S中插入与初始值不同的每个数字x,距离=sqrt(abs(初始值-x))。同时跟踪最大值m

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

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


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

    请澄清“远离其他”是什么意思?您是否希望相邻值之间差值的绝对值之和最大?您对排序方式的描述和示例不清楚。通过阅读GetDistanceIndex,您可以看到他实际上选择了与每个已排序数字的距离之和最大的数字