web-dev-qa-db-de.com

Finden Sie das zweitgrößte Element in einem Array mit minimaler Anzahl von Vergleichen

Wie groß ist die Anzahl der erforderlichen Vergleiche für ein Array der Größe N?

63
nababa

Der optimale Algorithmus verwendet n + log n-2 Vergleiche. Stellen Sie sich Elemente als Konkurrenten vor, und ein Turnier wird sie einordnen.

Vergleichen Sie zunächst die Elemente wie im Baum

   |
  / \
 |   |
/ \ / \
x x x x

dies erfordert n-1 Vergleiche und jedes Element ist höchstens n-mal im Vergleich. Sie finden das größte Element als Gewinner.

Das zweitgrößte Element muss ein Match gegen den Gewinner verloren haben (er kann kein Match gegen ein anderes Element verlieren), daher ist er eines der Log-n-Elemente, gegen die der Gewinner gespielt hat. Welcher von ihnen kann durch Vergleiche mit log n-1 ermittelt werden.

Die Optimalität wird durch gegnerische Argumente nachgewiesen. Siehe https://math.stackexchange.com/questions/1601 oder http://compgeom.cs.uiuc.edu/~jeffe/teaching/497/02-selection.pdf oder http://www.imada.sdu.dk/~jbj/DM19/lb06.pdf oder https://www.utdallas.edu/~chandra/documents/6363/lbd.pdf

108
sdcvvc

Sie finden den zweitgrößten Wert mit höchstens 2 · (N- 1) Vergleichen und zwei Variablen, die den größten und zweitgrößten Wert enthalten:

largest := numbers[0];
secondLargest := null
for i=1 to numbers.length-1 do
    number := numbers[i];
    if number > largest then
        secondLargest := largest;
        largest := number;
    else
        if number > secondLargest then
            secondLargest := number;
        end;
    end;
end;
11
Gumbo

Verwenden Sie den Bubble-Sortier- oder Selection-Sortieralgorithmus, der das Array in absteigender Reihenfolge sortiert. Sortieren Sie das Array nicht vollständig. Nur zwei Pässe. Der erste Durchgang gibt das größte Element und der zweite Durchgang gibt Ihnen das zweitgrößte Element.

Anzahl der Vergleiche für den ersten Durchgang: n-1

Anzahl der Vergleiche für den ersten Durchgang: n-2

Gesamtzahl zum Vergleich für das Finden der zweitgrößten: 2n-3

Möglicherweise können Sie diesen Algorithmus verallgemeinern. Wenn Sie den drittgrößten benötigen, machen Sie 3 Durchgänge.

Bei der obigen Strategie benötigen Sie keine temporären Variablen, da Bubble-Sortierung und Selection-Sortierung Ort-Sortier Algorithmen sind.

9
Rohit Bansod

Hier ist ein Code, der möglicherweise nicht optimal ist, aber zumindest das zweitgrößte Element findet:

if( val[ 0 ] > val[ 1 ] )
{
    largest = val[ 0 ]
    secondLargest = val[ 1 ];
}
else
{
    largest = val[ 1 ]
    secondLargest = val[ 0 ];
}

for( i = 2; i < N; ++i )
{
    if( val[ i ] > secondLargest )
    {
        if( val[ i ] > largest )
        {
            secondLargest = largest;
            largest = val[ i ];
        }
        else
        {
            secondLargest = val[ i ];
        }
    }
}

Es sind mindestens N-1-Vergleiche erforderlich, wenn sich die größten zwei Elemente am Anfang des Arrays befinden und im schlechtesten Fall höchstens 2N-3 (eines der ersten zwei Elemente ist das kleinste im Array).

2
x4u

PHP-Version des Gumbo-Algorithmus: http://sandbox.onlinephpfunctions.com/code/51e1b05dac2e648fd13e0b60f44a2abe1e4a8689

$numbers = [10, 9, 2, 3, 4, 5, 6, 7];

$largest = $numbers[0];
$secondLargest = null;
for ($i=1; $i < count($numbers); $i++) {
    $number = $numbers[$i];
    if ($number > $largest) {
        $secondLargest = $largest;
        $largest = $number;
    } else if ($number > $secondLargest) {
        $secondLargest = $number;
    }
}

echo "largest=$largest, secondLargest=$secondLargest";
1
forsberg

fall 1 -> 9 8 7 6 5 4 3 2 1
Fall 2 -> 50 10 8 25 ........
Fall 3 -> 50 50 10 8 25 .........
Fall 4 -> 50 50 10 8 50 25 ....... 

public void second element()  
{
      int a[10],i,max1,max2;  
      max1=a[0],max2=a[1];  
      for(i=1;i<a.length();i++)  
      {  
         if(a[i]>max1)  
          {
             max2=max1;  
             max1=a[i];  
          }  
         else if(a[i]>max2 &&a[i]!=max1)  
           max2=a[i];  
         else if(max1==max2)  
           max2=a[i];  
      }  
}
1
achal kumar

Nehmen wir an, das angegebene Array ist inPutArray = [1,2,5,8,7,3] erwartet O/P -> 7 (zweitgrößte)

 take temp array 
      temp = [0,0], int dummmy=0;
    for (no in inPutArray) {
    if(temp[1]<no)
     temp[1] = no
     if(temp[0]<temp[1]){
    dummmy = temp[0]
    temp[0] = temp[1]
    temp[1] = temp
      }
    }

    print("Second largest no is %d",temp[1])
1
Kiran K

Ich weiß, dass dies eine alte Frage ist, aber hier ist mein Versuch, sie zu lösen und den Turnieralgorithmus zu verwenden. Diese Lösung ähnelt der von @sdcvvc verwendeten Lösung, ich verwende jedoch zweidimensionales Array, um Elemente zu speichern.

Damit die Dinge funktionieren, gibt es zwei Annahmen:
1) Anzahl der Elemente im Array ist die Potenz von 2
2) Das Array enthält keine Duplikate

Der gesamte Prozess besteht aus zwei Schritten:
1. Erstellen eines 2D-Arrays durch Vergleich zweier Elemente. Die erste Zeile im 2D-Array wird das gesamte Eingabefeld sein. Die nächste Zeile enthält die Ergebnisse der Vergleiche der vorherigen Zeile. Wir führen Vergleiche mit dem neu erstellten Array fort und bauen das 2D-Array so lange auf, bis ein Array mit nur einem Element (dem größten Element) erreicht wird.
2. Wir haben ein 2D-Array, in dem die letzte Zeile nur ein Element enthält: das größte. Wir gehen weiter von unten nach oben und finden in jedem Array das Element, das vom größten "geschlagen" wurde, und vergleichen es mit dem aktuellen "zweitgrößten" Wert. Um das Element zu finden, das um den größten Wert getreten ist, und um O(n) - Vergleiche zu vermeiden, müssen wir den Index des größten Elements in der vorherigen Zeile speichern. Auf diese Weise können wir die benachbarten Elemente leicht überprüfen. Auf jeder Ebene (über der Wurzelebene) werden die benachbarten Elemente wie folgt erhalten:

leftAdjacent = rootIndex*2
rightAdjacent = rootIndex*2+1,

dabei ist rootIndex der Index des größten (root) Elements auf der vorherigen Ebene.

Ich weiß, dass die Frage nach C++ stellt, aber hier ist mein Versuch, es in Java zu lösen. (Ich habe Listen anstelle von Arrays verwendet, um eine unordentliche Änderung der Arraygröße und/oder unnötige Berechnungen der Arraygröße zu vermeiden.)

public static Integer findSecondLargest(List<Integer> list) {
        if (list == null) {
            return null;
        }
        if (list.size() == 1) {
            return list.get(0);
        }
        List<List<Integer>> structure = buildUpStructure(list);
        System.out.println(structure);
        return secondLargest(structure);

    }

    public static List<List<Integer>> buildUpStructure(List<Integer> list) {
        List<List<Integer>> newList = new ArrayList<List<Integer>>();
        List<Integer> tmpList = new ArrayList<Integer>(list);
        newList.add(tmpList);
        int n = list.size();
        while (n>1) {
            tmpList = new ArrayList<Integer>();
            for (int i = 0; i<n; i=i+2) {
                Integer i1 = list.get(i);
                Integer i2 = list.get(i+1);
                tmpList.add(Math.max(i1, i2));
            }
            n/= 2;
            newList.add(tmpList);   
            list = tmpList;
        }
        return newList;
    }

    public static Integer secondLargest(List<List<Integer>> structure) {
        int n = structure.size();
        int rootIndex = 0;
        Integer largest = structure.get(n-1).get(rootIndex);
        List<Integer> tmpList = structure.get(n-2);
        Integer secondLargest = Integer.MIN_VALUE;
        Integer leftAdjacent = -1;
        Integer rightAdjacent = -1;
        for (int i = n-2; i>=0; i--) {
            rootIndex*=2;
            tmpList = structure.get(i);
            leftAdjacent = tmpList.get(rootIndex);
            rightAdjacent = tmpList.get(rootIndex+1); 
            if (leftAdjacent.equals(largest)) {
                if (rightAdjacent > secondLargest) {
                    secondLargest = rightAdjacent;
                }
            }
            if (rightAdjacent.equals(largest)) {
                if (leftAdjacent > secondLargest) {
                    secondLargest = leftAdjacent;
                }
                rootIndex=rootIndex+1;
            }
        }

        return secondLargest;
    }
1
Maggie

Sorry, JS-Code ...

Getestet mit den beiden Eingängen:

a = [55,11,66,77,72];
a = [ 0, 12, 13, 4, 5, 32, 8 ];

var first = Number.MIN_VALUE;
var second = Number.MIN_VALUE;
for (var i = -1, len = a.length; ++i < len;) {
    var dist = a[i];
    // get the largest 2
    if (dist > first) {
        second = first;
        first = dist;
    } else if (dist > second) { // && dist < first) { // this is actually not needed, I believe
        second = dist;
    }
}

console.log('largest, second largest',first,second);
largest, second largest 32 13

Es sollte maximal a.length * 2 Vergleiche geben und wird nur einmal durch die Liste geführt.

1
geekdenz

Ein guter Weg mit O(1) Zeitkomplexität wäre die Verwendung eines Max-Heap. Rufen Sie das Heapify zweimal an und Sie haben die Antwort.

0
Harsh Gupta

versuche dies.

max1 = a[0].
max2.
for i = 0, until length:
  if a[i] > max:
     max2 = max1.
     max1 = a[i].
     #end IF
  #end FOR
return min2.

es sollte wie ein Zauber wirken. geringe Komplexität.

hier ist ein Java-Code.

int secondlLargestValue(int[] secondMax){
int max1 = secondMax[0]; // assign the first element of the array, no matter what, sorted or not.
int max2 = 0; // anything really work, but zero is just fundamental.
   for(int n = 0; n < secondMax.length; n++){ // start at zero, end when larger than length, grow by 1. 
        if(secondMax[n] > max1){ // nth element of the array is larger than max1, if so.
           max2 = max1; // largest in now second largest,
           max1 = secondMax[n]; // and this nth element is now max.
        }//end IF
    }//end FOR
    return max2;
}//end secondLargestValue()
0
sabbibJAVA
#include<stdio.h>
main()
{
        int a[5] = {55,11,66,77,72};
        int max,min,i;
        int smax,smin;
        max = min = a[0];
        smax = smin = a[0];
        for(i=0;i<=4;i++)
        {
                if(a[i]>max)
                {
                        smax = max;
                        max = a[i];
                }
                if(max>a[i]&&smax<a[i])
                {
                        smax = a[i];
                }
        }
        printf("the first max element z %d\n",max);
        printf("the second max element z %d\n",smax);
}
0
prawin

Verwenden Sie die Zählsortierung und suchen Sie dann das zweitgrößte Element, beginnend mit Index 0 zum Ende. Es sollte mindestens 1 Vergleich geben, höchstens n-1 (wenn nur ein Element vorhanden ist!). 

0
lyfzabrutalcode

Die folgende Lösung würde 2(N-1) Vergleiche durchführen:

arr  #array with 'n' elements
first=arr[0]
second=-999999  #large negative no
i=1
while i is less than length(arr):
    if arr[i] greater than first:
        second=first
        first=arr[i]
    else:
        if arr[i] is greater than second and arr[i] less than first:
            second=arr[i]
    i=i+1
print second
0
user3214392

Die akzeptierte Lösung von sdcvvc in C++ 11.

#include <algorithm>
#include <iostream>
#include <vector>
#include <cassert>
#include <climits>

using std::vector;
using std::cout;
using std::endl;
using std::random_shuffle;
using std::min;
using std::max;

vector<int> create_tournament(const vector<int>& input) {
  // make sure we have at least two elements, so the problem is interesting
  if (input.size() <= 1) {
    return input;
  }

  vector<int> result(2 * input.size() - 1, -1);

  int i = 0;
  for (const auto& el : input) {
    result[input.size() - 1 + i] = el;
    ++i;
  }

  for (uint j = input.size() / 2; j > 0; j >>= 1) {
    for (uint k = 0; k < 2 * j; k += 2) {
      result[j - 1 + k / 2] = min(result[2 * j - 1 + k], result[2 * j + k]);
    }
  }

  return result;
}

int second_smaller(const vector<int>& tournament) {
  const auto& minimum = tournament[0];
  int second = INT_MAX;

  for (uint j = 0; j < tournament.size() / 2; ) {
    if (tournament[2 * j + 1] == minimum) {
      second = min(second, tournament[2 * j + 2]);
      j = 2 * j + 1;
    }
    else {
      second = min(second, tournament[2 * j + 1]);
      j = 2 * j + 2;
    }
  }

  return second;
}

void print_vector(const vector<int>& v) {
  for (const auto& el : v) {
    cout << el << " ";
  }
  cout << endl;
}

int main() {

  vector<int> a;
  for (int i = 1; i <= 2048; ++i)
    a.Push_back(i);

  for (int i = 0; i < 1000; i++) {
    random_shuffle(a.begin(), a.end());
    const auto& v = create_tournament(a);
    assert (second_smaller(v) == 2);
  }

  return 0;
}
0

Dies kann in n + ceil (log n) - 2 verglichen werden.

Lösung: Es braucht n-1 Vergleiche, um ein Minimum zu erhalten.

Um jedoch ein Minimum zu erreichen, bauen wir ein Turnier auf, bei dem jedes Element paarweise angeordnet wird. wie ein Tennisturnier und Gewinner einer Runde wird weitergehen.

Die Höhe dieses Baumes wird log n sein, da wir bei jeder Runde die Hälfte haben.

Das zweite Minimum ist die Idee, dass der Mindestkandidat in einer der vorherigen Runden geschlagen wird. Wir müssen also ein Minimum an potenziellen Kandidaten finden (vom Minimum übertroffen).

Mögliche Kandidaten sind log n = Baumhöhe

Also nein. für den Vergleich, um ein Minimum unter Verwendung des Turnierbaums zu finden, ist n-1 und für das zweite Minimum ist log n -1 summiert sich = n + ceil (log n) - 2

Hier ist C++ - Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>

using namespace std;

typedef pair<int,int> ii;

bool isPowerOfTwo (int x)
{
  /* First x in the below expression is for the case when x is 0 */
  return x && (!(x&(x-1)));
}
// modified
int log_2(unsigned int n) {
    int bits = 0;
    if (!isPowerOfTwo(n))
        bits++;
    if (n > 32767) {
        n >>= 16;
        bits += 16;
    }
    if (n > 127) {
        n >>= 8;
        bits += 8;
    }
    if (n > 7) {
        n >>= 4;
        bits += 4;
    }
    if (n > 1) {
        n >>= 2;
        bits += 2;
    }
    if (n > 0) {
        bits++;
    }
    return bits;
}

int second_minima(int a[], unsigned int n) {

    // build a tree of size of log2n in the form of 2d array
    // 1st row represents all elements which fights for min
    // candidate pairwise. winner of each pair moves to 2nd
    // row and so on
    int log_2n = log_2(n);
    long comparison_count = 0;
    // pair of ints : first element stores value and second
    //                stores index of its first row
    ii **p = new ii*[log_2n];
    int i, j, k;
    for (i = 0, j = n; i < log_2n; i++) {
        p[i] = new ii[j];
        j = j&1 ? j/2+1 : j/2;
    }
    for (i = 0; i < n; i++)
        p[0][i] = make_pair(a[i], i);



    // find minima using pair wise fighting
    for (i = 1, j = n; i < log_2n; i++) {
        // for each pair
        for (k = 0; k+1 < j; k += 2) {
            // find its winner
            if (++comparison_count && p[i-1][k].first < p[i-1][k+1].first) {
                p[i][k/2].first = p[i-1][k].first;
                p[i][k/2].second = p[i-1][k].second;
            }
            else {
                p[i][k/2].first = p[i-1][k+1].first;
                p[i][k/2].second = p[i-1][k+1].second;
            }

        }
        // if no. of elements in row is odd the last element
        // directly moves to next round (row)
        if (j&1) {
            p[i][j/2].first = p[i-1][j-1].first;
            p[i][j/2].second = p[i-1][j-1].second;
        }
        j = j&1 ? j/2+1 : j/2;
    }



    int minima, second_minima;
    int index;
    minima = p[log_2n-1][0].first;
    // initialize second minima by its final (last 2nd row)
    // potential candidate with which its final took place
    second_minima = minima == p[log_2n-2][0].first ? p[log_2n-2][1].first : p[log_2n-2][0].first;
    // minima original index
    index = p[log_2n-1][0].second;
    for (i = 0, j = n; i <= log_2n - 3; i++) {
        // if its last candidate in any round then there is
        // no potential candidate
        if (j&1 && index == j-1) {
            index /= 2;
            j = j/2+1;
            continue;
        }
        // if minima index is odd, then it fighted with its index - 1
        // else its index + 1
        // this is a potential candidate for second minima, so check it
        if (index&1) {
            if (++comparison_count && second_minima > p[i][index-1].first)
                second_minima = p[i][index-1].first;
        }
        else {
            if (++comparison_count && second_minima > p[i][index+1].first)
                second_minima = p[i][index+1].first;
        }
        index/=2;
        j = j&1 ? j/2+1 : j/2;
    }


    printf("-------------------------------------------------------------------------------\n");
    printf("Minimum          : %d\n", minima);
    printf("Second Minimum   : %d\n", second_minima);
    printf("comparison count : %ld\n", comparison_count);
    printf("Least No. Of Comparisons (");
    printf("n+ceil(log2_n)-2) : %d\n", (int)(n+ceil(log(n)/log(2))-2));
    return 0;
}

int main()
{
    unsigned int n;
    scanf("%u", &n);
    int a[n];
    int i;
    for (i = 0; i < n; i++)
        scanf("%d", &a[i]);
    second_minima(a,n);
    return 0;
}
0
prakharjain
function findSecondLargeNumber(arr){

    var fLargeNum = 0;
    var sLargeNum = 0;

    for(var i=0; i<arr.length; i++){
        if(fLargeNum < arr[i]){
            sLargeNum = fLargeNum;
            fLargeNum = arr[i];         
        }else if(sLargeNum < arr[i]){
            sLargeNum = arr[i];
        }
    }

    return sLargeNum;

}
var myArray = [799, -85, 8, -1, 6, 4, 3, -2, -15, 0, 207, 75, 785, 122, 17];

Ref: http://www.ajaybadgujar.com/finding-second-largest-number-from-array-in-javascript/

0
coder
    int[] int_array = {4, 6, 2, 9, 1, 7, 4, 2, 9, 0, 3, 6, 1, 6, 8};
    int largst=int_array[0];
    int second=int_array[0];
    for (int i=0; i<int_array.length; i++){        
        if(int_array[i]>largst) { 
            second=largst;
            largst=int_array[i];
        }  
        else if(int_array[i]>second  &&  int_array[i]<largst) { 
            second=int_array[i];
        } 
    }
0
Usman

Ich habe alle obigen Beiträge durchgegangen, bin aber überzeugt, dass die Implementierung des Tournament-Algorithmus der beste Ansatz ist. Betrachten wir den folgenden von @Gumbo veröffentlichten Algorithmus

largest := numbers[0];
secondLargest := null
for i=1 to numbers.length-1 do
    number := numbers[i];
    if number > largest then
        secondLargest := largest;
        largest := number;
    else
        if number > secondLargest then
            secondLargest := number;
        end;
    end;
end;

Es ist sehr gut für den Fall, dass wir die zweitgrößte Zahl in einem Array finden. Es hat (2n-1) Anzahl von Vergleichen. Was aber, wenn Sie die drittgrößte oder eine k-größte Zahl berechnen möchten. Der obige Algorithmus funktioniert nicht. Sie sind zu einer anderen Prozedur gekommen. 

Ich glaube, der Ansatz des Turnieralgorithmus ist der beste und hier ist der link dafür.

Ich nehme an, folge dem "optimalen Algorithmus verwendet n + log n-2 Vergleiche" von oben, der Code, den ich mir ausgedacht habe und der keinen binären Baum zum Speichern des Werts verwendet, wäre folgender:

Bei jedem rekursiven Aufruf wird die Array-Größe halbiert.

Die Anzahl der Vergleiche lautet also: 

1. Iteration: n/2 Vergleiche

2. Iteration: n/4 Vergleiche

3. Iteration: n/8 Vergleiche

... Bis zu n Iterationen protokollieren?

Gesamt => n - 1 Vergleiche?

function findSecondLargestInArray(array) {
    let winner = [];
    if (array.length === 2) {
        if (array[0] < array[1]) {
            return array[0];
        } else {
            return array[1];
        }
    }
    for (let i = 1; i <= Math.floor(array.length / 2); i++) {
        if (array[2 * i - 1] > array[2 * i - 2]) {
            winner.Push(array[2 * i - 1]);
        } else {
            winner.Push(array[2 * i - 2]);
        }
    }
    return findSecondLargestInArray(winner);
}

Angenommen, das Array enthält 2 ^ n Zahlen.

Wenn 6 Zahlen vorhanden sind, bewegen sich 3 Zahlen zur nächsten Ebene, was nicht richtig ist.

Benötigen Sie 8 Zahlen => 4 Nummer => 2 Nummer => 1 Nummer => 2 ^ n Nummer der Nummer

0
Ou Ye

Angenommen, Platz ist irrelevant, dies ist der kleinste, den ich bekommen könnte. Es erfordert 2 * n Vergleiche im schlimmsten Fall und n Vergleiche im besten Fall:

arr = [ 0, 12, 13, 4, 5, 32, 8 ]
max = [ -1, -1 ]

for i in range(len(arr)):
     if( arr[i] > max[0] ):
        max.insert(0,arr[i])
     Elif( arr[i] > max[1] ):
        max.insert(1,arr[i])

print max[1]
0
riwalk