统计出现次数最多的数据

来源:互联网 发布:c语言打印图形 编辑:程序博客网 时间:2024/05/02 13:42

http://blog.csdn.net/v_july_v/article/details/6403777#comments

题目描述:
给你上千万或上亿数据(有重复),统计其中出现次数最多的前N个数据。

    分析:上千万或上亿的数据,现在的机器的内存应该能存下(也许可以,也许不可以)。所以考虑采用hash_map/搜索二叉树/红黑树等来进行统计次数。然后就是取出前N个出现次数最多的数据了。当然,也可以堆实现。

    ok,此题与上题类似,最好的方法是用hash_map统计出现的次数,然后再借用堆找出出现次数最多的N个数据。不过,上一题统计搜索引擎最热门的查询已经采用过hash表统计单词出现的次数,特此,本题咱们改用红黑树取代之前的用hash表,来完成最初的统计,然后用堆更新,找出出现次数最多的前N个数据。

    同时,正好个人此前用c && c++ 语言实现过红黑树,那么,代码能借用就借用吧。
完整代码

  1. //copyright@ zhouzhenren &&July  
  2. //July、updated,2011.05.08.  
  3.   
  4. //题目描述:  
  5. //上千万或上亿数据(有重复),统计其中出现次数最多的前N个数据  
  6.   
  7. //解决方案:  
  8. //1、采用红黑树(本程序中有关红黑树的实现代码来源于@July)来进行统计次数。  
  9. //2、然后遍历整棵树,同时采用最小堆更新前N个出现次数最多的数据。  
  10.   
  11. //声明:版权所有,引用必须注明出处。  
  12. #define PARENT(i) (i)/2  
  13. #define LEFT(i)   2*(i)  
  14. #define RIGHT(i)  2*(i)+1  
  15.   
  16. #include <stdio.h>  
  17. #include <stdlib.h>  
  18. #include <string.h>  
  19.   
  20. typedef enum rb_color{ RED, BLACK }RB_COLOR;  
  21. typedef struct rb_node  
  22. {  
  23.     int key;  
  24.     int data;  
  25.     RB_COLOR color;  
  26.     struct rb_node* left;  
  27.     struct rb_node* right;  
  28.     struct rb_node* parent;  
  29. }RB_NODE;  
  30.   
  31. RB_NODE* RB_CreatNode(int key, int data)  
  32. {  
  33.     RB_NODE* node = (RB_NODE*)malloc(sizeof(RB_NODE));  
  34.     if (NULL == node)  
  35.     {  
  36.         printf("malloc error!");  
  37.         exit(-1);  
  38.     }  
  39.       
  40.     node->key = key;  
  41.     node->data = data;  
  42.     node->color = RED;  
  43.     node->left = NULL;  
  44.     node->right = NULL;  
  45.     node->parent = NULL;  
  46.       
  47.     return node;  
  48. }  
  49.   
  50. /**  
  51. * 左旋   
  52. * 
  53. *  node           right  
  54. *  / /    ==>     / /  
  55. * a  right     node  y  
  56. *     / /       / /      
  57. *     b  y     a   b     
  58. */    
  59. RB_NODE* RB_RotateLeft(RB_NODE* node, RB_NODE* root)  
  60. {    
  61.     RB_NODE* right = node->right;    // 指定指针指向 right<--node->right    
  62.       
  63.     if ((node->right = right->left))      
  64.         right->left->parent = node;  // 好比上面的注释图,node成为b的父母  
  65.       
  66.     right->left = node;   // node成为right的左孩子   
  67.       
  68.     if ((right->parent = node->parent))    
  69.     {    
  70.         if (node == node->parent->right)    
  71.             node->parent->right = right;  
  72.         else    
  73.             node->parent->left = right;  
  74.     }    
  75.     else    
  76.         root = right;    
  77.       
  78.     node->parent = right;  //right成为node的父母    
  79.       
  80.     return root;    
  81. }    
  82.   
  83. /** 
  84. * 右旋   
  85. * 
  86. *      node            left  
  87. *       / /             / /  
  88. *     left y   ==>     a  node  
  89. *     / /                  / /  
  90. *    a   b                b   y   
  91. */    
  92. RB_NODE* RB_RotateRight(RB_NODE* node, RB_NODE* root)    
  93. {    
  94.     RB_NODE* left = node->left;    
  95.       
  96.     if ((node->left = left->right))    
  97.         left->right->parent = node;    
  98.       
  99.     left->right = node;    
  100.       
  101.     if ((left->parent = node->parent))    
  102.     {    
  103.         if (node == node->parent->right)      
  104.             node->parent->right = left;    
  105.         else    
  106.             node->parent->left = left;    
  107.     }    
  108.     else    
  109.         root = left;    
  110.       
  111.     node->parent = left;    
  112.       
  113.     return root;    
  114. }    
  115.   
  116. /**  
  117. * 红黑树的3种插入情况   
  118. * 用z表示当前结点, p[z]表示父母、p[p[z]]表示祖父, y表示叔叔. 
  119. */  
  120. RB_NODE* RB_Insert_Rebalance(RB_NODE* node, RB_NODE* root)    
  121. {    
  122.     RB_NODE *parent, *gparent, *uncle, *tmp;  //父母p[z]、祖父p[p[z]]、叔叔y、临时结点*tmp    
  123.       
  124.     while ((parent = node->parent) && parent->color == RED)    
  125.     { // parent 为node的父母,且当父母的颜色为红时    
  126.         gparent = parent->parent;   // gparent为祖父    
  127.           
  128.         if (parent == gparent->left)  // 当祖父的左孩子即为父母时,其实上述几行语句,无非就是理顺孩子、父母、祖父的关系。  
  129.         {  
  130.             uncle = gparent->right; // 定义叔叔的概念,叔叔y就是父母的右孩子。    
  131.             if (uncle && uncle->color == RED) // 情况1:z的叔叔y是红色的    
  132.             {    
  133.                 uncle->color = BLACK;   // 将叔叔结点y着为黑色    
  134.                 parent->color = BLACK;  // z的父母p[z]也着为黑色。解决z,p[z]都是红色的问题。    
  135.                 gparent->color = RED;      
  136.                 node = gparent;     // 将祖父当做新增结点z,指针z上移俩层,且着为红色。    
  137.                 // 上述情况1中,只考虑了z作为父母的右孩子的情况。    
  138.             }    
  139.             else                     // 情况2:z的叔叔y是黑色的,    
  140.             {       
  141.                 if (parent->right == node)  // 且z为右孩子    
  142.                 {    
  143.                     root = RB_RotateLeft(parent, root); // 左旋[结点z,与父母结点]    
  144.                     tmp = parent;    
  145.                     parent = node;    
  146.                     node = tmp;     // parent与node 互换角色    
  147.                 }    
  148.                 // 情况3:z的叔叔y是黑色的,此时z成为了左孩子。    
  149.                 // 注意,1:情况3是由上述情况2变化而来的。    
  150.                 // ......2:z的叔叔总是黑色的,否则就是情况1了。    
  151.                 parent->color = BLACK;   // z的父母p[z]着为黑色    
  152.                 gparent->color = RED;    // 原祖父结点着为红色    
  153.                 root = RB_RotateRight(gparent, root); // 右旋[结点z,与祖父结点]    
  154.             }    
  155.         }     
  156.           
  157.         else     
  158.         {         
  159.             // 这部分是特别为情况1中,z作为左孩子情况,而写的。    
  160.             uncle = gparent->left;  // 祖父的左孩子作为叔叔结点。[原理还是与上部分一样的]    
  161.             if (uncle && uncle->color == RED)  // 情况1:z的叔叔y是红色的    
  162.             {    
  163.                 uncle->color = BLACK;    
  164.                 parent->color = BLACK;    
  165.                 gparent->color = RED;    
  166.                 node = gparent;           // 同上  
  167.             }    
  168.             else                               // 情况2:z的叔叔y是黑色的,    
  169.             {    
  170.                 if (parent->left == node)  // 且z为左孩子    
  171.                 {    
  172.                     root = RB_RotateRight(parent, root);  // 以结点parent、root右旋    
  173.                     tmp = parent;    
  174.                     parent = node;    
  175.                     node = tmp;       // parent与node 互换角色    
  176.                 }     
  177.                 // 经过情况2的变化,成为了情况3.    
  178.                 parent->color = BLACK;    
  179.                 gparent->color = RED;    
  180.                 root = RB_RotateLeft(gparent, root);   // 以结点gparent和root左旋    
  181.             }    
  182.         }    
  183.     }    
  184.       
  185.     root->color = BLACK; // 根结点,不论怎样,都得置为黑色。    
  186.     return root;      // 返回根结点。    
  187. }  
  188.   
  189. /**  
  190. * 红黑树查找结点   
  191. * rb_search_auxiliary:查找   
  192. * rb_node_t* rb_search:返回找到的结点   
  193. */  
  194. RB_NODE* RB_SearchAuxiliary(int key, RB_NODE* root, RB_NODE** save)    
  195. {    
  196.     RB_NODE* node = root;  
  197.     RB_NODE* parent = NULL;    
  198.     int ret;    
  199.       
  200.     while (node)    
  201.     {    
  202.         parent = node;    
  203.         ret = node->key - key;    
  204.         if (0 < ret)    
  205.             node = node->left;    
  206.         else if (0 > ret)    
  207.             node = node->right;    
  208.         else    
  209.             return node;    
  210.     }    
  211.       
  212.     if (save)    
  213.         *save = parent;    
  214.       
  215.     return NULL;    
  216. }    
  217.   
  218. /**  
  219. * 返回上述rb_search_auxiliary查找结果   
  220. */  
  221. RB_NODE* RB_Search(int key, RB_NODE* root)    
  222. {    
  223.     return RB_SearchAuxiliary(key, root, NULL);    
  224. }    
  225.   
  226. /**  
  227. * 红黑树的插入   
  228. */  
  229. RB_NODE* RB_Insert(int key, int data, RB_NODE* root)    
  230. {    
  231.     RB_NODE* parent = NULL;  
  232.     RB_NODE* node = NULL;    
  233.       
  234.     parent = NULL;    
  235.     if ((node = RB_SearchAuxiliary(key, root, &parent)))  // 调用RB_SearchAuxiliary找到插入结点的地方    
  236.     {    
  237.         node->data++; // 节点已经存在data值加1  
  238.         return root;    
  239.     }    
  240.       
  241.     node = RB_CreatNode(key, data);  // 分配结点    
  242.     node->parent = parent;        
  243.       
  244.     if (parent)    
  245.     {    
  246.         if (parent->key > key)    
  247.             parent->left = node;    
  248.         else    
  249.             parent->right = node;    
  250.     }    
  251.     else    
  252.     {    
  253.         root = node;    
  254.     }    
  255.       
  256.     return RB_Insert_Rebalance(node, root);   // 插入结点后,调用RB_Insert_Rebalance修复红黑树的性质    
  257. }  
  258.   
  259. typedef struct rb_heap  
  260. {  
  261.     int key;  
  262.     int data;  
  263. }RB_HEAP;  
  264. const int heapSize = 10;  
  265. RB_HEAP heap[heapSize+1];  
  266.   
  267. /**  
  268. * MAX_HEAPIFY函数对堆进行更新,使以i为根的子树成最大堆 
  269. */  
  270. void MIN_HEAPIFY(RB_HEAP* A, const int& size, int i)  
  271. {  
  272.     int l = LEFT(i);  
  273.     int r = RIGHT(i);  
  274.     int smallest = i;  
  275.       
  276.     if (l <= size && A[l].data < A[i].data)  
  277.         smallest = l;  
  278.     if (r <= size && A[r].data < A[smallest].data)  
  279.         smallest = r;  
  280.       
  281.     if (smallest != i)  
  282.     {  
  283.         RB_HEAP tmp = A[i];  
  284.         A[i] = A[smallest];  
  285.         A[smallest] = tmp;  
  286.         MIN_HEAPIFY(A, size, smallest);  
  287.     }  
  288. }  
  289.   
  290. /**  
  291. * BUILD_MINHEAP函数对数组A中的数据建立最小堆 
  292. */  
  293. void BUILD_MINHEAP(RB_HEAP* A, const int& size)  
  294. {  
  295.     for (int i = size/2; i >= 1; --i)  
  296.         MIN_HEAPIFY(A, size, i);  
  297. }  
  298.   
  299.   
  300. /* 
  301. 3、维护k个元素的最小堆,原理与上述第2个方案一致, 
  302. 即用容量为k的最小堆存储最先在红黑树中遍历到的k个数,并假设它们即是最大的k个数,建堆费时O(k), 
  303. 然后调整堆(费时O(logk))后,有k1>k2>...kmin(kmin设为小顶堆中最小元素)。 
  304. 继续中序遍历红黑树,每次遍历一个元素x,与堆顶元素比较,若x>kmin,则更新堆(用时logk),否则不更新堆。 
  305. 这样下来,总费时O(k*logk+(n-k)*logk)=O(n*logk)。 
  306. 此方法得益于在堆中,查找等各项操作时间复杂度均为logk)。 
  307. */  
  308.   
  309. //中序遍历RBTree  
  310. void InOrderTraverse(RB_NODE* node)    
  311. {  
  312.     if (node == NULL)    
  313.     {    
  314.         return;    
  315.     }    
  316.     else    
  317.     {    
  318.         InOrderTraverse(node->left);    
  319.         if (node->data > heap[1].data) // 当前节点data大于最小堆的最小元素时,更新堆数据  
  320.         {  
  321.             heap[1].data = node->data;  
  322.             heap[1].key = node->key;  
  323.             MIN_HEAPIFY(heap, heapSize, 1);  
  324.         }  
  325.         InOrderTraverse(node->right);    
  326.     }  
  327. }   
  328.   
  329. void RB_Destroy(RB_NODE* node)  
  330. {  
  331.     if (NULL == node)  
  332.     {  
  333.         return;  
  334.     }  
  335.     else  
  336.     {  
  337.         RB_Destroy(node->left);  
  338.         RB_Destroy(node->right);  
  339.         free(node);  
  340.         node = NULL;  
  341.     }  
  342. }  
  343.   
  344. int main()  
  345. {  
  346.     RB_NODE* root = NULL;  
  347.     RB_NODE* node = NULL;    
  348.       
  349.     // 初始化最小堆  
  350.     for (int i = 1; i <= 10; ++i)  
  351.     {  
  352.         heap[i].key = i;  
  353.         heap[i].data = -i;  
  354.     }  
  355.     BUILD_MINHEAP(heap, heapSize);  
  356.       
  357.     FILE* fp = fopen("data.txt""r");  
  358.     int num;  
  359.     while (!feof(fp))  
  360.     {  
  361.         fscanf(fp, "%d", &num);  
  362.         root = RB_Insert(num, 1, root);  
  363.     }  
  364.     fclose(fp);  
  365.       
  366.     InOrderTraverse(root);   //递归遍历红黑树  
  367.     RB_Destroy(root);  
  368.       
  369.     for (i = 1; i <= 10; ++i)  
  370.     {  
  371.         printf("%d/t%d/n", heap[i].key, heap[i].data);  
  372.     }     
  373.     return 0;  
  374. }   

程序测试:咱们来对下面这个小文件进行测试:

运行结果:如下图所示,

 

问题补遗:

    ok,由于在遍历红黑树采用的是递归方式比较耗内存,下面给出一个非递归遍历的程序(下述代码若要运行,需贴到上述程序之后,因为其它的代码未变,只是在遍历红黑树的时候,采取非递归遍历而已,同时,主函数的编写也要稍微修改下):

  1. //copyright@ zhouzhenren  
  2. //July、updated,2011.05.08.  
  3. #define STACK_SIZE 1000  
  4. typedef struct  
  5. {                                              // 栈的结点定义  
  6.     RB_NODE** top;  
  7.     RB_NODE** base;  
  8. }*PStack, Stack;  
  9.   
  10. bool InitStack(PStack& st)                       // 初始化栈  
  11. {  
  12.     st->base = (RB_NODE**)malloc(sizeof(RB_NODE*) * STACK_SIZE);  
  13.     if (!st->base)  
  14.     {  
  15.         printf("InitStack error!");  
  16.         exit(1);  
  17.     }  
  18.     st->top = st->base;  
  19.     return true;  
  20. }  
  21.   
  22. bool Push(PStack& st, RB_NODE*& e)                    // 入栈  
  23. {  
  24.     if (st->top - st->base >= STACK_SIZE)  
  25.         return false;  
  26.     *st->top = e;  
  27.     st->top++;  
  28.     return true;  
  29. }  
  30.   
  31. bool Pop(PStack& st, RB_NODE*& e)                     // 出栈  
  32. {  
  33.     if (st->top == st->base)  
  34.     {  
  35.         e = NULL;  
  36.         return false;  
  37.     }  
  38.     e = *--st->top;  
  39.     return true;  
  40. }  
  41.   
  42. bool StackEmpty(PStack& st)                     // 栈是否为空  
  43. {  
  44.     if (st->base == st->top)  
  45.         return true;  
  46.     else  
  47.         return false;  
  48. }  
  49.   
  50. bool InOrderTraverse_Stack(RB_NODE*& T)                 // 中序遍历  
  51. {  
  52.     PStack S = (PStack)malloc(sizeof(Stack));  
  53.     RB_NODE* P = T;  
  54.     InitStack(S);  
  55.     while (P != NULL || !StackEmpty(S))  
  56.     {  
  57.         if (P != NULL)  
  58.         {  
  59.             Push(S, P);  
  60.             P = P->left;  
  61.         }  
  62.         else  
  63.         {  
  64.             Pop(S, P);  
  65.             if (P->data > heap[1].data) // 当前节点data大于最小堆的最小元素时,更新堆数据  
  66.             {  
  67.                 heap[1].data = P->data;  
  68.                 heap[1].key = P->key;  
  69.                 MIN_HEAPIFY(heap, heapSize, 1);  
  70.             }  
  71.             P = P->right;  
  72.         }  
  73.     }  
  74.     free(S->base);  
  75.     S->base = NULL;  
  76.     free(S);  
  77.     S = NULL;  
  78.       
  79.     return true;  
  80. }  
  81.   
  82. bool PostOrderTraverse_Stack(RB_NODE*& T)               //后序遍历  
  83. {  
  84.     PStack S = (PStack)malloc(sizeof(Stack));  
  85.     RB_NODE* P = T;  
  86.     RB_NODE* Pre = NULL;  
  87.     InitStack(S);  
  88.     while (P != NULL || !StackEmpty(S))  
  89.     {  
  90.         if (P != NULL) // 非空直接入栈  
  91.         {  
  92.             Push(S, P);  
  93.             P = P->left;  
  94.         }  
  95.         else  
  96.         {  
  97.             Pop(S, P); // 弹出栈顶元素赋值给P  
  98.             if (P->right == NULL || P->right == Pre) // P的右子树空或是右子树是刚访问过的  
  99.             { // 节点,则释放当前节点内存  
  100.                 free(P);  
  101.                 Pre = P;  
  102.                 P = NULL;  
  103.             }  
  104.             else // 反之,当前节点重新入栈,接着判断右子树  
  105.             {  
  106.                 Push(S, P);  
  107.                 P = P->right;  
  108.             }  
  109.         }  
  110.     }  
  111.     free(S->base);  
  112.     S->base = NULL;  
  113.     free(S);  
  114.     S = NULL;  
  115.       
  116.     return true;  
  117. }  
  118.   
  119. //主函数稍微修改如下:  
  120. int main()  
  121. {  
  122.     RB_NODE* root = NULL;  
  123.     RB_NODE* node = NULL;    
  124.       
  125.     // 初始化最小堆  
  126.     for (int i = 1; i <= 10; ++i)  
  127.     {  
  128.         heap[i].key = i;  
  129.         heap[i].data = -i;  
  130.     }  
  131.     BUILD_MINHEAP(heap, heapSize);  
  132.       
  133.     FILE* fp = fopen("data.txt""r");  
  134.     int num;  
  135.     while (!feof(fp))  
  136.     {  
  137.         fscanf(fp, "%d", &num);  
  138.         root = RB_Insert(num, 1, root);  
  139.     }  
  140.     fclose(fp);  
  141.       
  142.       //若上面的程序后面加上了上述的非递归遍历红黑树的代码,那么以下几行代码,就得修改如下:  
  143.     //InOrderTraverse(root); //此句去掉(递归遍历树)  
  144.     InOrderTraverse_Stack(root); // 非递归遍历树  
  145.       
  146.     //RB_Destroy(root); //此句去掉(通过递归释放内存)  
  147.     PostOrderTraverse_Stack(root); // 非递归释放内存  
  148.       
  149.     for (i = 1; i <= 10; ++i)  
  150.     {  
  151.         printf("%d/t%d/n", heap[i].key, heap[i].data);  
  152.     }     
  153.     return 0;  
  154. }   

updated:

 后来,我们狂想曲创作组中的3又用hash+堆实现了上题,很明显比采用上面的红黑树,整个实现简洁了不少,其完整源码如下:

完整源码:

  1. //Author: zhouzhenren  
  2. //Description: 上千万或上亿数据(有重复),统计其中出现次数最多的钱N个数据  
  3.   
  4. //Algorithm: 采用hash_map来进行统计次数+堆(找出Top K)。  
  5. //July,2011.05.12。纪念汶川地震三周年,默哀三秒。  
  6.   
  7. #define PARENT(i) (i)/2  
  8. #define LEFT(i)   2*(i)  
  9. #define RIGHT(i)  2*(i)+1  
  10.   
  11. #define HASHTABLESIZE 2807303  
  12. #define HEAPSIZE 10  
  13. #define A 0.6180339887  
  14. #define M 16384     //m=2^14  
  15.   
  16. #include <stdio.h>  
  17. #include <stdlib.h>  
  18.   
  19. typedef struct hash_node  
  20. {  
  21.     int data;  
  22.     int count;  
  23.     struct hash_node* next;  
  24. }HASH_NODE;  
  25. HASH_NODE* hash_table[HASHTABLESIZE];  
  26.   
  27. HASH_NODE* creat_node(int& data)  
  28. {  
  29.     HASH_NODE* node = (HASH_NODE*)malloc(sizeof(HASH_NODE));  
  30.       
  31.     if (NULL == node)  
  32.     {  
  33.         printf("malloc node failed!/n");  
  34.         exit(EXIT_FAILURE);  
  35.     }  
  36.       
  37.     node->data = data;  
  38.     node->count = 1;  
  39.     node->next = NULL;  
  40.     return node;  
  41. }  
  42.   
  43. /**  
  44. * hash函数采用乘法散列法 
  45. * h(k)=int(m*(A*k mod 1)) 
  46. */  
  47. int hash_function(int& key)    
  48. {    
  49.     double result = A * key;  
  50.     return (int)(M * (result - (int)result));    
  51. }  
  52.   
  53. void insert(int& data)  
  54. {  
  55.     int index = hash_function(data);  
  56.     HASH_NODE* pnode = hash_table[index];  
  57.     while (NULL != pnode)  
  58.     {   // 以存在data,则count++  
  59.         if (pnode->data == data)  
  60.         {  
  61.             pnode->count += 1;  
  62.             return;  
  63.         }  
  64.         pnode = pnode->next;  
  65.     }  
  66.       
  67.     // 建立一个新的节点,在表头插入  
  68.     pnode = creat_node(data);  
  69.     pnode->next = hash_table[index];  
  70.     hash_table[index] = pnode;  
  71. }  
  72.   
  73. /**  
  74. * destroy_node释放创建节点产生的所有内存 
  75. */  
  76. void destroy_node()  
  77. {  
  78.     HASH_NODE* p = NULL;  
  79.     HASH_NODE* tmp = NULL;  
  80.     for (int i = 0; i < HASHTABLESIZE; ++i)  
  81.     {  
  82.         p = hash_table[i];  
  83.         while (NULL != p)  
  84.         {  
  85.             tmp = p;  
  86.             p = p->next;  
  87.             free(tmp);  
  88.             tmp = NULL;  
  89.         }  
  90.     }  
  91. }  
  92.   
  93. typedef struct min_heap  
  94. {  
  95.     int count;  
  96.     int data;  
  97. }MIN_HEAP;  
  98. MIN_HEAP heap[HEAPSIZE + 1];  
  99.   
  100. /**  
  101. * min_heapify函数对堆进行更新,使以i为跟的子树成最大堆 
  102. */  
  103. void min_heapify(MIN_HEAP* H, const int& size, int i)  
  104. {  
  105.     int l = LEFT(i);  
  106.     int r = RIGHT(i);  
  107.     int smallest = i;  
  108.       
  109.     if (l <= size && H[l].count < H[i].count)  
  110.         smallest = l;  
  111.     if (r <= size && H[r].count < H[smallest].count)  
  112.         smallest = r;  
  113.       
  114.     if (smallest != i)  
  115.     {  
  116.         MIN_HEAP tmp = H[i];  
  117.         H[i] = H[smallest];  
  118.         H[smallest] = tmp;  
  119.         min_heapify(H, size, smallest);  
  120.     }  
  121. }  
  122.   
  123. /**  
  124. * build_min_heap函数对数组A中的数据建立最小堆 
  125. */  
  126. void build_min_heap(MIN_HEAP* H, const int& size)  
  127. {  
  128.     for (int i = size/2; i >= 1; --i)  
  129.         min_heapify(H, size, i);  
  130. }  
  131.   
  132. /**  
  133. * traverse_hashtale函数遍历整个hashtable,更新最小堆 
  134. */  
  135. void traverse_hashtale()  
  136. {  
  137.     HASH_NODE* p = NULL;  
  138.     for (int i = 0; i < HASHTABLESIZE; ++i)  
  139.     {  
  140.         p = hash_table[i];  
  141.         while (NULL != p)  
  142.         {   // 如果当前节点的数量大于最小堆的最小值,则更新堆  
  143.             if (p->count > heap[1].count)  
  144.             {  
  145.                 heap[1].count = p->count;  
  146.                 heap[1].data = p->data;  
  147.                 min_heapify(heap, HEAPSIZE, 1);  
  148.             }  
  149.             p = p->next;  
  150.         }  
  151.     }  
  152. }  
  153.   
  154. int main()  
  155. {  
  156.     // 初始化最小堆  
  157.     for (int i = 1; i <= 10; ++i)  
  158.     {  
  159.         heap[i].count = -i;  
  160.         heap[i].data = i;  
  161.     }  
  162.     build_min_heap(heap, HEAPSIZE);  
  163.       
  164.     FILE* fp = fopen("data.txt""r");  
  165.     int num;  
  166.     while (!feof(fp))  
  167.     {  
  168.         fscanf(fp, "%d", &num);  
  169.         insert(num);  
  170.     }  
  171.     fclose(fp);  
  172.       
  173.     traverse_hashtale();  
  174.       
  175.     for (i = 1; i <= 10; ++i)  
  176.     {  
  177.         printf("%d/t%d/n", heap[i].data, heap[i].count);  
  178.     }  
  179.       
  180.     return 0;  
  181. }   

原创粉丝点击