it-swarm.com.de

Was ist die schnellste Suchmethode für ein sortiertes Array?

Als Antwort auf eine andere Frage habe ich das folgende Programm geschrieben, um verschiedene Suchmethoden in einem sortierten Array zu vergleichen. Grundsätzlich habe ich zwei Implementierungen der Interpolationssuche und eine der binären Suche verglichen. Ich verglich die Leistung, indem ich die (mit demselben Datensatz) verbrachten Zyklen der verschiedenen Varianten zählte.

Ich bin mir jedoch sicher, dass es Möglichkeiten gibt, diese Funktionen zu optimieren, um sie noch schneller zu machen. Hat jemand eine Idee, wie ich diese Suchfunktion beschleunigen kann? Eine Lösung in C oder C++ ist akzeptabel, aber ich brauche es, um ein Array mit 100000 Elementen zu verarbeiten.

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <assert.h>

static __inline__ unsigned long long rdtsc(void)
{
  unsigned long long int x;
     __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
     return x;
}

int interpolationSearch(int sortedArray[], int toFind, int len) {
    // Returns index of toFind in sortedArray, or -1 if not found
    int64_t low = 0;
    int64_t high = len - 1;
    int64_t mid;

    int l = sortedArray[low];
    int h = sortedArray[high];

    while (l <= toFind && h >= toFind) {
        mid = low + (int64_t)((int64_t)(high - low)*(int64_t)(toFind - l))/((int64_t)(h-l));

        int m = sortedArray[mid];

        if (m < toFind) {
            l = sortedArray[low = mid + 1];
        } else if (m > toFind) {
            h = sortedArray[high = mid - 1];
        } else {
            return mid;
        }
    }

    if (sortedArray[low] == toFind)
        return low;
    else
        return -1; // Not found
}

int interpolationSearch2(int sortedArray[], int toFind, int len) {
    // Returns index of toFind in sortedArray, or -1 if not found
    int low = 0;
    int high = len - 1;
    int mid;

    int l = sortedArray[low];
    int h = sortedArray[high];

    while (l <= toFind && h >= toFind) {
        mid = low + ((float)(high - low)*(float)(toFind - l))/(1+(float)(h-l));
        int m = sortedArray[mid];

        if (m < toFind) {
            l = sortedArray[low = mid + 1];
        } else if (m > toFind) {
            h = sortedArray[high = mid - 1];
        } else {
            return mid;
        }
    }

    if (sortedArray[low] == toFind)
        return low;
    else
        return -1; // Not found
}

int binarySearch(int sortedArray[], int toFind, int len) 
{
    // Returns index of toFind in sortedArray, or -1 if not found
    int low = 0;
    int high = len - 1;
    int mid;

    int l = sortedArray[low];
    int h = sortedArray[high];

    while (l <= toFind && h >= toFind) {
        mid = (low + high)/2;

        int m = sortedArray[mid];

        if (m < toFind) {
            l = sortedArray[low = mid + 1];
        } else if (m > toFind) {
            h = sortedArray[high = mid - 1];
        } else {
            return mid;
        }
    }

    if (sortedArray[low] == toFind)
        return low;
    else
        return -1; // Not found
}

int order(const void *p1, const void *p2) { return *(int*)p1-*(int*)p2; }

int main(void) {
    int i = 0, j = 0, size = 100000, trials = 10000;
    int searched[trials];
    srand(-time(0));
    for (j=0; j<trials; j++) { searched[j] = Rand()%size; }

    while (size > 10){
        int arr[size];
        for (i=0; i<size; i++) { arr[i] = Rand()%size; }
        qsort(arr,size,sizeof(int),order);

        unsigned long long totalcycles_bs = 0;
        unsigned long long totalcycles_is_64 = 0;
        unsigned long long totalcycles_is_float = 0;
        unsigned long long totalcycles_new = 0;
        int res_bs, res_is_64, res_is_float, res_new;
        for (j=0; j<trials; j++) {
            unsigned long long tmp, cycles = rdtsc();
            res_bs = binarySearch(arr,searched[j],size);
            tmp = rdtsc(); totalcycles_bs += tmp - cycles; cycles = tmp;

            res_is_64 = interpolationSearch(arr,searched[j],size);
            assert(res_is_64 == res_bs || arr[res_is_64] == searched[j]); 
            tmp = rdtsc(); totalcycles_is_64 += tmp - cycles; cycles = tmp;

            res_is_float = interpolationSearch2(arr,searched[j],size);
            assert(res_is_float == res_bs || arr[res_is_float] == searched[j]); 
            tmp = rdtsc(); totalcycles_is_float += tmp - cycles; cycles = tmp;
        }
        printf("----------------- size = %10d\n", size);
        printf("binary search          = %10llu\n", totalcycles_bs);
        printf("interpolation uint64_t = %10llu\n",  totalcycles_is_64);
        printf("interpolation float    = %10llu\n",  totalcycles_is_float);
        printf("new                    = %10llu\n",  totalcycles_new);
        printf("\n");
        size >>= 1;
    }
}
23
kriss

Wenn Sie eine gewisse Kontrolle über das In-Memory-Layout der Daten haben, möchten Sie vielleicht Judy-Arrays betrachten.

Oder um es einfacher zu machen: Bei einer binären Suche wird der Suchraum immer halbiert. Ein optimaler Schnittpunkt kann durch Interpolation gefunden werden (der Schnittpunkt sollte NICHT der Ort sein, an dem der Schlüssel erwartet wird, sondern der Punkt, der die statistische Erwartung des Suchraums für den nächsten Schritt minimiert). Dies minimiert die Anzahl der Schritte, aber ... nicht alle Schritte sind gleich teuer. Mit hierarchischen Speichern können mehrere Tests gleichzeitig mit einem einzigen Test ausgeführt werden, wenn die Lokalität beibehalten werden kann. Da die ersten M Schritte einer binären Suche nur maximal 2 ** M eindeutige Elemente berühren, kann das gemeinsame Speichern dieser Elemente zu einer wesentlich geringeren Reduzierung des Suchraums pro Cacheline-Abruf (nicht per Vergleich) führen, was in der Realität eine höhere Leistung bedeutet.

n-ary-Bäume arbeiten auf dieser Basis, und dann fügen Judy-Arrays einige weniger wichtige Optimierungen hinzu.

Fazit: Selbst "Random Access Memory" (RAM) ist beim sequentiellen Zugriff schneller als zufällig. Ein Suchalgorithmus sollte diese Tatsache zu seinem Vorteil nutzen.

15
Ben Voigt

Benchmarking unter Win32 Core2 Quad Q6600, gcc v4.3 msys. Kompilieren mit g ++ -O3, nichts Besonderes.

Beobachtung - Die Aussagen, das Timing und der Overhead der Schleife betragen etwa 40%. Daher sollten die unten aufgeführten Gewinne durch 0,6 geteilt werden, um die tatsächliche Verbesserung der getesteten Algorithmen zu erhalten.

Einfache Antworten:

  1. Bei meiner Maschine ersetzt int64_t durch int für "low", "high" und "mid" in interpolationSearch eine Beschleunigung von 20% bis 40%. Dies ist die schnellste Methode, die ich finden konnte. Es dauert ungefähr 150 Zyklen pro Suche auf meinem Computer (für die Array-Größe von 100000). Das ist ungefähr die gleiche Anzahl von Zyklen wie ein Cache-Miss. In realen Anwendungen wird es wahrscheinlich der größte Faktor sein, auf den Cache zu achten.

  2. Durch Ersetzen von "/ 2" von binarySearch durch ">> 1" wird die Geschwindigkeit um 4% erhöht.

  3. Bei Verwendung des binary_search-Algorithmus von STL auf einem Vektor, der die gleichen Daten wie "arr" enthält, ist die Geschwindigkeit ungefähr dieselbe Geschwindigkeit wie die von Hand codierte binarySearch. Obwohl auf der kleineren "Größe" s STL ist viel langsamer - um 40%.

9

Ich habe eine übermäßig komplizierte Lösung, die eine spezialisierte Sortierfunktion erfordert. Die Sortierung ist etwas langsamer als ein guter Quellsort, aber alle meine Tests zeigen, dass die Suchfunktion viel schneller ist als eine Binär- oder Interpolationssuche. Ich nannte es eine Regressionsart, bevor ich herausfand, dass der Name bereits vergeben war, aber ich dachte nicht an einen neuen Namen (Ideen?).

Es gibt drei Dateien zum Demonstrieren.

Der Regressions-Sortierungs-/Suchcode:

#include <sstream>
#include <math.h>
#include <ctime>
#include "limits.h"

void insertionSort(int array[], int length) {
   int key, j;
   for(int i = 1; i < length; i++) {
      key = array[i];
      j = i - 1;
      while (j >= 0 && array[j] > key) {
         array[j + 1] = array[j];
         --j;
      }
      array[j + 1] = key;
   }
}

class RegressionTable {
   public:
      RegressionTable(int arr[], int s, int lower, int upper, double mult, int divs);
      RegressionTable(int arr[], int s);
      void sort(void);
      int find(int key);
      void printTable(void);
      void showSize(void);
   private:
      void createTable(void);
      inline unsigned int resolve(int n);
      int * array;
      int * table;
      int * tableSize;
      int size;
      int lowerBound;
      int upperBound;
      int divisions;
      int divisionSize;
      int newSize;
      double multiplier;
};

RegressionTable::RegressionTable(int arr[], int s) {
   array = arr;
   size = s;
   multiplier = 1.35;
   divisions = sqrt(size);
   upperBound = INT_MIN;
   lowerBound = INT_MAX;
   for (int i = 0; i < size; ++i) {
      if (array[i] > upperBound)
         upperBound = array[i];
      if (array[i] < lowerBound)
         lowerBound = array[i];
   }
   createTable();
}

RegressionTable::RegressionTable(int arr[], int s, int lower, int upper, double mult, int divs) {
   array = arr;
   size = s;
   lowerBound = lower;
   upperBound = upper;
   multiplier = mult;
   divisions = divs;
   createTable();
}

void RegressionTable::showSize(void) {
   int bytes = sizeof(*this);
   bytes = bytes + sizeof(int) * 2 * (divisions + 1);
}

void RegressionTable::createTable(void) {
   divisionSize = size / divisions;
   newSize = multiplier * double(size);
   table = new int[divisions + 1];
   tableSize = new int[divisions + 1];

   for (int i = 0; i < divisions; ++i) {
      table[i] = 0;
      tableSize[i] = 0;
   }

   for (int i = 0; i < size; ++i) {
      ++table[((array[i] - lowerBound) / divisionSize) + 1];
   }

   for (int i = 1; i <= divisions; ++i) {
      table[i] += table[i - 1];
   }
   table[0] = 0;

   for (int i = 0; i < divisions; ++i) {
      tableSize[i] = table[i + 1] - table[i];
   }
}

int RegressionTable::find(int key) {
   double temp = multiplier;
   multiplier = 1;

   int minIndex = table[(key - lowerBound) / divisionSize];
   int maxIndex = minIndex + tableSize[key / divisionSize];
   int guess = resolve(key);
   double t;
   while (array[guess] != key) {
      // uncomment this line if you want to see where it is searching.
      //cout << "Regression Guessing " << guess << ", not there." << endl;
      if (array[guess] < key) {
         minIndex = guess + 1;
      }
      if (array[guess] > key) {
         maxIndex = guess - 1;
      }
      if (array[minIndex] > key || array[maxIndex] < key) {
         return -1;
      }
      t = ((double)key - array[minIndex]) / ((double)array[maxIndex] - array[minIndex]);
      guess = minIndex + t * (maxIndex - minIndex);
   }

   multiplier = temp;

   return guess;
}

inline unsigned int RegressionTable::resolve(int n) {
   float temp;
   int subDomain = (n - lowerBound) / divisionSize;
   temp = n % divisionSize;
   temp /= divisionSize;
   temp *= tableSize[subDomain];
   temp += table[subDomain];
   temp *= multiplier;
   return (unsigned int)temp;
}

void RegressionTable::sort(void) {
   int * out = new int[int(size * multiplier)];
   bool * used = new bool[int(size * multiplier)];
   int higher, lower;
   bool placed;

   for (int i = 0; i < size; ++i) {

      /* Figure out where to put the darn thing */
      higher = resolve(array[i]);
      lower = higher - 1;

      if (higher > newSize) {
         higher = size;
         lower = size - 1;
      } else if (lower < 0) {
         higher = 0;
         lower = 0;
      }
      placed = false;
      while (!placed) {
         if (higher < size && !used[higher]) {
            out[higher] = array[i];
            used[higher] = true;
            placed = true;
         } else if (lower >= 0 && !used[lower]) {
            out[lower] = array[i];
            used[lower] = true;
            placed = true;
         }
         --lower;
         ++higher;
      }
   }
   int index = 0;
   for (int i = 0; i < size * multiplier; ++i) {
      if (used[i]) {
         array[index] = out[i];
         ++index;
      }
   }

   insertionSort(array, size);
}

Und dann gibt es die regulären Suchfunktionen:

#include <iostream>
using namespace std;

int binarySearch(int array[], int start, int end, int key) {
   // Determine the search point.
   int searchPos = (start + end) / 2;
   // If we crossed over our bounds or met in the middle, then it is not here.
   if (start >= end)
      return -1;
   // Search the bottom half of the array if the query is smaller.
   if (array[searchPos] > key)
      return binarySearch (array, start, searchPos - 1, key);
   // Search the top half of the array if the query is larger.
   if (array[searchPos] < key)
      return binarySearch (array, searchPos + 1, end, key);
   // If we found it then we are done.
   if (array[searchPos] == key)
      return searchPos;
}

int binarySearch(int array[], int size, int key) {
   return binarySearch(array, 0, size - 1, key);
}

int interpolationSearch(int array[], int size, int key) {
   int guess = 0;
   double t;
   int minIndex = 0;
   int maxIndex = size - 1;
   while (array[guess] != key) {

      t = ((double)key - array[minIndex]) / ((double)array[maxIndex] - array[minIndex]);
      guess = minIndex + t * (maxIndex - minIndex);

      if (array[guess] < key) {
         minIndex = guess + 1;
      }
      if (array[guess] > key) {
         maxIndex = guess - 1;
      }
      if (array[minIndex] > key || array[maxIndex] < key) {
         return -1;
      }
   }

   return guess;
}

Und dann habe ich eine einfache Hauptlinie geschrieben, um die verschiedenen Arten auszuprobieren.

    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    #include <ctime>
    #include "regression.h"
    #include "search.h"
    using namespace std;

    void randomizeArray(int array[], int size) {
       for (int i = 0; i < size; ++i) {
          array[i] = Rand() % size;
       }
    }

    int main(int argc, char * argv[]) {

       int size = 100000;
       string arg;
       if (argc > 1) {
          arg = argv[1];
          size = atoi(arg.c_str());
       }
       srand(time(NULL));
       int * array;
       cout << "Creating Array Of Size " << size << "...\n";
       array = new int[size];

       randomizeArray(array, size);
       cout << "Sorting Array...\n";
       RegressionTable t(array, size, 0, size*2.5, 1.5, size);
       //RegressionTable t(array, size);
       t.sort();
       int trials = 10000000;
       int start;

       cout << "Binary Search...\n";
       start = clock();
       for (int i = 0; i < trials; ++i) {
          binarySearch(array, size, i % size);
       }
       cout << clock() - start << endl;

       cout << "Interpolation Search...\n";
       start = clock();
       for (int i = 0; i < trials; ++i) {
          interpolationSearch(array, size, i % size);
       }
       cout << clock() - start << endl;

       cout << "Regression Search...\n";
       start = clock();
       for (int i = 0; i < trials; ++i) {
          t.find(i % size);
       }
       cout << clock() - start << endl;

       return 0;
}

Probieren Sie es aus und sagen Sie mir, ob es für Sie schneller ist. Es ist super kompliziert, also ist es wirklich leicht, es zu brechen, wenn Sie nicht wissen, was Sie tun. Seien Sie vorsichtig bei der Änderung.

Ich habe das Main mit g ++ auf Ubuntu kompiliert.

4
regality

Sehen Sie sich zuerst die Daten an und prüfen Sie, ob durch eine datenspezifische Methode eine große Verstärkung über eine allgemeine Methode erzielt werden kann.

Für große, statisch sortierte Datensätze können Sie einen zusätzlichen Index erstellen, um eine partielle Taubenlochung zu ermöglichen, basierend auf dem Speicherplatz, den Sie verwenden möchten. z.B. Angenommen, wir erstellen ein zweidimensionales Array mit 256 x 256 Pixeln, das wir mit den Start- und Endpositionen im Sucharray von Elementen mit entsprechenden Bytes hoher Ordnung füllen. Wenn wir zur Suche kommen, verwenden wir die Bytes höherer Ordnung des Schlüssels, um den Bereich/die Teilmenge des Arrays zu finden, das wir suchen müssen. Wenn wir bei unserer binären Suche nach 100.000 Elementen ~ 20 Vergleiche O(log2(n)) hatten, sind wir jetzt bei 4 Elementen für 16 Elemente oder O (log2 (n/15)). . Die Speicherkosten betragen hier etwa 512k

Eine andere Methode, die wiederum für Daten geeignet ist, die sich nicht viel ändern, ist das Aufteilen der Daten in Arrays von häufig gesuchten Elementen und selten gesuchten Elementen. Wenn Sie beispielsweise Ihre vorhandene Suche in einer großen Anzahl realer Fälle über einen längeren Testzeitraum laufen lassen und die Details des gesuchten Objekts protokollieren, stellen Sie möglicherweise fest, dass die Verteilung sehr ungleichmäßig ist, dh einige Werte sind sehr unterschiedlich viel häufiger als andere gesucht. Wenn dies der Fall ist, teilen Sie Ihr Array in ein viel kleineres Array mit häufig gesuchten Werten und ein größeres verbleibendes Array auf und suchen Sie zuerst das kleinere Array. Wenn die Daten richtig sind (großes Wenn!), Können Sie oft ähnliche Verbesserungen der ersten Lösung ohne die Speicherkosten erzielen.

Es gibt viele andere datenspezifische Optimierungen, die weitaus besser abschneiden als der Versuch, bewährte, weit verbreitete allgemeine Lösungen zu verbessern.

3
SmacL

Wenn nicht bekannt ist, dass Ihre Daten besondere Eigenschaften haben, besteht bei der reinen Interpolationssuche die Gefahr, dass sie lineare Zeit in Anspruch nimmt. Wenn Sie davon ausgehen, dass die Interpolation bei den meisten Daten hilfreich ist, aber bei pathologischen Daten nicht verletzt werden sollte, würde ich einen (möglicherweise gewichteten) Durchschnitt der interpolierten Vermutung und des Mittelpunkts verwenden, um eine logarithmische Begrenzung der Laufzeit sicherzustellen.

3
R..

Eine Möglichkeit, dies zu erreichen, ist die Verwendung eines Abstands zwischen Zeit und Zeit. Es gibt verschiedene Möglichkeiten, um dies zu erreichen. Der extreme Weg wäre, einfach ein Array zu erstellen, dessen maximale Größe dem maximalen Wert des sortierten Arrays entspricht. Initialisieren Sie jede Position mit dem Index in sortiertenArray. Dann wäre die Suche einfach O (1). 

Die folgende Version ist jedoch möglicherweise etwas realistischer und möglicherweise in der realen Welt nützlich. Es verwendet eine "Helfer" -Struktur, die beim ersten Aufruf initialisiert wird. Es bildet den Suchraum auf ein kleineres Feld ab, indem es durch eine Zahl dividiert wird, die ich ohne große Tests aus der Luft gezogen habe. Es speichert den Index der unteren Grenze für eine Gruppe von Werten in SortedArray in der Helper-Map. Die tatsächliche Suche teilt die toFind-Nummer durch den ausgewählten Divisor und extrahiert die eingegrenzten Grenzen von sortedArray für eine normale binäre Suche. 

Wenn beispielsweise die sortierten Werte im Bereich von 1 bis 1000 liegen und der Divisor 100 ist, enthält das Suchfeld möglicherweise 10 "Abschnitte". Um nach dem Wert 250 zu suchen, würde der Wert durch 100 dividiert, um eine ganzzahlige Indexposition 250/100 = 2 zu erhalten. map[2] würde den sortiertenArray-Index für Werte ab 200 enthalten. map[3] würde die Indexposition der Werte 300 und größer haben, wodurch eine kleinere Begrenzungsposition für eine normale binäre Suche bereitgestellt würde. Der Rest der Funktion ist dann eine exakte Kopie Ihrer binären Suchfunktion. 

Die Initialisierung der Helper-Map ist möglicherweise effizienter, wenn Sie die Positionen mit einer binären Suche anstelle eines einfachen Scans ausfüllen. Dies ist jedoch ein einmaliger Aufwand, sodass ich mich nicht mit dem Testen befasst habe. Dieser Mechanismus funktioniert gut für die angegebenen Testnummern, die gleichmäßig verteilt sind. Wie geschrieben, wäre es nicht so gut, wenn die Verteilung nicht gleichmäßig wäre. Ich denke, diese Methode könnte auch mit Fließkommasuchwerten verwendet werden. Es kann jedoch schwieriger sein, es auf generische Suchschlüssel zu extrapolieren. Zum Beispiel bin ich nicht sicher, wie die Methode für Zeichendatenschlüssel aussehen würde. Es würde eine Art O(1) Lookup/Hash benötigen, das einer bestimmten Arrayposition zugeordnet wurde, um die Indexgrenzen zu finden. Mir ist im Moment noch nicht klar, was diese Funktion wäre oder ob sie existiert.

Ich habe mir das Setup der Helper Map in der folgenden Implementierung ziemlich schnell vorgenommen. Es ist nicht hübsch und ich bin nicht 100% sicher, dass es in allen Fällen korrekt ist, aber es zeigt die Idee. Ich habe es mit einem Debug-Test ausgeführt, um die Ergebnisse mit Ihrer vorhandenen binarySearch-Funktion zu vergleichen, um sicher zu sein, dass es richtig funktioniert. 

Es folgen Beispielnummern:

100000 * 10000 : cycles binary search          = 10197811
100000 * 10000 : cycles interpolation uint64_t = 9007939
100000 * 10000 : cycles interpolation float    = 8386879
100000 * 10000 : cycles binary w/helper        = 6462534

Hier ist die schnelle und schmutzige Implementierung:

#define REDUCTION 100  // pulled out of the air
typedef struct {
    int init;  // have we initialized it?
    int numSections;
    int *map;
    int divisor;
} binhelp;

int binarySearchHelp( binhelp *phelp, int sortedArray[], int toFind, int len)
{
    // Returns index of toFind in sortedArray, or -1 if not found
    int low;
    int high;
    int mid;

    if ( !phelp->init && len > REDUCTION ) {
        int i;
        int numSections = len / REDUCTION;
        int divisor = (( sortedArray[len-1] - 1 ) / numSections ) + 1;
        int threshold;
        int arrayPos;

        phelp->init = 1;
        phelp->divisor = divisor;
        phelp->numSections = numSections;
        phelp->map = (int*)malloc((numSections+2) * sizeof(int));
        phelp->map[0] = 0;
        phelp->map[numSections+1] = len-1;
        arrayPos = 0;
        // Scan through the array and set up the mapping positions.  Simple linear
        // scan but it is a one-time cost.
        for ( i = 1; i <= numSections; i++ ) {
            threshold = i * divisor;
            while ( arrayPos < len && sortedArray[arrayPos] < threshold )
                arrayPos++;
            if ( arrayPos < len )
                phelp->map[i] = arrayPos;
            else
                // kludge to take care of aliasing
                phelp->map[i] = len - 1;
        }
    }

    if ( phelp->init ) {
        int section = toFind / phelp->divisor;
        if ( section > phelp->numSections )
            // it is bigger than all values
            return -1;

        low = phelp->map[section];
        if ( section == phelp->numSections )
            high = len - 1;
        else
            high = phelp->map[section+1];
    } else {
        // use normal start points
        low = 0;
        high = len - 1;
    }

    // the following is a direct copy of the Kriss' binarySearch
    int l = sortedArray[low];
    int h = sortedArray[high];

    while (l <= toFind && h >= toFind) {
        mid = (low + high)/2;

        int m = sortedArray[mid];

        if (m < toFind) {
            l = sortedArray[low = mid + 1];
        } else if (m > toFind) {
            h = sortedArray[high = mid - 1];
        } else {
            return mid;
        }
    }

    if (sortedArray[low] == toFind)
        return low;
    else
        return -1; // Not found
}

Die Helper-Struktur muss initialisiert (und der Speicher freigegeben werden):

    help.init = 0;
    unsigned long long totalcycles4 = 0;
    ... make the calls same as for the other ones but pass the structure ...
        binarySearchHelp(&help, arr,searched[j],length);
    if ( help.init )
        free( help.map );
    help.init = 0;
3
Mark Wilkins

Posting meiner aktuellen Version, bevor die Frage geschlossen ist (hoffentlich kann ich sie später noch verbessern). Im Moment ist es schlimmer als jede andere Version (wenn jemand versteht, warum meine Änderungen am Ende der Schleife diese Auswirkung haben, sind Kommentare willkommen).

int newSearch(int sortedArray[], int toFind, int len) 
{
    // Returns index of toFind in sortedArray, or -1 if not found
    int low = 0;
    int high = len - 1;
    int mid;

    int l = sortedArray[low];
    int h = sortedArray[high];

    while (l < toFind && h > toFind) {
        mid = low + ((float)(high - low)*(float)(toFind - l))/(1+(float)(h-l));

        int m = sortedArray[mid];

        if (m < toFind) {
            l = sortedArray[low = mid + 1];
        } else if (m > toFind) {
            h = sortedArray[high = mid - 1];
        } else {
            return mid;
        }
    }

    if (l == toFind)
        return low;
    else if (h == toFind)
        return high;
    else
        return -1; // Not found
}
2
kriss

Die Implementierung der binären Suche, die für Vergleiche verwendet wurde, kann verbessert werden. Die Schlüsselidee ist, den Bereich anfangs so zu "normalisieren", dass das Ziel nach dem ersten Schritt immer> ein Minimum und <ein Maximum ist. Dies erhöht die Abschlußdelta-Größe. Dies hat auch die Wirkung von speziellen Gehäusezielen, die kleiner als das erste Element des sortierten Arrays oder größer als das letzte Element des sortierten Arrays sind. Erwarten Sie eine Verbesserung der Suchzeit um etwa 15%. So könnte der Code in C++ aussehen.

int binarySearch(int * &array, int target, int min, int max)
{ // binarySearch
  // normalize min and max so that we know the target is > min and < max
  if (target <= array[min]) // if min not normalized
  { // target <= array[min]
      if (target == array[min]) return min;
      return -1;
  } // end target <= array[min]
  // min is now normalized

  if (target >= array[max]) // if max not normalized
  { // target >= array[max]
      if (target == array[max]) return max;
      return -1;
  } // end target >= array[max]
    // max is now normalized

  while (min + 1 < max)
  { // delta >=2
    int tempi = min + ((max - min) >> 1); // point to index approximately in the middle between min and max
    int atempi = array[tempi]; // just in case the compiler does not optimize this
    if (atempi > target)max = tempi; // if the target is smaller, we can decrease max and it is still normalized        
    else if (atempi < target)min = tempi; // the target is bigger, so we can increase min and it is still normalized        
        else return tempi; // if we found the target, return with the index
        // Note that it is important that this test for equality is last because it rarely occurs.
  } // end delta >=2
  return -1; // nothing in between normalized min and max
} // end binarySearch
0
Peter Baum