editar:
tão claramente que não expliquei isso muito bem, então deixe-me tentar novamente com exemplos. Eu tenho um 'pipe' de um determinado tamanho com sinais roteados através dele em determinadas compensações. O tubo pode se fragmentar com sinais em diferentes compensações, impossibilitando o ajuste de um novo sinal. Eu quero um algoritmo que me diga como organizar os sinais para desfragmentar o tubo; mas com um número mínimo de sinais realmente sendo movidos! Então, por exemplo ..
Digamos que eu tenho um tubo de tamanho 16. Ele tem os seguintes sinais com os tamanhos e compensações descritos.
offset 0: A (size of 4; fills slots 0-3)
offset 5: C (size of 2, fills slot 5-6)
offset 8: B (size of 4, fills 8-11)
offset 14: D (size 2, fills 14-15)
Pipe: AAAA_CC_BBBB__DD
Nesse caso, tenho 1 slot aberto nas compensações 4 e 7 e dois na compensação 12-13. Agora, digamos que eu queira adicionar um sinal de tamanho 4 a este tubo. Não há espaço contínuo para ele agora, mas sei que tenho espaço suficiente para desfragmentar. A solução "óbvia" é agrupar todos os sinais no topo, assim:
offset 0: A (size 4, fills 0-3)
offset 4: B (size 4, fills 4-7)
offset 8: C (size 2, fills 8-9)
offset 10: D (size 2, fills 10-11)
Pipe: AAAABBBBCCDD____
isso deixa os slots 12 a 15 gratuitos para o meu novo sinal. No entanto, para fazer isso, reposicionei 3 sinais (BD). Para cada sinal que mudei, tenho que enviar comandos para o hardware e aguardar uma quantidade não trivial de tempo.
Se eu fosse mais esperto, poderia perceber que há outra abordagem. Eu poderia reposicionar assim:
offset 0: A(size 4, fills 0-3)
offset 8: B(size 4, fills 8-11)
offset 12: C(size 2, fills 12-13)
offset 14: D(size 2, fills 14-15).
Pipe: AAAA____BBBBCCDD
Agora posso ajustar meu novo sinal nas compensações 4-7; E eu só tive que reposicionar um sinal (B). Economizando assim em chamadas de hardware.
Eu estou querendo saber se existe um bom algoritmo para detectar situações como esta; onde posso 'encaixar' um sinal em um tubo com o número mínimo de sinais movidos. O mês de abril que vem à mente é um N! algoritmo; que basicamente significa "gerar todas as distribuições possíveis, calcular em quantos movimentos resultou". Estou procurando uma abordagem mais rápida.
A abordagem não precisa ser 100% perfeita. Estou procurando principalmente minimizar o caso médio, desde que o pior caso não seja muito horrendo. Eu sei que nunca terei mais que 255 sinais em um determinado tubo; para que eu possa 'fugir' com o N! Tão ruim quanto isso soa. Eu também sei que o tamanho de cada sinal é uma potência de 2, assim como o tamanho do tubo.
Além disso, existem algoritmos brilhantes para a colocação de sinais que minimizem a fragmentação?
Pergunta respondida; ver abaixo.
Eu queria explicar um pouco a resposta para melhor explicar como a desfragmentação ocorreria para qualquer um que estivesse lendo; O amigo explica que eu queria apontar uma abordagem mais simples para conceituar e explicar a parte da difração em mais detalhes, já que essa era a pergunta original.
Estou explicando minha abordagem, que é uma abordagem ligeiramente diferente / mais simples, mas mantém efetivamente o conceito de "amigo". Não estou pré-computando blocos ou rotulando-os, é um esforço demais para implementar e manter. Para mim, o custo da CPU de calcular para onde o sinal irá é bastante trivial em comparação com a real colocação / exclusão de sinais; para que eu possa perder uma quantidade minúscula e linear de CPU, sem pré-computação para simplificar minha lógica. Então o processo é:
para inserção:
Todos os sinais são mantidos em limites de sinal iguais ao tamanho do sinal; portanto, um sinal começará no deslocamento, onde% de sinalização fora do tamanho = 0. Para o deslocamento atual, percorremos e descobrimos intervalos que mantêm esse limite. Portanto, se meu sinal for do tamanho 4 em um tubo de 16, examinarei os intervalos 0-4, 5-7, 8-11, 12-15.
Para cada intervalo, verifique se todo o espaço nesse intervalo está livre. No caso simples, temos um intervalo sem sinais e apenas colocamos o sinal nesse intervalo. Importante, observamos os intervalos em ordem e colocamos nosso sinal no primeiro intervalo livre , para garantir que quebremos o menor 'bloco' possível (usando termos de amizade) quando adicionamos nosso sinal. Isso deve ser equivalente ao método descrito por im3l96; exceto sem pré-computação de blocos.
se nenhum intervalo for completamente livre, temos que desfragmentar. Para isso, encontramos o sinal com os slots mais não utilizados. Se intervalos múltiplos tiverem o mesmo número de slots não utilizados, selecione o primeiro intervalo. Em seguida, encontramos o maior sinal nesse intervalo e chamamos recursivamente o mesmo algoritmo de inserção para o sinal menor (exceto marque o intervalo que selecionamos para inserir nosso primeiro sinal como indisponível de alguma forma). Isso move o sinal para outro lugar em que ele se encaixa. Em seguida, encontramos o próximo sinal menor no intervalo selecionado e fazemos o mesmo até mover todos os sinais. O pior caso de 2 ^ n-1 sinais foi movido; onde N é o número de tamanhos de sinal em potencial <= nosso sinal (assumindo que os sinais sejam múltiplos de 2, em seguida, N = log2 (tamanho do sinal)).
Aqui está um exemplo. * significa um slot marcado como indisponível quando chamamos recursivamente esse método (ou seja, o intervalo em que o método de chamada queria colocar seu sinal e, portanto, não quer que a chamada recursiva tente colocar um sinal)
Aqui está um caso mais simples e simples que eu poderia sugerir que ainda demonstra total complexidade. Nota: a estrutura a seguir seria difícil de criar, mas poderia resultar da abordagem do amigo se alguém tentasse muito.
FFFFFFFF__AA_B__EEEE_HGGCC_DII_J
Alguém passa em um sinal Z de tamanho 8
nós selecionamos o deslocamento 8:
defragInsert (z, tamanho 8)
effective structure: FFFFFFFF__AA_B__EEEE_HGGCC_DII_J
placing signal in interval: __AA_B__
defragInput (A, tamanho 2)
effective structure: FFFFFFFF********EEEE_HGGCC_DII_J
place signal in interval (offset 20) _H
defragInput (H, tamanho1)
effective structure: FFFFFFFF********EEEE**GGCC_DII_J
place signal between C & D
retornar defragInput (H, tamanho1)
effective structure: FFFFFFFF********EEEE__GGCCHDII_J
place H at offset 20 now that it's open
return defragInput (A, tamanho 2)
estrutura efetiva: FFFFFFFF_ _ _B__EEEEAAGGCCHDII_J move B now ...
defragInput (B, tamanho1)
estrutura efetiva: FFFFFFFF * ** * EEEEAAGGCCHDII_J coloque B entre I e J
retornar defragInput (B, tamanho1)
estrutura eficaz: FFFFFFFF_ __ _EEEEAAGGCCHDIIBJ add B
return defragInsert (z, tamanho 8)
fianl structure: FFFFFFFFzzzzzzzzEEEEAAGGCCHDIIBJ
fonte
Respostas:
O problema é semelhante à alocação de memória, então minha solução proposta é usar http://en.wikipedia.org/wiki/Buddy_memory_allocation . O uso do alocador de amigos minimiza a fragmentação, escolhendo o menor espaço livre contíguo no canal para um sinal.
Usando o exemplo, veja como o espaço será alocado para o tamanho 8 pipe:
Liberar espaço é uma questão de verificar o "amigo" do espaço que está sendo liberado; se o amigo também estiver livre, eles poderão ser mesclados para formar um espaço contíguo maior. Portanto, se o espaço estiver sendo liberado na ordem em que os sinais chegarem, ficará assim:
Também é bastante simples e rápido, porque há apenas uma pequena fragmentação, principalmente porque o tamanho dos sinais é a potência de 2.
Se for realmente necessário, a desfragmentação / compactação também pode ser feita facilmente, é apenas uma questão de encontrar blocos alocados do mesmo tamanho com amigos livres e mesclá-los (mover um bloco alocado criará um bloco livre maior).
fonte
Bem, antes de procurar uma resposta, você deve primeiro definir claramente o que deseja minimizar, ou seja, que tipo de reposicionamento de sinal é permitido.
tirar um (e apenas um) sinal do tubo e adicioná-lo em outro local sem sobreposições (e repetir esse passo n vezes)?
ou pegar n sinais simultaneamente do seu tubo e reinseri-los depois sem sobreposições (contados como n movimentos)?
Obviamente, essa primeira alternativa é muito mais restrita, oferecendo um espaço de pesquisa muito menor. Por exemplo, para passar de
AAAA_CC_BBBB__DD
paraAAAA_CC___DDBBBB
, serão necessários pelo menos 4 movimentos, se nenhum reposicionamento simultâneo for permitido, e 2 movimentos, se forem permitidos.Suponho que você tenha o primeiro problema em mente (confirme isso), então aqui está minha sugestão para isso:
faça deste um problema de pesquisa gráfica. Para um canal de distribuição, cada configuração de sinal define os vértices do seu gráfico, e as arestas entre esses vértices são os possíveis reposicionamentos.
atribuir a cada vértice um valor: o comprimento da sequência de slots contínua mais longa
Agora deve ser fácil usar uma técnica de pesquisa de gráfico padrão, como a primeira pesquisa de largura ou a pesquisa A *, para encontrar o menor número de etapas até chegar a uma configuração de canal que tenha espaço suficiente para o novo sinal que você deseja adicionar.
fonte
Você precisa coletar uma amostra representativa dos seus dados reais e simular diferentes algoritmos de reembalagem. No momento, não tenho informações suficientes para simular o sistema, portanto não pude verificar como funcionava qualquer algoritmo.
fonte