简体   繁体   English

将数组的所有不同元素放在C#的左侧

[英]Place all distinct elements of the array to the left in C#

I'm trying to write a programme that places all distinct elements of an array to the left of the same array, and all other (non-distinct) elements right after in whatever order. 我正在尝试编写一个程序,将数组的所有不同元素放置在同一数组的左侧,而所有其他(非不同的)元素则以任意顺序紧随其后。 The time complexity must be O(n log n), ie using sorting and no additional array must be created. 时间复杂度必须为O(n log n),即使用排序并且不必创建其他数组。 I made an attempt to print the distinct elements with the following code: 我尝试使用以下代码打印不同的元素:

using System;  
using System.Diagnostics;
public class Program
{  
    public static void Main() 
    {
      int []arr = {1, 1, 6, 5, 4, 3, 4, 6, 1, 7, 2, 1, 4, 9};
      allDistinct(arr);
    }

     public static void allDistinct(int[] x)
     {
          int n = x.Length;
          Trace.Assert(n>0);

          Array.Sort(x); //O(n log n)

          for (int i = 0; i < n; i++)
          {
               // Move the index ahead while 
               // there are duplicates
               while (i < n - 1 && x[i] == x[i + 1])
                    i++;
          }
          Console.WriteLine(x[i]);
    }
}

However, I'd like my function to be of the form 但是,我希望函数的形式为

public static int[] allDistinct(int[] x)

and then use the auxiliary function to print the array in the Main() 然后使用辅助函数在Main()中打印数组

printArray(allDistinct(arr));

where 哪里

public static void printArray(int[] array)
{
     for(int i=0; i<array.Length; ++i) 
     {
         Console.Write("" + array[i] + " ");
     }
     Console.WriteLine("");
 }

I made an attempt using the swap function, but I didn't succeed to get what I wanted, ie given the array 我尝试使用swap函数,但没有成功获得想要的结果,即给出了数组

1 1 6 5 4 3 4 6 1 7 2 1 4 9

my output should be 我的输出应该是

1 2 3 4 5 6 7 9 + (duble elements in whatever order, e.g. 1 1 1 4 4 6)

thanks for your advise 感谢您的意见

I got a fully working example : 我有一个完整的例子

using System.IO;
using System;

class Program
{
    static void Main()
    {
        int[] array = {1, 1, 6, 5, 4, 3, 4, 6, 1, 7, 2, 1, 4, 9};
        allDistinct(array);
    }

    static int[] allDistinct(int[] array)
    {
        Array.Sort(array);
        printArray(array); // first step monitoring
        int n = array.Length;

        // iterate through array
        for(int i=0;i<n-1;i++)
        {
            // bubble push duplicates to the back
            while(array[i] == array[i+1])
            {
                for(int j=i+1;j<n-1;j++)
                {
                    array[j] = array[j+1];
                }
                array[n-1] = array[i];
                n--;
            }

            printArray(array); // loop steps monitoring
        }

        return array;
    }

    static void printArray(int[] array)
    {
        Console.WriteLine(string.Join(" ", array));
    }
}

This yields this output: 这将产生以下输出:

1 1 1 1 2 3 4 4 4 5 6 6 7 9 
1 2 3 4 4 4 5 6 6 7 9 1 1 1 
1 2 3 4 4 4 5 6 6 7 9 1 1 1 
1 2 3 4 4 4 5 6 6 7 9 1 1 1 
1 2 3 4 5 6 6 7 9 4 4 1 1 1 
1 2 3 4 5 6 6 7 9 4 4 1 1 1 
1 2 3 4 5 6 7 9 6 4 4 1 1 1 
1 2 3 4 5 6 7 9 6 4 4 1 1 1

Note that this will change the order of the original array and return it, as arrays can't be passed by value in C#. 请注意,这将更改原始数组的顺序 返回它,因为数组无法在C#中按值传递。


Edit: 编辑:

About the bubble-push, you could instead count the number of duplicates and push harder: 关于冒泡推送,您可以计算重复次数并加倍努力:

static int[] allDistinct2(int[] array)
{
    Array.Sort(array);
    printArray(array);
    int n = array.Length;

    for(int i=0;i<n;i++)
    {
        int countDup = 0;
        int iValue = array[i];

        // Count the number of duplicates
        for(int j=i+1;j<n && array[j] == iValue;j++)
        {
            countDup++;
        }

        Console.WriteLine("// " + countDup + " time(s) the value " + iValue);
        if(countDup > 0)
        {
            for(int j=i+1;j<n-countDup;j++)
            {
                array[j] = array[j+countDup];
            }
            for(int j=n-countDup;j<n;j++)
            {
                array[j] = iValue;
            }
        }
        n-=countDup;

        printArray(array);
    }

    return array;
}

This yields: 这样产生:

1 1 1 1 2 3 4 4 4 5 6 6 7 9
// 3 time(s) the value 1
1 2 3 4 4 4 5 6 6 7 9 1 1 1
// 0 time(s) the value 2
1 2 3 4 4 4 5 6 6 7 9 1 1 1
// 0 time(s) the value 3
1 2 3 4 4 4 5 6 6 7 9 1 1 1
// 2 time(s) the value 4
1 2 3 4 5 6 6 7 9 4 4 1 1 1
// 0 time(s) the value 5
1 2 3 4 5 6 6 7 9 4 4 1 1 1
// 1 time(s) the value 6
1 2 3 4 5 6 7 9 6 4 4 1 1 1
// 0 time(s) the value 7
1 2 3 4 5 6 7 9 6 4 4 1 1 1
// 0 time(s) the value 9
1 2 3 4 5 6 7 9 6 4 4 1 1 1

Updated coding-ground link 更新了编码地面链接

places all distinct elements of an array to the left of the same array 将数组的所有不同元素放在同一数组的左侧

I don't see any requirement for the resultset to be sorted. 我没有要求对结果集进行排序。 The only requirement is that the elements be arranged so that all duplicates come later than all distinct values. 唯一的要求是元素的排列方式应使所有重复项晚于所有不同值。

If the resultset need not be sorted, there is no reason to call Array.Sort() (which is sort of cheating really); 如果不需要对结果集进行排序,则没有理由调用Array.Sort() (这实际上是一种作弊); we can write our own solution that collates the numbers ourselves. 我们可以编写自己的解决方案来自行整理数字。

This algorithm flips the problem by starting at the end and looking for duplicates. 该算法通过从头开始并查找重复项来解决问题。 When one is found, it is swapped into place, and the upper boundary of the array is moved downward. 找到一个后,将其交换到位,并将数组的上边界向下移动。 If the element at the end has no duplicates, we swap it with first element, and adjust the lower boundary upward so we don't look at it again. 如果末尾的元素没有重复项,我们将其与第一个元素交换,并向上调整下边界,以免再次查看。

public class Program
{
    public static int[] DistinctFirst(int[] arr)
    {
        var lbound = 0;
        var ubound = arr.GetUpperBound(0);
        var i = ubound;
        while ( i>lbound )
        {
            var k = i;
            for (int j=i-1; j>=lbound; j--)
            {
                if (arr[j] == arr[i])
                {
                    Swap(ref arr[j], ref arr[i-1]);
                    i--;
                }
            }
            if (k == i)
            {
                Swap(ref arr[i], ref arr[lbound]);
                lbound++;
            }
            else
            {
                i--;
            }
        }
        return arr;
    }

    public static void Swap(ref int a, ref int b)
    {
        int c = a;
        a = b;
        b = c;
    }

    public static void Main() 
    {
        int[] arr = {1, 1, 6, 5, 4, 3, 4, 6, 1, 7, 2, 1, 4, 9};
        int[] result = DistinctFirst(arr);

        foreach (var i in result)
        {
            Console.WriteLine(i);
        }
    }
}

Output: 输出:

9
7
2
3
5
4
4
4
6
6
1
1
1
1

Code on DotNetFiddle DotNetFiddle上的代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM