Índice
2. Análise lógica de problemas Top-K
2.1 Construa uma pilha, uma pequena pilha de tamanho K
3. Código de implementação do TopK
4. O código completo do problema Top-K
A introdução da pergunta TopK:
Todo mundo encontrou um herói número xxx na cidade xxx e um herói xxx número xxx no distrito xxx ao jogar King of Glory. Ou se quisermos comer uma determinada comida quando pedirmos takeaway hoje, abrimos o Meituan/Ele.me, escolhemos a opção mais próxima de nós ou a opção com a pontuação mais alta, e os x nomes da loja que você escolher serão classificados fora em ordem. Top 10 na lista da Forbes, top 5 na lista dos ricos do Hurun, etc. Esses problemas requerem a ordenação de uma grande quantidade de dados e a seleção dos maiores top K. Aqui, o algoritmo TopK é usado para resolver esse tipo de problema.
1. O que é um problema Top-K?
Problema TOP-K: Encontre os maiores elementos ou os menores elementos principais K na combinação de dados. Geralmente, a quantidade de dados é relativamente grande.
Por exemplo: os 10 melhores jogadores profissionais, os 500 melhores do mundo, a lista dos ricos, os 100 melhores jogadores ativos no jogo, etc.
Para o problema Top-K, a forma mais simples e direta que pode ser pensada é a ordenação, mas: se a quantidade de dados for muito grande, a ordenação não é aconselhável (talvez não seja possível carregar todos os dados na memória
em uma vez). A melhor maneira é usar o heap para resolvê-lo. A ideia básica é a seguinte:
1.1 Ideia básica do Top-K
(1) Use os primeiros K elementos no conjunto de dados para construir uma pilha.
Se forem os primeiros k elementos maiores, construa uma pilha pequena.
Se forem os primeiros k elementos menores, construa uma pilha grande.
(2) Use os elementos NK restantes para comparar com os elementos superiores (estamos aqui para encontrar o maior K como exemplo), estamos construindo um pequeno heap, então o elemento superior do heap é o menor neste pequeno pilha, então começamos de Os elementos NK restantes são primeiro comparados com o topo da pilha. Se for maior que o elemento superior da pilha, substitua o elemento superior da pilha e ajuste para baixo para reconstruir a pilha pequena. Se é menor que o elemento superior da pilha, não o substitua e deixe o próximo elemento Comparado com o topo da pilha, os elementos NK restantes são comparados por sua vez e esta etapa é repetida.
(3) Depois de comparar os elementos NK restantes com os elementos do topo da pilha, os K elementos restantes na pilha são os primeiros K menores ou maiores elementos procurados.
2. Análise lógica de problemas Top-K
(1) Primeiro use o primeiro K para construir pequenas pilhas;
(2) Compare os elementos N - K restantes com os elementos superiores por sua vez e substitua se forem maiores;
(3) Pilha de impressão.
Essa é a nossa grande lógica, vamos analisar essas três etapas passo a passo:
2.1 Construa uma pilha, uma pequena pilha de tamanho K
processo:
1. Primeiro abrimos um espaço de tamanho k;
2. Ajuste os primeiros K dados para baixo para formar uma pequena pilha. (Para quem não entende como ajustar para baixo, pode clicar aqui para revisar )
código mostra como abaixo:
int* kminheap = (int*)malloc(sizeof(int) * k);
if (NULL == kminheap)
{
perror("malloc fail:");
return;
}
for (int i = 0; i < k; i++)
{
fscanf(fout, "%d", &kminheap[i]);
}
//建小堆
for (int i = (k - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(kminheap, k, i);
}
2.2 Compare os elementos N - K restantes com os elementos superiores por sua vez e substitua-os se forem maiores
processo:
1. Como somos os maiores dados do top K, construímos um pequeno heap. O elemento superior do pequeno heap é o menor elemento do heap e os elementos NK restantes são comparados com o topo do heap;
2. Se este elemento for maior que o topo da pilha, vamos deixá-lo substituir o elemento superior da pilha, se for menor que isso, não vamos trocá-lo e passar para os seguintes elementos por sua vez para comparar;
3. Se for trocado, comece pelo topo da pilha e ajuste para baixo para reconstruir a pilha, e o topo da pilha será o menor elemento novamente;
4. Quando os elementos NK são comparados sequencialmente, os K elementos no heap são os primeiros K maiores elementos a serem encontrados.
código mostra como abaixo:
int val = 0;
while (!feof(fout))
{
fscanf(fout, "%d", &val);
if (val > kminheap[0])
{
kminheap[0] = val;
AdjustDown(kminheap, k, 0);
}
}
2.3 Pilha de Impressão
for (int i = 0; i < k; i++)
{
printf("%d ", kminheap[i]);
}
3. Código de implementação do TopK
void PrintTopK(int k)
{
const char* file = "data.txt";
FILE* fout = fopen(file, "r");
if (NULL == fout)
{
perror("fopen error:");
return;
}
int* kminheap = (int*)malloc(sizeof(int) * k);
if (NULL == kminheap)
{
perror("malloc fail:");
return;
}
for (int i = 0; i < k; i++)
{
fscanf(fout, "%d", &kminheap[i]);
}
//建小堆
for (int i = (k - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(kminheap, k, i);
}
int val = 0;
while (!feof(fout))
{
fscanf(fout, "%d", &val);
if (val > kminheap[0])
{
kminheap[0] = val;
AdjustDown(kminheap, k, 0);
}
}
for (int i = 0; i < k; i++)
{
printf("%d ", kminheap[i]);
}
printf("\n");
}
Nosso código aqui lê os dados do arquivo e armazenamos os dados preparados no arquivo.
4. O código completo do problema Top-K
Estamos primeiro criando 1.000 números, armazenando os números em um arquivo e, em seguida, pegando esses números do arquivo ao buscar Top-K.
void CreateNData()
{
//造数据
int n = 1000;
srand((unsigned int)time(NULL));
const char* file = "data.txt";
FILE* fin = fopen(file, "w");
if (NULL == fin)
{
perror("fopen error:");
return;
}
for (size_t i = 0; i < n; i++)
{
int x = rand() % 100000;
fprintf(fin, "%d\n", x);
}
fclose(fin);
}
void PrintTopK(int k)
{
const char* file = "data.txt";
FILE* fout = fopen(file, "r");
if (NULL == fout)
{
perror("fopen error:");
return;
}
int* kminheap = (int*)malloc(sizeof(int) * k);
if (NULL == kminheap)
{
perror("malloc fail:");
return;
}
for (int i = 0; i < k; i++)
{
fscanf(fout, "%d", &kminheap[i]);
}
//建小堆
for (int i = (k - 1 - 1) / 2; i >= 0; i--)
{
AdjustDown(kminheap, k, i);
}
int val = 0;
while (!feof(fout))
{
fscanf(fout, "%d", &val);
if (val > kminheap[0])
{
kminheap[0] = val;
AdjustDown(kminheap, k, 0);
}
}
for (int i = 0; i < k; i++)
{
printf("%d ", kminheap[i]);
}
printf("\n");
}
A exibição do resultado:
Técnica de verificação rápida : escrevemos no arquivo aqui. Para verificar rapidamente se o código está escrito corretamente, chamamos a interface que gera os dados, comentamos, entramos no arquivo data.txt e alteramos os cinco maiores dados e, em seguida, vá para imprimir, para que você possa verificar rapidamente.
Compare as duas imagens e imprima os 5 maiores valores.
*** Fim do artigo ***