2012-12-07 12 views
40

Mam więc nieposortowaną tablicę numeryczną int[] anArray = { 1, 5, 2, 7 }; i potrzebuję uzyskać zarówno wartość i indeks największej wartości w tablicy, która byłaby 7 i 3, jak mam to zrobić?C# znaleźć najwyższą wartość tablicy i indeks

+0

Dotychczas ive próbował użyć metody Max(), a następnie użyć binarny metodę wyszukiwania, aby uzyskać indeks tej maksymalnej wartości, ale to robi esnt działa, chyba że tablica jest posortowana, więc nie mogę jej użyć, gdy próbowałem, że to dało mi liczby ujemne –

+3

Po przesłaniu kodu, proszę. –

+0

@EdmundRojas Nie musisz używać wyszukiwania binarnego. Proste liniowe wyszukiwanie działa dobrze w przypadku nieposortowanych list. – millimoose

Odpowiedz

63

To nie jest najbardziej efektowny sposób, ale działa.

(musi mieć using System.Linq;)

int maxValue = anArray.Max(); 
int maxIndex = anArray.ToList().IndexOf(maxValue); 
+6

Zaoszczędzisz dużo czasu na pisanie kodu, ale skończysz przeglądać kolekcję dwa razy. –

+3

Nie potrzebujesz nawet '.ToList()', tablice jawnie implementują 'IList' – millimoose

+0

@GaroYeriazarian Jeśli złożoność liniowa jest zbyt duża dla twojego przypadku użycia, prawdopodobnie musisz zgolić więcej niż tylko zredukować stały współczynnik o trzeci. (Chociaż oczywiście nie jest to pomijalna optymalizacja.) – millimoose

20

Jeśli indeks nie jest posortowana, trzeba wykonać iterację tablicy co najmniej jeden raz, aby znaleźć najwyższą wartość. Chciałbym użyć prostego for pętlę:

int? maxVal = null; //nullable so this works even if you have all super-low negatives 
int index = -1; 
for (int i = 0; i < anArray.Length; i++) 
{ 
    int thisNum = anArray[i]; 
    if (!maxVal.HasValue || thisNum > maxVal.Value) 
    { 
    maxVal = thisNum; 
    index = i; 
    } 
} 

Jest to bardziej gadatliwy niż coś przy użyciu LINQ lub inne rozwiązania jednej linii, ale to chyba trochę szybciej. Naprawdę nie ma sposobu, aby zrobić to szybciej niż O (N).

+1

Możesz zapisać jedną iterację przez zainicjowanie 'maxVal' do wartości tablicy w indeksie 0 (przy założeniu, że tablica ma co najmniej długość 1),' index' na 0 i uruchomienie pętli for w ' i = 1'. –

8

Obowiązkowe LINQ jeden [1] -liner:

var max = anArray.Select((value, index) => new {value, index}) 
       .OrderByDescending(vi => vi.value) 
       .First(); 

(. Sortowanie prawdopodobnie jest spadek wydajności w stosunku do innych rozwiązań)

[1]: o ustalonej wartości z jednego".

+8

Po prostu, aby dodać to rozwiązanie, w najlepszym wypadku jest złożoność O (nlogn). Znalezienie max można uzyskać w czasie O (n) dla nieposortowanej tablicy. – dopplesoldner

28
int[] anArray = { 1, 5, 2, 7 }; 
// Finding max 
int m = anArray.Max(); 

// Positioning max 
int p = Array.IndexOf(anArray, m); 
1
anArray.Select((n, i) => new { Value = n, Index = i }) 
    .Where(s => s.Value == anArray.Max()); 
+0

To jest rozwiązanie O (n^2), ponieważ obliczasz anArray.Max() na każdej iteracji. To będzie bardzo powolne w przypadku dużych tablic. –

1
int[] numbers = new int[7]{45,67,23,45,19,85,64}; 
int smallest = numbers[0]; 
for (int index = 0; index < numbers.Length; index++) 
{ 
if (numbers[index] < smallest) smallest = numbers[index]; 
} 
Console.WriteLine(smallest); 
0

wyjścia dla kodu poniżej:

00: 00: +00,3279270 - max1 00: 00: +00,2615935 - max2 00: 00: +00,6010360 - max3 (arr.Max ())

z 100000000 ints w szyku niezbyt dużej różnicy ale nadal ...

class Program 
    { 
     static void Main(string[] args) 
     { 
      int[] arr = new int[100000000]; 

      Random randNum = new Random(); 
      for (int i = 0; i < arr.Length; i++) 
      { 
       arr[i] = randNum.Next(-100000000, 100000000); 
      } 
      Stopwatch stopwatch1 = new Stopwatch(); 
      Stopwatch stopwatch2 = new Stopwatch(); 
      Stopwatch stopwatch3 = new Stopwatch(); 
      stopwatch1.Start(); 

      var max = GetMaxFullIterate(arr); 

      Debug.WriteLine(stopwatch1.Elapsed.ToString()); 


      stopwatch2.Start(); 
      var max2 = GetMaxPartialIterate(arr); 

      Debug.WriteLine(stopwatch2.Elapsed.ToString()); 

      stopwatch3.Start(); 
      var max3 = arr.Max(); 
      Debug.WriteLine(stopwatch3.Elapsed.ToString()); 

     } 



private static int GetMaxPartialIterate(int[] arr) 
     { 
      var max = arr[0]; 
      var idx = 0; 
      for (int i = arr.Length/2; i < arr.Length; i++) 
      { 
       if (arr[i] > max) 
       { 
        max = arr[i]; 
       } 

       if (arr[idx] > max) 
       { 
        max = arr[idx]; 
       } 
       idx++; 
      } 
      return max; 
     } 


     private static int GetMaxFullIterate(int[] arr) 
     { 
      var max = arr[0]; 
      for (int i = 0; i < arr.Length; i++) 
      { 
       if (arr[i] > max) 
       { 
        max = arr[i]; 
       } 
      } 
      return max; 
     } 
0
int[] Data= { 1, 212, 333,2,12,3311,122,23 }; 
int large = Data.Max(); 
Console.WriteLine(large); 
+0

Twoja odpowiedź podaje tylko najwyższą wartość, ale osoba pytająca zażądała zarówno najwyższej wartości, jak i indeksu najwyższej wartości. – Cardin

2

Oto dwa podejścia. Możesz chcieć dodać obsługę, gdy tablica jest pusta.

public static void FindMax() 
{ 
    // Advantages: 
    // * Functional approach 
    // * Compact code 
    // Cons: 
    // * We are indexing into the array twice at each step 
    // * The Range and IEnumerable add a bit of overhead 
    // * Many people will find this code harder to understand 

    int[] array = { 1, 5, 2, 7 }; 

    int maxIndex = Enumerable.Range(0, array.Length).Aggregate((max, i) => array[max] > array[i] ? max : i); 
    int maxInt = array[maxIndex]; 

    Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}"); 
} 

public static void FindMax2() 
{ 
    // Advantages: 
    // * Near-optimal performance 

    int[] array = { 1, 5, 2, 7 }; 
    int maxIndex = -1; 
    int maxInt = Int32.MinValue; 

    // Modern C# compilers optimize the case where we put array.Length in the condition 
    for (int i = 0; i < array.Length; i++) 
    { 
     int value = array[i]; 
     if (value > maxInt) 
     { 
      maxInt = value; 
      maxIndex = i; 
     } 
    } 

    Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}"); 
} 
0
public static class ArrayExtensions 
{ 
    public static int MaxIndexOf<T>(this T[] input) 
    { 
     var max = input.Max(); 
     int index = Array.IndexOf(input, max); 
     return index; 
    } 
} 

To działa dla wszystkich typów zmiennych ...

var array = new int[]{1, 2, 4, 10, 0, 2}; 
var index = array.MaxIndexOf(); 


var array = new double[]{1.0, 2.0, 4.0, 10.0, 0.0, 2.0}; 
var index = array.MaxIndexOf(); 
0

Rozważmy następujący:

/// <summary> 
    /// Returns max value 
    /// </summary> 
    /// <param name="arr">array to search in</param> 
    /// <param name="index">index of the max value</param> 
    /// <returns>max value</returns> 
    public static int MaxAt(int[] arr, out int index) 
    { 
     index = -1; 
     int max = Int32.MinValue; 

     for (int i = 0; i < arr.Length; i++) 
     { 
      if (arr[i] > max) 
      { 
       max = arr[i]; 
       index = i; 
      } 
     } 

     return max; 
    } 

Zastosowanie:

int m, at; 
m = Max(new int[]{1,2,7,3,4,5,6}, out at); 
Console.WriteLine("Max: {0}, found at: {1}", m, at); 
0

Oto rozwiązanie LINQ, który jest O (n) z porządnych czynników stałych:

int[] anArray = { 1, 5, 2, 7, 1 }; 

int index = 0; 
int maxIndex = 0; 

var max = anArray.Aggregate(
    (oldMax, element) => { 
     ++index; 
     if (element <= oldMax) 
      return oldMax; 
     maxIndex = index; 
     return element; 
    } 
); 

Console.WriteLine("max = {0}, maxIndex = {1}", max, maxIndex); 

Ale trzeba naprawdę napisać wyraźny for lop jeśli zależy Ci na wydajności.

1
public static void Main() 
{ 
    int a,b=0; 
    int []arr={1, 2, 2, 3, 3, 4, 5, 6, 5, 7, 7, 7, 100, 8, 1}; 

    for(int i=arr.Length-1 ; i>-1 ; i--) 
     { 
      a = arr[i]; 

      if(a > b) 
      { 
       b=a;  
      } 
     } 
    Console.WriteLine(b); 
} 
0

Kolejna perspektywa z wykorzystaniem DataTable. Zadeklaruj DataTable z 2 kolumnami o nazwach index i val. Dodaj opcję AutoIncrement i obie wartości AutoIncrementSeed i AutoIncrementStep do kolumny . Następnie użyj pętli foreach i wstaw każdy element tablicy do wiersza datatable. Następnie za pomocą metody Select wybierz wiersz o wartości maksymalnej.

Kod

int[] anArray = { 1, 5, 2, 7 }; 
DataTable dt = new DataTable(); 
dt.Columns.AddRange(new DataColumn[2] { new DataColumn("index"), new DataColumn("val")}); 
dt.Columns["index"].AutoIncrement = true; 
dt.Columns["index"].AutoIncrementSeed = 1; 
dt.Columns["index"].AutoIncrementStep = 1; 
foreach(int i in anArray) 
    dt.Rows.Add(null, i); 

DataRow[] dr = dt.Select("[val] = MAX([val])"); 
Console.WriteLine("Max Value = {0}, Index = {1}", dr[0][1], dr[0][0]); 

Wyjście

Max Value = 7, Index = 4 

Find a demo here

Powiązane problemy