C語言筆試:top K 問題
經過幾次C語言筆試,發現經常會被問到求1萬個數中前100大的數,現在想了兩種方法來解決:
方法一:一維數值
代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
//求數組的最大值,返回b【0】
int max(int b[],int n)
{
int i,t,k=0,m=0;
int c=n;
//將數組兩兩進行比較,把較大值至於最前面
while(n!=1)
{
for(i=0;i<n;i++)
{
if(b[i]>b[i+1])
{
t=0;
t=b[i];
b[i]=b[i/2];
b[i/2]=t;
}
else{
t=0;
t=b[i+1];
b[i+1]=b[i/2];
b[i/2]=t;
}
i++;
}
n=n/2;
}
m=b[0];
return m;
}
int main(int argc, char *argv[])
{
int *test,i,k,d=0,x=0,y=0;
int l=100000,h=100; //l表示數的總個數,h表示要求的前h大數
int m[h];
d=l;
if(d&(d-1))
{
while(d>1){
d>>=1;
x++;}
x++;
}
else
{
while(d>1){
d>>=1;
x++;} //x表示要進行的比較次數,y表示要申請的空間大小
}
y=pow(2,x);
srand(time(0));
test=(int *)malloc(sizeof(int)*y);
for(long a=0;a<l;a++)
{
test[a]=rand()%100000+1; //動態生成隨機數
printf("%d ",test[a]);
}
printf("\n");
for(i=l;i<y;i++)
{
test[i]=0;
}
m[0]=max(test,y);
for(i=1;i<h;i++)
{
for(k=0;k<l;k++)
{
if(test[k]==m[i-1])
test[k]=0;
}
m[i]=max(test,y);
}
printf("這%d個數中前%d大的數分別為:\n",l,h);
for(i=0;i<h;i++)
{
printf("%d ",m[i]);
}
printf("\n");
printf("單次比較次數為:%d\n",x);
printf("總計比較次數為:%d\n",h*x);
printf("\n");
free(test);
test=NULL;
return 0;
}
方法二:哈夫曼樹
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef int ElemType;
struct BTreeNode
{
ElemType data;
struct BTreeNode* left;
struct BTreeNode* right;
};
//根據數組 a 中 n 個權值建立一棵哈夫曼樹,返回樹根指針
struct BTreeNode* CreateHuffman(ElemType a[], int n)
{
int i, j;
struct BTreeNode **b, *q;
b = (BTreeNode **)malloc(sizeof(struct BTreeNode)*n);
for (i = 0; i < n; i++) //初始化b指針數組,使每個指針元素指向a數組中對應的元素結點
{
b[i] = (BTreeNode *)malloc(sizeof(struct BTreeNode));
b[i]->data = a[i];
b[i]->left = b[i]->right = NULL;
}
for (i = 1; i < n; i++)//進行 n-1 次循環建立哈夫曼樹
{
//k1表示森林中具有最小權值的樹根結點的下標,k2為次最小的下標
int k1 = -1, k2;
for (j = 0; j < n; j++)//讓k1初始指向森林中第一棵樹,k2指向第二棵
{
if (b[j] != NULL && k1 == -1)
{
k1 = j;
continue;
}
if (b[j] != NULL)
{
k2 = j;
break;
}
}
for (j = k2; j < n; j++)//從當前森林中求出最小權值樹和次最小
{
if (b[j] != NULL)
{
if (b[j]->data < b[k1]->data)
{
k2 = k1;
k1 = j;
}
else if (b[j]->data < b[k2]->data)
k2 = j;
}
}
//由最小權值樹和次最小權值樹建立一棵新樹,q指向樹根結點
q = (BTreeNode *)malloc(sizeof(struct BTreeNode));
q->data = b[k2]->data;
q->left = b[k1];
q->right = b[k2];
b[k1] = q;//將指向新樹的指針賦給b指針數組中k1位置
b[k2] = NULL;//k2位置為空
}
free(b); //刪除動態建立的數組b
return q; //返回整個哈夫曼樹的樹根指針
}
int main(int argc, char *argv[])
{
int *test;
int l=100,h=10,i,k;
int m[h];
struct BTreeNode* q;
srand(time(0));
test=(int *)malloc(sizeof(int)*l);
for(long a=0;a<l;a++)
{
test[a]=rand()%100+1;
printf("%d ",test[a]);
}
printf("\n");
q=CreateHuffman(test,l);
m[0]=q->data;
for(i=1;i<h;i++)
{
for(k=0;k<l;k++)
{
if(test[k]==m[i-1])
test[k]=0;
}
q=CreateHuffman(test,l);
m[i]=q->data;
}
printf("這%d個數中前%d大的數分別為:\n",l,h);
for(i=0;i<h;i++)
{
printf("%d ",m[i]);
}
printf("\n");
printf("比較次數為:%d",l-1);
printf("\n");
return 0;
}
運行結果如下:
C語言筆試:top K 問題