Je crois qu'il existe un moyen de trouver le kème plus grand élément dans un tableau non trié de longueur n dans O (n). Ou peut-être que c'est O (n) «attendu» ou quelque chose. Comment peut-on le faire?
performance
algorithm
big-o
MrDatabase
la source
la source
Réponses:
C'est ce qu'on appelle trouver la statistique d'ordre k . Il existe un algorithme aléatoire très simple (appelé quickselect ) prenant le
O(n)
temps moyen, leO(n^2)
pire des cas, et un algorithme non aléatoire assez compliqué (appelé introselect ) prenant leO(n)
pire des cas. Il y a quelques informations sur Wikipédia , mais ce n'est pas très bon.Tout ce dont vous avez besoin se trouve dans ces diapositives PowerPoint. Pour extraire l'algorithme de base de l'algorithme leO(n)
plus défavorable (introsélection):Il est également très bien détaillé dans le livre Introduction to Algorithms de Cormen et al.
la source
Si vous voulez un vrai
O(n)
algorithme, par opposition àO(kn)
quelque chose comme ça, alors vous devriez utiliser quickselect (c'est essentiellement quicksort où vous jetez la partition qui ne vous intéresse pas). Mon prof a une excellente synthèse, avec l'analyse d'exécution: ( référence )L'algorithme QuickSelect trouve rapidement le k-ème plus petit élément d'un tableau d'
n
éléments non triés . Il s'agit d'un RandomizedAlgorithm , nous calculons donc le temps d'exécution prévu le plus défavorable .Voici l'algorithme.
Quel est le temps d'exécution de cet algorithme? Si l'adversaire retourne des pièces pour nous, nous pouvons constater que le pivot est toujours l'élément le plus grand et
k
est toujours 1, ce qui donne un temps d'exécution deMais si les choix sont bien aléatoires, le temps de fonctionnement attendu est donné par
où nous faisons l'hypothèse non entièrement raisonnable que la récursion atterrit toujours dans le plus grand de
A1
ouA2
.Imaginons cela
T(n) <= an
pour certainsa
. Ensuite, nous obtenonset maintenant, d'une manière ou d'une autre, nous devons obtenir la somme horrible à droite du signe plus pour absorber celle
cn
de gauche. Si nous le relions juste comme , nous obtenons à peu près . Mais c'est trop grand - il n'y a pas de place pour ajouter un supplément . Développons donc la somme en utilisant la formule de série arithmétique:2(1/n) ∑i=n/2 to n an
2(1/n)(n/2)an = an
cn
où nous profitons du fait que n est "suffisamment grand" pour remplacer les
floor(n/2)
facteurs laids par le plus propre (et plus petit)n/4
. Nous pouvons maintenant continuer avecfournis
a > 16c
.Cela donne
T(n) = O(n)
. C'est clairementOmega(n)
, donc nous obtenonsT(n) = Theta(n)
.la source
k > length(A) - length(A2)
?A
dansA1
etA2
autour du pivot, nous le savonslength(A) == length(A1)+length(A2)+1
. Donc,k > length(A)-length(A2)
est équivalent àk > length(A1)+1
, ce qui est vrai quandk
est quelque partA2
.Un rapide Google à ce sujet («kème plus grand tableau d'éléments») a renvoyé ceci: http://discuss.joelonsoftware.com/default.asp?interview.11.509587.17
(c'était spécifiquement pour 3d plus grand)
et cette réponse:
la source
Vous aimez le tri rapide. Choisissez un élément au hasard et enfoncez tout plus haut ou plus bas. À ce stade, vous saurez quel élément vous avez réellement choisi, et si c'est le kème élément que vous avez terminé, sinon vous répétez avec le bac (supérieur ou inférieur), que le kème élément tomberait. Statistiquement parlant, l'heure il faut pour trouver que le kième élément croît avec n, O (n).
la source
Un compagnon de programmeur pour l'analyse d'algorithmes donne une version qui est O (n), bien que l'auteur déclare que le facteur constant est si élevé, vous préféreriez probablement la méthode naïve de trier la liste puis de sélectionner.
J'ai répondu à la lettre de ta question :)
la source
La bibliothèque standard C ++ a presque exactement cet appel de fonction
nth_element
, bien qu'elle modifie vos données. Il a prévu un temps d'exécution linéaire, O (N), et il effectue également un tri partiel.la source
Bien qu'il ne soit pas très sûr de la complexité de O (n), mais il sera sûr d'être entre O (n) et nLog (n). Assurez-vous également d'être plus proche de O (n) que de nLog (n). La fonction est écrite en Java
la source
J'ai implémenté la recherche de kth minimum dans n éléments non triés en utilisant la programmation dynamique, en particulier la méthode des tournois. Le temps d'exécution est O (n + klog (n)). Le mécanisme utilisé est répertorié comme l'une des méthodes sur la page Wikipédia sur l'algorithme de sélection (comme indiqué dans l'une des publications ci-dessus). Vous pouvez lire sur l'algorithme et également trouver du code (java) sur ma page de blog Finding Kth Minimum . De plus, la logique peut faire un classement partiel de la liste - retourner d'abord K min (ou max) en temps O (klog (n)).
Bien que le code fourni donne kth minimum, une logique similaire peut être utilisée pour trouver le kth maximum dans O (klog (n)), en ignorant le travail préalable effectué pour créer un arbre de tournoi.
la source
Vous pouvez le faire dans O (n + kn) = O (n) (pour k constant) pour le temps et O (k) pour l'espace, en gardant une trace des k plus grands éléments que vous avez vus.
Pour chaque élément du tableau, vous pouvez parcourir la liste des k plus grands et remplacer le plus petit élément par le nouveau s'il est plus grand.
La solution de tas prioritaire de Warren est plus nette cependant.
la source
O(n log k)
... dégénère toujours en O (nlogn) en cas de grand k. Je pense que cela fonctionnerait bien pour de petites valeurs de k cependant ... peut-être plus rapidement que certains des autres algorithmes mentionnés ici [???]Sélection rapide sexy en Python
la source
a1 = [i for i in arr if i > arr[r]]
eta2 = [i for i in arr if i < arr[r]]
, renverra le kème plus grand élément.numpy.sort
pournumpy array
ousorted
pour des listes) que d'utiliser cette implémentation manuelle.Trouvez la médiane du tableau en temps linéaire, puis utilisez la procédure de partitionnement exactement comme dans le tri rapide pour diviser le tableau en deux parties, les valeurs à gauche de la médiane étant inférieures (<) à la médiane et à droite supérieures à (>) la médiane , cela aussi peut être fait en temps linéaire, maintenant, allez à la partie du tableau où se trouve le kième élément, maintenant la récurrence devient: T (n) = T (n / 2) + cn qui me donne O (n) global.
la source
Vous trouverez ci-dessous le lien vers une implémentation complète avec une explication assez détaillée du fonctionnement de l'algorithme de recherche du Kème élément dans un algorithme non trié. L'idée de base est de partitionner le tableau comme dans QuickSort. Mais afin d'éviter les cas extrêmes (par exemple, lorsque le plus petit élément est choisi comme pivot à chaque étape, de sorte que l'algorithme dégénère en temps d'exécution O (n ^ 2)), une sélection de pivot spéciale est appliquée, appelée algorithme médiane des médianes. L'ensemble de la solution s'exécute en temps O (n) dans le pire et dans le cas moyen.
Voici le lien vers l'article complet (il s'agit de trouver Kth le plus petit élément, mais le principe est le même pour trouver Kth le plus grand ):
Trouver le Kth le plus petit élément dans un tableau non trié
la source
Selon cet article Trouver le Kème élément le plus grand dans une liste de n éléments, l'algorithme suivant prendra du
O(n)
temps dans le pire des cas.Analyse: Comme suggéré dans le document original:
Pourquoi la taille de la partition est prise 5 et non 3?
Comme mentionné dans le document original :
Maintenant, j'ai essayé d'implémenter l'algorithme ci-dessus comme:
Par souci de clarté, un autre algorithme utilise la file d'attente prioritaire et prend du temps
O(nlogn)
.Ces deux algorithmes peuvent être testés comme:
La sortie attendue est:
18 18
la source
Que diriez-vous de cette approche
Maintenez a
buffer of length k
et atmp_max
, obtenir tmp_max est O (k) et se fait n fois donc quelque chose commeO(kn)
Est-ce bien ou ai-je raté quelque chose?
Bien qu'il ne bat pas le cas moyen de la sélection rapide et le pire des cas de la méthode des statistiques médianes, il est assez facile à comprendre et à mettre en œuvre.
la source
parcourir la liste. si la valeur actuelle est plus grande que la plus grande valeur stockée, stockez-la en tant que valeur la plus grande et faites tomber les 1-4 et 5 supprime la liste. Sinon, comparez-le au numéro 2 et faites la même chose. Répétez, en le comparant aux 5 valeurs stockées. cela devrait le faire dans O (n)
la source
je voudrais suggérer une réponse
si nous prenons les k premiers éléments et les trions dans une liste chaînée de k valeurs
maintenant, pour toutes les autres valeurs, même dans le pire des cas, si nous faisons un tri par insertion pour les valeurs nk de repos, même dans le pire des cas, le nombre de comparaisons sera k * (nk) et pour les valeurs k précédentes à trier, que ce soit k * (k- 1) il en résulte que (nk-k) qui est o (n)
à votre santé
la source
Une explication de l'algorithme médiane des médianes pour trouver le k-ième plus grand entier sur n peut être trouvée ici: http://cs.indstate.edu/~spitla/presentation.pdf
L'implémentation en c ++ est ci-dessous:
la source
Il y a aussi l'algorithme de sélection de Wirth , qui a une implémentation plus simple que QuickSelect. L'algorithme de sélection de Wirth est plus lent que QuickSelect, mais avec certaines améliorations, il devient plus rapide.
Plus en détail. En utilisant l'optimisation MODIFIND de Vladimir Zabrodsky et la sélection de pivot de la médiane de 3 et en prêtant une attention aux étapes finales de la partie de partitionnement de l'algorithme, j'ai trouvé l'algorithme suivant (imaginablement nommé "LefSelect"):
Dans les benchmarks que j'ai faits ici , LefSelect est 20-30% plus rapide que QuickSelect.
la source
Solution Haskell:
Cela implémente la médiane des solutions médianes en utilisant la méthode withShape pour découvrir la taille d'une partition sans réellement la calculer.
la source
Voici une implémentation C ++ de QuickSelect aléatoire. L'idée est de choisir au hasard un élément pivot. Pour implémenter une partition aléatoire, nous utilisons une fonction aléatoire, rand () pour générer un index entre l et r, échanger l'élément à un index généré aléatoirement avec le dernier élément, et enfin appeler le processus de partition standard qui utilise le dernier élément comme pivot.
La pire complexité temporelle de la solution ci-dessus est toujours O (n2). Dans le pire des cas, la fonction aléatoire peut toujours choisir un élément de coin. La complexité temporelle attendue de QuickSelect randomisé ci-dessus est Θ (n)
la source
Appelez poll () k fois.
la source
Ceci est une implémentation en Javascript.
Si vous libérez la contrainte que vous ne pouvez pas modifier le tableau, vous pouvez empêcher l'utilisation de mémoire supplémentaire en utilisant deux index pour identifier la "partition actuelle" (dans le style de tri rapide classique - http://www.nczonline.net/blog/2012/ 11/27 / computer-science-in-javascript-quicksort / ).
Si vous souhaitez tester ses performances, vous pouvez utiliser cette variante:
Le reste du code consiste simplement à créer une aire de jeux:
Maintenant, exécutez vos tests quelques fois. En raison de Math.random (), il produira à chaque fois des résultats différents:
Si vous le testez plusieurs fois, vous pouvez voir même empiriquement que le nombre d'itérations est, en moyenne, O (n) ~ = constant * n et la valeur de k n'affecte pas l'algorithme.
la source
Je suis venu avec cet algorithme et semble être O (n):
Disons que k = 3 et nous voulons trouver le 3ème plus grand élément du tableau. Je créerais trois variables et comparerais chaque élément du tableau avec le minimum de ces trois variables. Si l'élément de tableau est supérieur à notre minimum, nous remplacerions la variable min par la valeur de l'élément. Nous continuons la même chose jusqu'à la fin du tableau. Le minimum de nos trois variables est le troisième plus grand élément du tableau.
Et, pour trouver le Kème élément le plus grand, nous avons besoin de K variables.
Exemple: (k = 3)
Quelqu'un peut-il revoir ceci et me faire savoir ce qui me manque?
la source
Voici l'implémentation de l'algorithme eladv proposée (j'ai également mis ici l'implémentation avec pivot aléatoire):
la source
elle est similaire à la stratégie quickSort, où nous choisissons un pivot arbitraire, et amenons les petits éléments à sa gauche et les plus grands à droite
la source
Allez à la fin de ce lien: ...........
http://www.geeksforgeeks.org/kth-smallestlargest-element-unsorted-array-set-3-worst-case-linear-time/
la source
Vous pouvez trouver le kème plus petit élément dans le temps O (n) et l'espace constant. Si nous considérons que le tableau est uniquement pour les entiers.
L'approche consiste à effectuer une recherche binaire sur la plage de valeurs de tableau. Si nous avons un min_value et un max_value à la fois dans la plage entière, nous pouvons faire une recherche binaire sur cette plage. Nous pouvons écrire une fonction de comparaison qui nous dira si une valeur est la kth-plus petite ou plus petite que kth-plus petite ou plus grande que kth-plus petite. Effectuez la recherche binaire jusqu'à ce que vous atteigniez le kième plus petit nombre
Voici le code pour ça
Solution de classe:
la source
Il existe également un algorithme qui surpasse l'algorithme de sélection rapide. Il s'agit de l' algorithme Floyd-Rivets (FR) .
Article d'origine: https://doi.org/10.1145/360680.360694
Version téléchargeable: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.309.7108&rep=rep1&type=pdf
Article de Wikipédia https://en.wikipedia.org/wiki/Floyd%E2%80%93Rivest_algorithm
J'ai essayé d'implémenter quickselect et l'algorithme FR en C ++. Je les ai également comparés aux implémentations standard de la bibliothèque C ++ std :: nth_element (qui est essentiellement un hybride introsélection de quickselect et heapselect). Le résultat a été quickselect et nth_element a fonctionné de manière comparable en moyenne, mais l'algorithme FR a fonctionné environ. deux fois plus vite par rapport à eux.
Exemple de code que j'ai utilisé pour l'algorithme FR:
la source
Ce que je ferais c'est ceci:
Vous pouvez simplement stocker des pointeurs vers le premier et le dernier élément de la liste chaînée. Ils ne changent que lorsque des mises à jour de la liste sont effectuées.
Mettre à jour:
la source
D'abord, nous pouvons construire un BST à partir d'un tableau non trié qui prend du temps O (n) et à partir du BST, nous pouvons trouver le kème plus petit élément dans O (log (n)) qui, au total, compte jusqu'à un ordre de O (n).
la source