Adivinhando por falta de contexto - você está perguntando sobre uma classificação na memória sem necessidade de espalhar resultados intermediários no disco?
esse é um excelente link, a propósito, parabéns e +1
ninesided 20/10/08
5
O tipo de bolha é terrível. É sempre O (n ^ 2). Pelo menos tire isso da sua resposta para que esteja certo, por favor.
jjnguy
79
jjnguy, isso é simplesmente errado. Eu acho que você precisa refazer sua classe de algoritmos. Em dados quase ordenados (é um caso adaptável), é O (N). No entanto, são necessárias duas passagens pelos dados e a Inserção leva apenas 1 para os dados quase classificados, o que torna a Inserção a vencedora. A bolha ainda é boa
mmcdole 21/10/08
3
O desempenho diminui muito se seus dados ainda não são quase classificados. Eu ainda não o usaria pessoalmente.
Blorgbeard sai em 21/10/08
5
Esse link foi quebrado quando eu tentei. Tente isto em vez disso: sorting-algorithms.com
Michael La Voie
107
Apenas alguns itens => CLASSIFICAÇÃO DA INSERÇÃO
Os itens já estão classificados principalmente => CLASSIFICAÇÃO DA INSERÇÃO
Preocupado com os piores cenários => HEAP SORT
Interessado em um bom resultado de caso médio => QUICKSORT
Os itens são retirados de um universo denso => ORÇAMENTO
Desejo escrever o mínimo de código possível => CLASSIFICAÇÃO DA INSERÇÃO
Esse é exatamente o tipo de resposta que eu estou procurando, leio livros, mas não consigo encontrar uma explicação clara para a seleção de alogoritmos em casos específicos. Você poderia elaborar isso ou passar um link para que eu possa entrar em contato com ele? um pouco mais? Obrigado
Simran kaur
9
Você deve adicionar "Os dados já estão classificados por outro critério => MERGE SORT"
Jim Hunziker
30
timsort
Timsort é "uma combinação natural adaptável, estável e estável" com " desempenho sobrenatural em muitos tipos de matrizes parcialmente ordenadas (são necessárias comparações inferiores a 1g (N!) E tão poucas quanto N-1)". O Python embutidosort()usa esse algoritmo há algum tempo, aparentemente com bons resultados. Ele foi projetado especificamente para detectar e tirar proveito de subsequências parcialmente classificadas na entrada, que geralmente ocorrem em conjuntos de dados reais. Geralmente, no mundo real, as comparações são muito mais caras do que trocar itens de uma lista, uma vez que normalmente apenas trocamos indicadores, o que muitas vezes faz do timsort uma excelente opção. No entanto, se você souber que suas comparações são sempre muito baratas (escrever um programa de brinquedo para classificar números inteiros de 32 bits, por exemplo), existem outros algoritmos que provavelmente terão um desempenho melhor. A maneira mais fácil de tirar proveito do timsort é, obviamente, usar o Python, mas como o Python é de código aberto, você também poderá emprestar o código. Como alternativa, a descrição acima contém detalhes mais que suficientes para escrever sua própria implementação.
@JF Sebastian: timsort é muito mais rápido do que lg(n!)comparações em uma matriz quase ordenada, até o final O(n)! | @behrooz: Nenhum tipo de comparação pode ter um caso médio de melhor que O(n log n)e lg(n!)é O(n log n). Portanto, o pior caso de timsort não é assintoticamente pior que o de qualquer outro tipo de comparação. Além disso, seu melhor caso é melhor ou igual a qualquer outro tipo de comparação.
Artelius
3
Timsort ainda é O (nlogn) no pior dos casos, mas seus bons casos são bastante agradáveis. Aqui está uma comparação, com alguns gráficos: stromberg.dnsalias.org/~strombrg/sort-comparison Note que timsort em Cython não era tão rápido como construído em timsort em C. de Python
user1277476
19
Classificação de inserção com o seguinte comportamento:
Para cada elemento knos slots 1..n, verifique primeiro se el[k] >= el[k-1]. Nesse caso, vá para o próximo elemento. (Obviamente pule o primeiro elemento.)
Caso contrário, use a pesquisa binária nos elementos 1..k-1para determinar o local de inserção e, em seguida, passe os elementos por cima. (Você pode fazer isso somente se k>Tonde Té algum valor limiar; com pequenas keste é um exagero.)
Acho que o tipo de bolha pode superar isso se o número de elementos não classificados for muito pequeno (como um ou dois), mas, em geral, isso me parece provavelmente a melhor solução.
Sol
Devido à etapa 1, para qualquer elemento que já esteja classificado, há exatamente uma comparação e zero movimentação de dados, o que é obviamente o melhor que você pode fazer. A Etapa 2 é aquela em que você pode melhorar, mas a bolha moverá o mesmo número de elementos e poderá ter mais comparações, dependendo da sua implementação.
Jason Cohen
Na verdade, pensando melhor, acho que o tipo de bolha é mais forte do que estava pensando. Na verdade, é uma pergunta bastante complicada. Por exemplo, se você considerar o caso em que a lista é totalmente classificada, exceto que o elemento que deve ser o último seja o primeiro, a classificação por bolhas superará amplamente o que você descreve.
305/08 Sol
Tentei implementar isso, mas a pesquisa binária não é uma melhoria, pois você ainda precisa mover o bloco inteiro para inserir o elemento. Então, ao invés de 2xrange, você obtém range + logb (range).
É baseado no quicksort, mas evita o pior comportamento que o quicksort tem para listas quase ordenadas.
O truque é que esse algoritmo de classificação detecta os casos em que o quicksort entra no modo de pior caso e muda para a classificação de pilha ou mesclagem. Partições quase ordenadas são detectadas por algum método de partição não ingênuo e partições pequenas são manipuladas usando a classificação por inserção.
Você obtém o melhor de todos os principais algoritmos de classificação pelo custo de mais código e complexidade. E você pode ter certeza de que nunca terá comportamento de pior caso, independentemente da aparência dos seus dados.
Se você é um programador de C ++, verifique seu algoritmo std :: sort. Ele já pode usar classificação introspectiva internamente.
Splaysort é um método de classificação obscuro baseado em árvores espalhadas , um tipo de árvore binária adaptável. Splaysort é bom não apenas para dados parcialmente classificados, mas também para dados parcialmente reversos ou para qualquer dado que tenha algum tipo de ordem preexistente. É O (nlogn) no caso geral e O (n) no caso em que os dados são classificados de alguma forma (frente, ré, régua, órgão etc.).
Sua grande vantagem sobre a classificação por inserção é que ela não reverte para o comportamento O (n ^ 2) quando os dados não são classificados, portanto, você não precisa ter certeza absoluta de que os dados são parcialmente classificados antes de usá-los. .
Sua desvantagem é a sobrecarga de espaço extra da estrutura da árvore de espalhamento necessária, bem como o tempo necessário para construir e destruir a árvore de espalhamento. Mas, dependendo do tamanho dos dados e da quantidade de pré-classificação esperada, a sobrecarga pode valer a pena pelo aumento da velocidade.
O smoothsort de Dijkstra é um ótimo tipo de dados já classificados. É uma variante heapsort executada em O (n lg n) pior caso e O (n) melhor caso. I escreveu uma análise do algoritmo, no caso de você estiver curioso como ele funciona.
O mergesort natural é outro realmente bom para isso - é uma variante de mergesort de baixo para cima que funciona tratando a entrada como a concatenação de vários intervalos classificados diferentes e, em seguida, usando o algoritmo de mesclagem para juntá-los. Você repete esse processo até que todo o intervalo de entrada seja classificado. Isso é executado em O (n) tempo se os dados já estiverem classificados e O (n lg n) na pior das hipóteses. É muito elegante, embora na prática não seja tão bom quanto outros tipos adaptativos, como Timsort ou smoothsort.
o que são as constantes de tempo de execução do smoothsort em comparação com outros algoritmos de classificação? (ou seja, tempo de execução (smoothsort) / tempo de execução (insertion sort) para os mesmos dados)
Arne Babenhauserheide
4
Se os elementos já estiverem classificados ou houver apenas alguns, seria um caso de uso perfeito para a Classificação de inserção!
A ordenação por inserção leva tempo O (n + o número de inversões).
Uma inversão é um par (i, j)tal que i < j && a[i] > a[j]. Ou seja, um par fora de ordem.
Uma medida de ser "quase classificado" é o número de inversões - pode-se tomar "dados quase classificados" para significar dados com poucas inversões. Se alguém souber que o número de inversões é linear (por exemplo, você acabou de adicionar elementos O (1) a uma lista classificada), a classificação por inserção leva tempo O (n).
Como todo mundo disse, tenha cuidado com o Quicksort ingênuo - que pode ter desempenho O (N ^ 2) em dados classificados ou quase classificados. No entanto, com um algoritmo apropriado para a escolha do pivô (aleatório ou mediano de três - consulte Escolhendo um pivô para o Quicksort ), o Quicksort ainda funcionará de maneira saudável.
Em geral, a dificuldade de escolher algoritmos como a classificação de inserção está em decidir quando os dados estão suficientemente fora de ordem para que o Quicksort realmente seja mais rápido.
Não vou fingir ter todas as respostas aqui, porque acho que obter as respostas reais pode exigir a codificação dos algoritmos e a criação de perfis em amostras de dados representativas. Mas eu estive pensando sobre essa pergunta a noite toda, e aqui está o que me ocorreu até agora e algumas suposições sobre o que funciona melhor onde.
Seja N o número total de itens, M seja o número fora de ordem.
O tipo de bolha terá que fazer algo como 2 * M + 1 passar por todos os N itens. Se M for muito pequeno (0, 1, 2?), Acho que será muito difícil de derrotar.
Se M for pequeno (digamos, menor que o log N), a classificação da inserção terá um ótimo desempenho médio. No entanto, a menos que haja um truque que eu não esteja vendo, ele terá um desempenho muito ruim no pior dos casos. (Certo? Se o último item do pedido for o primeiro, você deverá inserir todos os itens, tanto quanto eu possa ver, o que prejudicará o desempenho.) Suponho que exista um algoritmo de classificação mais confiável para isso. caso, mas não sei o que é.
Se M for maior (digamos igual ou ótimo que log N), a classificação introspectiva é quase certamente a melhor.
Exceção a tudo isso: se você souber antecipadamente quais elementos não estão classificados, sua melhor aposta será extrair esses itens, classificá-los usando uma classificação introspectiva e mesclar as duas listas classificadas em uma lista classificada. Se você pudesse descobrir rapidamente quais itens estão fora de ordem, essa também seria uma boa solução geral - mas não consegui descobrir uma maneira simples de fazer isso.
Pensamentos adicionais (durante a noite): Se M + 1 <N / M, você pode digitalizar a lista procurando uma execução de N / M em uma linha que seja classificada e, em seguida, expandir essa execução em qualquer direção para encontrar a saída -Itens de ordem. Isso levará no máximo 2N comparações. Em seguida, você pode classificar os itens não classificados e fazer uma mesclagem classificada nas duas listas. As comparações totais devem ser menores do que algo como 4N + M log2 (M), que superará qualquer rotina de classificação não especializada, eu acho. (Ainda mais: isso é mais complicado do que eu estava pensando, mas ainda acho que é razoavelmente possível.)
Outra interpretação da pergunta é que pode haver muitos itens fora de ordem, mas eles estão muito perto de onde deveriam estar na lista. (Imagine começar com uma lista classificada e trocar todos os outros itens pelo que vem depois dela.) Nesse caso, acho que a classificação das bolhas funciona muito bem - acho que o número de passes será proporcional ao item mais distante do lugar. é. A classificação de inserção funcionará mal, porque cada item fora de pedido acionará uma inserção. Suspeito que um tipo introspectivo ou algo assim funcione bem também.
Se você precisar de uma implementação específica para ordenar algoritmos, estruturas de dados ou qualquer coisa que tenha um link para o acima, eu poderia recomendar o excelente projeto "Estruturas de dados e algoritmos" no CodePlex?
Ele terá tudo o que você precisa sem reinventar a roda.
Essa bela coleção de algoritmos de classificação para esse fim nas respostas parece não ter o Gnome Sort , o que também seria adequado e provavelmente requer o menor esforço de implementação.
A classificação por inserção é o melhor caso O (n) na entrada classificada. E é muito próximo da entrada classificada principalmente (melhor que a classificação rápida).
Consistência não é motivo de preocupação aqui. O Heapsort fornecerá O (n lg n) mesmo em dados classificados e não é realmente adaptável. As opções viáveis podem ser: Classificação de inserção, Timsort e Bubblesort.
Max
0
A classificação por bolha (ou, mais segura ainda, a classificação bidirecional por bolhas) provavelmente é ideal para a maioria das listas classificadas, embora eu aposto que uma classificação por pente com ajustes (com um tamanho de intervalo inicial muito menor) seria um pouco mais rápida quando a lista não estivesse ' t perfeitamente organizado. Classificação de pente degrada para classificação de bolha.
Esse teste de eficiência de algoritmo "até onde estou preocupado" iluminou meu dia :) Mas falando sério, ao escrever "remover e inserir", você quis dizer Insertion Sort (que já foi mencionado nas respostas anteriores), ou você oferece um novo tipo de algoritmo? Nesse caso, expanda sua resposta.
usar o seguinte comando
0
O tipo de bolha é definitivamente o vencedor O próximo no radar seria o tipo de inserção.
Eu sugiro que você dê uma olhada nas respostas disponíveis antes de postar para evitar duplicatas.
angainor
-1
Afaste-se do QuickSort - é muito ineficiente para dados pré-classificados. A classificação por inserção manipula bem quase os dados classificados, movendo o menor número possível de valores.
Respostas:
Com base no método altamente científico de assistir gifs animados, eu diria que os tipos de inserção e bolha são bons candidatos.
fonte
Apenas alguns itens => CLASSIFICAÇÃO DA INSERÇÃO
Os itens já estão classificados principalmente => CLASSIFICAÇÃO DA INSERÇÃO
Preocupado com os piores cenários => HEAP SORT
Interessado em um bom resultado de caso médio => QUICKSORT
Os itens são retirados de um universo denso => ORÇAMENTO
Desejo escrever o mínimo de código possível => CLASSIFICAÇÃO DA INSERÇÃO
fonte
timsort
Timsort é "uma combinação natural adaptável, estável e estável" com " desempenho sobrenatural em muitos tipos de matrizes parcialmente ordenadas (são necessárias comparações inferiores a 1g (N!) E tão poucas quanto N-1)". O Python embutido
sort()
usa esse algoritmo há algum tempo, aparentemente com bons resultados. Ele foi projetado especificamente para detectar e tirar proveito de subsequências parcialmente classificadas na entrada, que geralmente ocorrem em conjuntos de dados reais. Geralmente, no mundo real, as comparações são muito mais caras do que trocar itens de uma lista, uma vez que normalmente apenas trocamos indicadores, o que muitas vezes faz do timsort uma excelente opção. No entanto, se você souber que suas comparações são sempre muito baratas (escrever um programa de brinquedo para classificar números inteiros de 32 bits, por exemplo), existem outros algoritmos que provavelmente terão um desempenho melhor. A maneira mais fácil de tirar proveito do timsort é, obviamente, usar o Python, mas como o Python é de código aberto, você também poderá emprestar o código. Como alternativa, a descrição acima contém detalhes mais que suficientes para escrever sua própria implementação.fonte
lg(n!)
comparações em uma matriz quase ordenada, até o finalO(n)
! | @behrooz: Nenhum tipo de comparação pode ter um caso médio de melhor queO(n log n)
elg(n!)
éO(n log n)
. Portanto, o pior caso de timsort não é assintoticamente pior que o de qualquer outro tipo de comparação. Além disso, seu melhor caso é melhor ou igual a qualquer outro tipo de comparação.Classificação de inserção com o seguinte comportamento:
k
nos slots1..n
, verifique primeiro seel[k] >= el[k-1]
. Nesse caso, vá para o próximo elemento. (Obviamente pule o primeiro elemento.)1..k-1
para determinar o local de inserção e, em seguida, passe os elementos por cima. (Você pode fazer isso somente sek>T
ondeT
é algum valor limiar; com pequenask
este é um exagero.)Este método faz o menor número de comparações.
fonte
Tente classificação introspectiva. http://en.wikipedia.org/wiki/Introsort
É baseado no quicksort, mas evita o pior comportamento que o quicksort tem para listas quase ordenadas.
O truque é que esse algoritmo de classificação detecta os casos em que o quicksort entra no modo de pior caso e muda para a classificação de pilha ou mesclagem. Partições quase ordenadas são detectadas por algum método de partição não ingênuo e partições pequenas são manipuladas usando a classificação por inserção.
Você obtém o melhor de todos os principais algoritmos de classificação pelo custo de mais código e complexidade. E você pode ter certeza de que nunca terá comportamento de pior caso, independentemente da aparência dos seus dados.
Se você é um programador de C ++, verifique seu algoritmo std :: sort. Ele já pode usar classificação introspectiva internamente.
fonte
Splaysort é um método de classificação obscuro baseado em árvores espalhadas , um tipo de árvore binária adaptável. Splaysort é bom não apenas para dados parcialmente classificados, mas também para dados parcialmente reversos ou para qualquer dado que tenha algum tipo de ordem preexistente. É O (nlogn) no caso geral e O (n) no caso em que os dados são classificados de alguma forma (frente, ré, régua, órgão etc.).
Sua grande vantagem sobre a classificação por inserção é que ela não reverte para o comportamento O (n ^ 2) quando os dados não são classificados, portanto, você não precisa ter certeza absoluta de que os dados são parcialmente classificados antes de usá-los. .
Sua desvantagem é a sobrecarga de espaço extra da estrutura da árvore de espalhamento necessária, bem como o tempo necessário para construir e destruir a árvore de espalhamento. Mas, dependendo do tamanho dos dados e da quantidade de pré-classificação esperada, a sobrecarga pode valer a pena pelo aumento da velocidade.
Um artigo sobre splaysort foi publicado em Software - Practice & Experience.
fonte
inserção ou tipo de concha!
fonte
O smoothsort de Dijkstra é um ótimo tipo de dados já classificados. É uma variante heapsort executada em O (n lg n) pior caso e O (n) melhor caso. I escreveu uma análise do algoritmo, no caso de você estiver curioso como ele funciona.
O mergesort natural é outro realmente bom para isso - é uma variante de mergesort de baixo para cima que funciona tratando a entrada como a concatenação de vários intervalos classificados diferentes e, em seguida, usando o algoritmo de mesclagem para juntá-los. Você repete esse processo até que todo o intervalo de entrada seja classificado. Isso é executado em O (n) tempo se os dados já estiverem classificados e O (n lg n) na pior das hipóteses. É muito elegante, embora na prática não seja tão bom quanto outros tipos adaptativos, como Timsort ou smoothsort.
fonte
Se os elementos já estiverem classificados ou houver apenas alguns, seria um caso de uso perfeito para a Classificação de inserção!
fonte
A ordenação por inserção leva tempo O (n + o número de inversões).
Uma inversão é um par
(i, j)
tal quei < j && a[i] > a[j]
. Ou seja, um par fora de ordem.Uma medida de ser "quase classificado" é o número de inversões - pode-se tomar "dados quase classificados" para significar dados com poucas inversões. Se alguém souber que o número de inversões é linear (por exemplo, você acabou de adicionar elementos O (1) a uma lista classificada), a classificação por inserção leva tempo O (n).
fonte
Como todo mundo disse, tenha cuidado com o Quicksort ingênuo - que pode ter desempenho O (N ^ 2) em dados classificados ou quase classificados. No entanto, com um algoritmo apropriado para a escolha do pivô (aleatório ou mediano de três - consulte Escolhendo um pivô para o Quicksort ), o Quicksort ainda funcionará de maneira saudável.
Em geral, a dificuldade de escolher algoritmos como a classificação de inserção está em decidir quando os dados estão suficientemente fora de ordem para que o Quicksort realmente seja mais rápido.
fonte
Não vou fingir ter todas as respostas aqui, porque acho que obter as respostas reais pode exigir a codificação dos algoritmos e a criação de perfis em amostras de dados representativas. Mas eu estive pensando sobre essa pergunta a noite toda, e aqui está o que me ocorreu até agora e algumas suposições sobre o que funciona melhor onde.
Seja N o número total de itens, M seja o número fora de ordem.
O tipo de bolha terá que fazer algo como 2 * M + 1 passar por todos os N itens. Se M for muito pequeno (0, 1, 2?), Acho que será muito difícil de derrotar.
Se M for pequeno (digamos, menor que o log N), a classificação da inserção terá um ótimo desempenho médio. No entanto, a menos que haja um truque que eu não esteja vendo, ele terá um desempenho muito ruim no pior dos casos. (Certo? Se o último item do pedido for o primeiro, você deverá inserir todos os itens, tanto quanto eu possa ver, o que prejudicará o desempenho.) Suponho que exista um algoritmo de classificação mais confiável para isso. caso, mas não sei o que é.
Se M for maior (digamos igual ou ótimo que log N), a classificação introspectiva é quase certamente a melhor.
Exceção a tudo isso: se você souber antecipadamente quais elementos não estão classificados, sua melhor aposta será extrair esses itens, classificá-los usando uma classificação introspectiva e mesclar as duas listas classificadas em uma lista classificada. Se você pudesse descobrir rapidamente quais itens estão fora de ordem, essa também seria uma boa solução geral - mas não consegui descobrir uma maneira simples de fazer isso.
Pensamentos adicionais (durante a noite): Se M + 1 <N / M, você pode digitalizar a lista procurando uma execução de N / M em uma linha que seja classificada e, em seguida, expandir essa execução em qualquer direção para encontrar a saída -Itens de ordem. Isso levará no máximo 2N comparações. Em seguida, você pode classificar os itens não classificados e fazer uma mesclagem classificada nas duas listas. As comparações totais devem ser menores do que algo como 4N + M log2 (M), que superará qualquer rotina de classificação não especializada, eu acho. (Ainda mais: isso é mais complicado do que eu estava pensando, mas ainda acho que é razoavelmente possível.)
Outra interpretação da pergunta é que pode haver muitos itens fora de ordem, mas eles estão muito perto de onde deveriam estar na lista. (Imagine começar com uma lista classificada e trocar todos os outros itens pelo que vem depois dela.) Nesse caso, acho que a classificação das bolhas funciona muito bem - acho que o número de passes será proporcional ao item mais distante do lugar. é. A classificação de inserção funcionará mal, porque cada item fora de pedido acionará uma inserção. Suspeito que um tipo introspectivo ou algo assim funcione bem também.
fonte
Se você precisar de uma implementação específica para ordenar algoritmos, estruturas de dados ou qualquer coisa que tenha um link para o acima, eu poderia recomendar o excelente projeto "Estruturas de dados e algoritmos" no CodePlex?
Ele terá tudo o que você precisa sem reinventar a roda.
Apenas meu pequeno grão de sal.
fonte
Essa bela coleção de algoritmos de classificação para esse fim nas respostas parece não ter o Gnome Sort , o que também seria adequado e provavelmente requer o menor esforço de implementação.
fonte
A classificação por inserção é o melhor caso O (n) na entrada classificada. E é muito próximo da entrada classificada principalmente (melhor que a classificação rápida).
fonte
ponderar Experimente o Heap. Eu acredito que é o mais consistente dos tipos O (n lg n).
fonte
A classificação por bolha (ou, mais segura ainda, a classificação bidirecional por bolhas) provavelmente é ideal para a maioria das listas classificadas, embora eu aposto que uma classificação por pente com ajustes (com um tamanho de intervalo inicial muito menor) seria um pouco mais rápida quando a lista não estivesse ' t perfeitamente organizado. Classificação de pente degrada para classificação de bolha.
fonte
bem, depende do caso de uso. Se você souber quais elementos foram alterados, remova e insira será o melhor caso, no que me diz respeito.
fonte
O tipo de bolha é definitivamente o vencedor O próximo no radar seria o tipo de inserção.
fonte
Afaste-se do QuickSort - é muito ineficiente para dados pré-classificados. A classificação por inserção manipula bem quase os dados classificados, movendo o menor número possível de valores.
fonte