一个关于算法的面试题,来源于网络

  1. /* 一个关于算法的面试题,来源于网络 */  
  2. /* 
  3. 请教大家一个算法题[问题点数:10分] 
  4. chu009 
  5. (chu009) 
  6.    
  7. 我面试的时候曾经遇到的一道算法题,写在这大家一起讨论下,争取找出个好的解决方案。 
  8. 题目是这样的:有两个文件,A文件里有大量的电话号码,上亿条,里面有少量的重复号码,要求把A文件里面的重复号码去掉然后存入B文件。 
  9.  
  10. 我的解决方法:建立一个二叉排序树存储所有A文件中不重复的电话号码信息。我从A文件每次读取一条电话号码,然后插入到二叉树结构中,如果这条记录已经存在则不进行插入。最后二叉排序树中包含了所有A文件中不重复的电话号码信息。改进的方式是在插入过程中将二叉排序树调整为二叉平衡树。 
  11. 将二叉树按某种方式进行遍历,将电话号码信息依次写入B文件。如果按中序遍历,则B文件中的电话号码是有序的。 
  12.  
  13. 这里我建立二叉树的时间复杂度是O(nlgn),写入B文件O(n),但是二叉树节点需要存储电话号码信息就要占用内存,上亿节点占用多大的内存啊,这是对方给我提出的challenge,我没给出更好的方法。 
  14.  
  15. 我的出发点是降低时间复杂度,但是没有解决内存占用问题。 
  16. 但是不把A文件中的节点存入内存,假如这样做:将A文件一次取一条记录,然后在B文件从头至尾查找是否有重复的,如果没有重复的加入到B文件末尾,然后A文件再取下一条,重复此过程。 
  17. 这样虽然节省了内存,但是时间复杂度为O(N*N)(上亿条记录,这个时间复杂度是很恐怖的),而且每插入一条就要把B文件读取一遍也是非常耗时的。 
  18.  
  19. 我没有想出更好的方法,大家帮忙看看吧。  
  20. */  
  21.   
  22.   
  23. /*==============================================================================    
  24. 文 件 名 : Win32CApp.c 
  25. 功    能 : 从A文件中读入手机号码,去掉重复出现的手机号,内容输出到文件B中。 
  26. 日    期 : 2011-10-16 
  27. 作    者 : jernymy 
  28. 版    权 : <Copyright(C) ... jernymy.> 
  29. 版    本 : V1.0 
  30. ------------------------------------------------------------------------------- 
  31. 说    明 : 使用位图的模式,参考编程珠玑(2)中介绍的一种算法。 
  32.  
  33.            以下是中国的手机号码分段情况 
  34.            新联通  (中国联通+中国网通)手机号码开头数字 130、131、132、145、 
  35.                155、156、185、186 
  36.            新移动  (中国移动+中国铁通)手机号码开头数字 134、135、136、137、 
  37.                138、139、147、150、151、152、157、158、159、182、183、187、188 
  38.            新电信  (中国电信+中国卫通)手机号码开头数字 133、153、189、180 
  39.             
  40.            号码段情况可以看到手机号码区间在130 0000 0000 - 189 9999 9999 
  41.            范围 = 600 0000 0000, 无法用以一个u32的整形表示到。 
  42.             
  43.            而160,170均不可用,所以将18用16来替换,于是180->160, 189->169 
  44.            则范围40 0000 0000,已经在u32最大范围之内 
  45.            (0xFFFF FFFF) 42 9496 7295,所以我们只需要定义足够u32数组即可。 
  46.  
  47.            目前定一个区间为40 0000 0000,共需要(40 0000 0000/32)= 
  48.            1 2500 0000个u32数组表示, 
  49.            公占用内存空间(40 0000 0000/32)*4=5 0000 0000 Bytes 
  50.            ≈476.837158203125M Bytes,方法可行。 
  51. ==============================================================================*/     
  52.   
  53. #include <stdio.h>  
  54. #include <string.h>  
  55. #include <stdlib.h>  
  56. #include <time.h>  
  57. #include <malloc.h>  
  58.   
  59. // 42 9496 7295  
  60. // 2147483648  
  61. typedef unsigned int   u32;  
  62.   
  63.   
  64. /* { jernymy - the status error no */  
  65. typedef u32                    STATUS;  
  66. #define ERR_OK                 0  
  67. #define ERR_PRMT_NULL          1  
  68. #define ERR_PHONE_ZERO         2  
  69. #define ERR_PHONE_NOTINRAGNE   3  
  70. #define ERR_PHONE_INVAILD      4  
  71. #define ERR_PHONE_LEN          5  
  72.   
  73. #define ERR_MALLOC             10  
  74. #define ERR_CREATE_FILE        11  
  75. #define ERR_OPEN_FILE          12  
  76. /* } jernymy - the status error no */  
  77.   
  78.   
  79. // 1亿的数据  
  80. #define ONE_YI                  (u32)(10000*10000)  
  81. // for test  
  82. #define FILE_PHONE_NUM          (u32)(10000*100)  
  83.   
  84. #define PHONE_EVERY             (u32)(10*ONE_YI)  
  85.   
  86. #define VAR_LEN                 (u32)(32)  
  87.   
  88. // phone like   130 xxxx xxxx  
  89. #define MAX_PHONE_NUM_LEN        11  
  90.   
  91. // process like  30 xxxx xxxx, remove high bit  
  92. #define MAX_PHONE_USE_LEN        10  
  93.   
  94. // current is 40 0000 0000  
  95. #define TOTAL_PHONE_NUM          (u32)(40*ONE_YI)  
  96.   
  97. // current is 30 0000 0000  
  98. #define SPECIAL_PHONE_NUM        (u32)(30*ONE_YI)  
  99.   
  100. // current is 40 0000 0000/32 = 1 2500 0000  
  101. #define MAX_PHONE_BIT            (u32)(TOTAL_PHONE_NUM/VAR_LEN)  
  102.   
  103. // source file, will process  
  104. #define PHONE_FILE_NAME          "phone.txt"  
  105.   
  106. // the dest file, not have repeat phone  
  107. #define PHONE_NO_RPT_FILE_NAME   "phone_norpt.txt"  
  108.   
  109. // set array one bit is 1  
  110. #define SET_ARY_BIT(ary,id)      ( ary[id/VAR_LEN] |= (1 << (id%VAR_LEN)) )  
  111.   
  112. // check array one bit is 1 ?  
  113. #define IS_SET_BIT(ary,id)       ( ary[id/VAR_LEN] &  (1 << (id%VAR_LEN)) )  
  114.   
  115. // current phone rang in used  
  116. static short g_sPhoneAry[] =   
  117. {  
  118.     130, 131, 132, 133, 134, 135, 136, 137, 138, 139,  
  119.                              145,      147,  
  120.     150, 151, 152, 153, 154, 155, 156, 157, 158, 159,  
  121.     180,      182, 183,      185, 186, 187, 188, 189,  
  122. };  
  123.   
  124. #define PHONE_TITLE_NUM        ( sizeof(g_sPhoneAry) / sizeof(short) )  
  125.   
  126. // u32 array pointer, need malloc  
  127. static u32 *g_padwPhoneAry = NULL;  
  128.   
  129. #define PHONE_REPEAT_FILE_NAME     "phone_rpt.txt"   
  130. static FILE *g_fpRepeat = NULL;  
  131.   
  132. /*--------------------------------- { function ---------------------------------*/  
  133. /*============================================================================== 
  134. 函 数 名 : TstInputFile 
  135. 功    能 : 建立一个手机号码文件,100万个,其中包括一部分重复的号码,仅测试使用 
  136. 参    数 : 无 
  137. 返 回 值 : 无 
  138. 日    期 : 2011-10-16 
  139. 作    者 : jernymy 
  140. 版    本 : V1.0 
  141. ==============================================================================*/  
  142. static void TstInputFile(void)  
  143. {  
  144.     u32 dwIdx;  
  145.     u32 dwVar;  
  146.     short wAryId;  
  147.     FILE *fpDst;  
  148.     char achPhone[12] = {0};  
  149.   
  150.     fpDst = fopen(PHONE_FILE_NAME, "wt");  
  151.     if (NULL == fpDst)  
  152.     {  
  153.         printf("open file:%s fail\n", PHONE_FILE_NAME);  
  154.         return;  
  155.     }  
  156.   
  157.     srand( (unsigned)time(NULL) );   
  158.   
  159.     printf("PHONE_TITLE_NUM:%d\n", PHONE_TITLE_NUM);  
  160.     // create FILE_PHONE_NUM phone number  
  161.     for (dwIdx = 0; dwIdx < FILE_PHONE_NUM; dwIdx++)  
  162.     {  
  163.         wAryId = rand()%PHONE_TITLE_NUM;  
  164.         dwVar  = rand()%FILE_PHONE_NUM;  
  165.         fprintf(fpDst, "%3d%08d\n", g_sPhoneAry[wAryId], dwVar);  
  166.           
  167.         // create 100 repeat phone number  
  168.         // and total phone may have other repeat   
  169.         if (0 == (dwIdx % (FILE_PHONE_NUM/100)) )  
  170.         {  
  171.             fprintf(fpDst, "%3d%08d\n", g_sPhoneAry[wAryId], dwVar);  
  172.         }  
  173.     }  
  174.     fclose(fpDst);  
  175. }  
  176.   
  177. /*============================================================================== 
  178. 函 数 名 : TstCrtRepeatFile 
  179. 功    能 : 建立一个文件句柄,该文件记录所有重复号码 
  180. 参    数 : 无 
  181. 返 回 值 : 无 
  182. 日    期 : 2011-10-16 
  183. 作    者 : jernymy 
  184. 版    本 : V1.0 
  185. ==============================================================================*/  
  186. static void TstCrtRepeatFile(void)  
  187. {  
  188.     g_fpRepeat = fopen(PHONE_REPEAT_FILE_NAME, "wt");  
  189.     if (NULL == g_fpRepeat)  
  190.     {  
  191.         printf("Create file:%s fail\n", PHONE_REPEAT_FILE_NAME);  
  192.     }  
  193. }  
  194.   
  195. /*============================================================================== 
  196. 函 数 名 : TstAtoll 
  197. 功    能 : 建立一个文件句柄,该文件记录所有重复号码 
  198. 参    数 : [in]  const char *pchStr     - 手机号码字符串 
  199.            [out] u32         *pdwNumber - 要输出的手机号码整形,将最高位的1去 
  200.                      掉,同时范围在0-3之间。前3为变动 
  201.                      130-159-->100-129-->00-29 
  202.                      180-189-->130-139-->30-39 
  203. 返 回 值 : STATUS (ERR_OK-success, other-error) 
  204. 日    期 : 2011-10-16 
  205. 作    者 : jernymy 
  206. 版    本 : V1.0 
  207. ==============================================================================*/  
  208. static STATUS TstAtoll(const char *pchStr, u32 *pdwNumber)  
  209. {  
  210.     u32  dwLen = 0;  
  211.     char achPhone[MAX_PHONE_NUM_LEN+1] = {0};  
  212.       
  213.     if (NULL == pchStr)  
  214.     {  
  215.         printf("parameter is NULL!\n");  
  216.         return ERR_PRMT_NULL;  
  217.     }  
  218.   
  219.     if (NULL == pchStr[0])  
  220.     {  
  221.         printf("parameter[0] is 0, phone is 0!\n");  
  222.         return ERR_PHONE_ZERO;  
  223.     }  
  224.   
  225.     // check phone is valid  
  226.     if (   (pchStr[1] > '8') || (pchStr[1] < '3') )  
  227.     {  
  228.         printf("parameter:%s not a phone!\n", pchStr);  
  229.         printf("must in range (130 0000 0000 - 189 9999 9999)!\n");  
  230.         return ERR_PHONE_NOTINRAGNE;  
  231.     }  
  232.   
  233.     // remove the high bit char, 130 xxxx xxxx - 30 xxxx xxxx  
  234.     strncpy(achPhone, pchStr+1, MAX_PHONE_USE_LEN);  
  235.   
  236.     /* change 18x xxxx xxxx -> 16x xxxx xxxx */  
  237.     if (achPhone[0] == '8')  
  238.     {  
  239.         achPhone[0] = '6';  
  240.     }  
  241.   
  242.     // range in u32 data, so change (13x-16x) (10x-13x)  
  243.     achPhone[0] -= 3;  
  244.     while (achPhone[dwLen] != '\n' && (dwLen < 10))  
  245.     {  
  246.         if ( (achPhone[dwLen] < '0') || (achPhone[dwLen] > '9') )  
  247.         {  
  248.             printf("parameter:%s is not a string number!\n", dwLen);  
  249.             return ERR_PHONE_INVAILD;  
  250.         }  
  251.         *pdwNumber = (*pdwNumber * 10) + (achPhone[dwLen]-'0');  
  252.         dwLen++;  
  253.     }  
  254.   
  255.     // check phone length is valid  
  256.     if (MAX_PHONE_USE_LEN != dwLen)  
  257.     {  
  258.         printf("parameter:%s length error, must is:%d\n",  
  259.             pchStr, MAX_PHONE_NUM_LEN);  
  260.         return ERR_PHONE_LEN;  
  261.     }  
  262.     return ERR_OK;  
  263. }  
  264.   
  265. /*============================================================================== 
  266. 函 数 名 : GetPhone 
  267. 功    能 : 从A文件中读取手机号码,并使用位图模式保存到分配的内存中。 
  268. 参    数 : 无 
  269. 返 回 值 : STATUS (ERR_OK-success, other-error) 
  270. 日    期 : 2011-10-16 
  271. 作    者 : jernymy 
  272. 版    本 : V1.0 
  273. ==============================================================================*/  
  274. static STATUS GetPhone(void)  
  275. {  
  276.     u32  dwNum;  
  277.     char achPhone[16] = {0};  
  278.     FILE *fpSrc;  
  279.   
  280.     // 5 0000 0000 Bytes  
  281.     // 476.837158203125 M Bytes  
  282.     // if here can not new this succ, please use 4 array, every new 1 2500 0000 Bytes  
  283.     printf("TOTAL_PHONE_NUM:%u, VAR_LEN:%u\n", TOTAL_PHONE_NUM, VAR_LEN);  
  284.     printf("malloc %u u32 size memory start\n", MAX_PHONE_BIT);  
  285.     g_padwPhoneAry = (u32 *)malloc(MAX_PHONE_BIT*sizeof(u32)); //    g_padwPhoneAry = new u32[MAX_PHONE_BIT];  
  286.     if (NULL == g_padwPhoneAry)  
  287.     {  
  288.         printf("malloc %u u32 size memory fail\n", MAX_PHONE_BIT);  
  289.         return ERR_MALLOC;  
  290.     }  
  291.     memset(g_padwPhoneAry, 0, MAX_PHONE_BIT*sizeof(u32));  
  292.   
  293.     fpSrc = fopen(PHONE_FILE_NAME, "rt");  
  294.     if (NULL == fpSrc)  
  295.     {  
  296.         printf("open file:%s fail\n", PHONE_FILE_NAME);  
  297.         return ERR_OPEN_FILE;  
  298.     }  
  299.   
  300.     while (!feof(fpSrc))  
  301.     {  
  302.         if (!fgets(achPhone, sizeof(achPhone), fpSrc))  
  303.         {  
  304.             break;  
  305.         }  
  306.   
  307.         // switch string phone to u32 data  
  308.         dwNum = 0;  
  309.         if (ERR_OK != TstAtoll(achPhone, &dwNum))  
  310.         {  
  311.             continue;  
  312.         }  
  313.   
  314.         // check the bit is set, no set the set  
  315.         if (!IS_SET_BIT(g_padwPhoneAry, dwNum))  
  316.         {  
  317.             SET_ARY_BIT(g_padwPhoneAry, dwNum);  
  318.         }  
  319.         else  
  320.         {  
  321.             // save the data to repeat file  
  322.             if (NULL != g_fpRepeat)  
  323.             {  
  324.                 // the string have \n  
  325.                 fprintf(g_fpRepeat, "%s", achPhone);  
  326.             }  
  327. //            printf("get a repeat num:%s\n", achPhone);  
  328.         }  
  329.     }  
  330.   
  331.     fclose(fpSrc);  
  332.     if (NULL != g_fpRepeat)  
  333.     {  
  334.         fclose(g_fpRepeat);  
  335.         g_fpRepeat = NULL;  
  336.     }  
  337.   
  338.     return ERR_OK;  
  339. }  
  340.   
  341. /*============================================================================== 
  342. 函 数 名 : PutPhone 
  343. 功    能 : 将内存中的数据存入到文件B中,此时已经没有重复的数据。 
  344. 参    数 : 无 
  345. 返 回 值 : STATUS (ERR_OK-success, other-error) 
  346. 日    期 : 2011-10-16 
  347. 作    者 : jernymy 
  348. 版    本 : V1.0 
  349. ==============================================================================*/  
  350. static STATUS PutPhone(void)  
  351. {  
  352.     u32 dwIdx;  
  353.     u32 dwHigh;  
  354.     FILE *fpDst;  
  355.     char achPhone[12] = {0};  
  356.   
  357.     fpDst = fopen(PHONE_NO_RPT_FILE_NAME, "wt");  
  358.     if (NULL == fpDst)  
  359.     {  
  360.         printf("Create file:%s fail\n", PHONE_NO_RPT_FILE_NAME);  
  361.         return ERR_CREATE_FILE;  
  362.     }  
  363.   
  364.     // the max range (40 0000 0000)  
  365.     for (dwIdx = 0; dwIdx < TOTAL_PHONE_NUM; dwIdx++)  
  366.     {  
  367.         if (IS_SET_BIT(g_padwPhoneAry, dwIdx))  
  368.         {  
  369.             dwHigh = dwIdx / SPECIAL_PHONE_NUM;  
  370.             dwHigh += 30;  
  371.             if (dwHigh >= 60)  
  372.             {  
  373.                 dwHigh += 20;  
  374.             }  
  375.             // 1xx xxxx xxxx to file B  
  376.             fprintf(fpDst, "1%2d%08d\n", dwHigh, dwIdx);  
  377.         }  
  378.     }  
  379.     fclose(fpDst);  
  380.     return ERR_OK;  
  381. }  
  382.   
  383. /*============================================================================== 
  384. 函 数 名 : PrintTime 
  385. 功    能 : 打印输入的字符串和当前时间 
  386. 参    数 : [in] const char *pchStr - 要打印的字符串 
  387. 返 回 值 : 无 
  388. 日    期 : 2011-10-16 
  389. 作    者 : jernymy 
  390. 版    本 : V1.0 
  391. ==============================================================================*/  
  392. static void PrintTime(const char *pchStr)  
  393. {  
  394.     time_t dwCurTime = time(NULL);  
  395.     printf("%s:%s", pchStr, ctime(&dwCurTime));  
  396. }  
  397.   
  398. /*============================================================================== 
  399. 函 数 名 : main 
  400. 功    能 : 文件的主函数 
  401. 参    数 : 无 
  402. 返 回 值 : 无 
  403. 日    期 : 2011-10-16 
  404. 作    者 : jernymy 
  405. 版    本 : V1.0 
  406. ==============================================================================*/  
  407. int main(void)  
  408. {  
  409.     // jernymy used create a phone file for test  
  410. //    TstInputFile();  
  411.   
  412.     // jernymy used create a phone repeat file  
  413.     // for save repeat phone, just test  
  414.     TstCrtRepeatFile();  
  415.   
  416.     // get phone data, from file string to memory u32  
  417.     // and remove repeat data  
  418.     printf("get file string phone start...\n");  
  419.     PrintTime("Start Time");  
  420.     if (ERR_OK != GetPhone())  
  421.     {  
  422.         printf("get file string phone fail\n");  
  423.         return -1;  
  424.     }  
  425.     PrintTime("End   Time");  
  426.     printf("get file string phone finish\n");  
  427.   
  428.     printf("---------------------------------------------\n");  
  429.   
  430.     // put phone data, from memory u32 to file string  
  431.     printf("put memory phone to file string start...\n");  
  432.     PrintTime("Start Time");  
  433.     if (ERR_OK != PutPhone())  
  434.     {  
  435.         printf("put memory phone to file string fail\n");  
  436.         return -2;  
  437.     }  
  438.     PrintTime("End   Time");  
  439.     printf("put memory phone to file string finish\n");  
  440.   
  441.     return 0;  
  442. }  
  443. /*--------------------------------- } function ---------------------------------*/  
  444.   
  445.   
  446. /* 
  447. jernymy 
  448. 测试结果VC6.0上,使用100万的测试数据中有筛选了重复之后剩下的62万多的数据 
  449. 耗时不到2分钟 
  450. 硬件信息 
  451. CPU--intel Pentium Dual E2160 1.8G 
  452. 内存-3G 
  453.  
  454. get file string phone start... 
  455. Start Time:Sun Oct 16 19:06:50 2011 
  456. TOTAL_PHONE_NUM:4000000000, VAR_LEN:32 
  457. malloc 125000000 u32 size memory start 
  458. End   Time:Sun Oct 16 19:06:51 2011 
  459. get file string phone finish 
  460. --------------------------------------------- 
  461. put memory phone to file string start... 
  462. Start Time:Sun Oct 16 19:06:51 2011 
  463. End   Time:Sun Oct 16 19:08:13 2011 
  464. put memory phone to file string finish 
  465. Press any key to continue 
  466. **/  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值