简体   繁体   中英

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. 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()

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

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#.


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); 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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