2013.5.12搜狐实习生笔试题(编码题部分)


1.利用堆排序对数组进行排序。

 堆结构是把数组看成完全二叉树,除最后一层,每一层都是满的。堆分最大堆和最小堆,其中最大堆是指每一个子树中,根要比其两个孩子的值大,最小堆反之;数组元素升序需要用最大堆,降序用最小堆;这里使用最大堆。

实现堆排序需要三个主要函数:建立最大堆,维持最大堆性质,和堆排序函数。

建立最大堆(BuildMaxHeap):自底向上地维持最大堆性质,heapsize/2为最底下一层的父结点,即需要从结点下标为heapsize/2 ~ 0的结点调用维持最大堆性质的函数(MaxHeapify)。

维持最大堆性质(MaxHeapify):将堆中某个元素调整到合适的位置(下沉);使之满足最大堆性质。

堆排序函数(HeapSort):将堆顶(该堆的最大值)和堆底交换,并将heapsize减1,再调用函数使目前的堆维持最大堆性质。

 

 code:

 1 void Swap(int *A, int i, int j)
 2 {
 3     int tmp = A[i];
 4     A[i] = A[j];
 5     A[j] = tmp;
 6 }
 7 //维持最大堆性质
 8 void MaxHeapify(int *A, int i, int heapsize)
 9 {
10     //递归版本
11     //int nLeft = 2 * i + 1;
12     //int nRight = 2 * i + 2;
13     //int nLargrIndex;
14     //if (A[nLeft] < A[nRight])
15     //{
16     //    nLargrIndex = nRight;
17     //}
18     //else
19     //{
20     //    nLargrIndex = nLeft;
21     //}
22     //if (A[i] < A[nLargrIndex])
23     //{
24     //    //swap(A, i , nLargeIndex)
25     //    Swap(A, i, nLargrIndex);
26     //    MaxHeapify(A, nLargrIndex, heapsize);
27     //}
28     //非递归版本
29     int child; int tmp;
30     for (tmp = A[i]; heapsize > 2 * i + 1; i = child)
31     {
32         child = 2 * i + 1;
33         //记录孩子中较大者下标
34         if (child != heapsize - 1 && A[child + 1] > A[child])
35         {
36             child++;
37         }
38         //若当前的父亲比孩子小,则交换
39         if (tmp < A[child])
40         {
41             A[i] = A[child];
42         }
43         else
44             break;
45     }
46     A[i] = tmp;//把原父节点放到合适的位置上
47 }
48 
49 void BuildMaxHeap(int *A, int heapsize)
50 {
51     //从堆底的父节点开始向上建立堆,就是让每一个子堆具有最大堆性质,自底向上的
52     for(int i = heapsize / 2; i >= 0; i--)
53     {
54         MaxHeapify(A, i, heapsize);
55     }
56 }
57 
58 void HeapSort(int *A, int heapsize)
59 {
60     BuildMaxHeap(A, heapsize);
61     for (int i = heapsize - 1; i > 0; i--)
62     {
63         //交换堆顶和堆最后一个元素,堆个数减1
64         Swap(A, 0, i);
65         heapsize--;
66         //保持最大堆性质
67         MaxHeapify(A, 0, heapsize);
68     }
69 
70 }

 


2.已知rand7()生成1~7的随机数,写出rand10()。

 思想:利用进制的方法生成进制位上的元素,选择输出指定的范围。ps:直接扩充的方法产生的每个数概率不相等,中间的数概率会高些。

code:

 1 //产生范围1~10
 2 int rand10()
 3 {
 4     int result;
 5     while (1)
 6     {    //利用7进制产生result,其范围是0-48
 7         result = 7 * (rand7() - 1) + rand7() - 1;
 8         //若范围在1~10,则break并返回
 9         if (result > 0 && result < 11)
10         {
11             break;
12         }
13     }
14     return result;
15      
16 }

 

3.设计算法,实现一个对数组左移k个元素的函数,要求时间复杂度为O(n)。

此题在Programming Pearls Column2有相应介绍。主要思想是利用等式(arbr)r = ba,r表示reverse,例如序列{1,2,3,4,5,6,7},现在数组左移3位得到的结果为{4,5,6,7,1,2,3};利用前面介绍的等式,把原序列中的前3位,和剩下一部分分别反转,于是得到{3,2,1,7,6,5,4},再整体反转一次得到{4,5,6,7,1,2,3}即为最终结果。反转的时间复杂度为O(n),故满足题意,而且不需要额外的内存空间。

code: 

 1 //对数组A 指定范围反转元素
 2 template <class T>
 3 void Reverse(T *A, int nStart, int nEnd)
 4 {
 5     int i;
 6     for (i = nStart; i < nStart + (1 + nEnd - nStart) / 2; ++i)
 7     {
 8         T tmp = A[i];
 9         A[i] = A[nEnd + nStart - i];
10         A[nEnd + nStart - i] = tmp;
11     }
12 }
13 template <class T>
14 void LeftMoveKthElements(T *A, int k, int n)
15 {
16     //@Param n: Number of elements in array A
17     //@Param k: left move k elements
18     Reverse(A, 0, k - 1);
19     Reverse(A, k, n - 1);
20     Reverse(A, 0, n - 1);
21 }


实例:

 

 


4.用最快的算法打印1~n的素数。

 思路:用筛选法和位运算。利用一个unsigned int的位数可代表32个数,于是n个元素只需要1+ n/32个unsigned int就够了。

筛选法:遍历2~sqrt(n),把2~sqrt(n)的倍数 对应的位设为0(异或操作^)。 输出时把2~n对应位数非0的数输出即可。

 

 1 void printPrime(unsigned int n)
 2 {
 3     int nSize = (int)sqrt((double)n);
 4     //申请空间n个元素所需要的空间(按bit算)
 5     unsigned int *nArray = (unsigned int*)malloc((1 + n / 32) * sizeof(unsigned int));
 6     if (nArray == NULL)
 7     {
 8         throw ("malloc failed!");
 9     }
10     for (int i = 0; i < 1 + n / 32; ++i)
11     {
12         nArray[i] = 0xFFFFFFFF;//initialization
13     }
14     for (int i = 2; i < nSize; ++i)
15     {
16         for (int j = 2 * i; j <= n; j += i)
17         {
18             //判断某位是否为0,非零则设为0,注意下面的判断语句的值不一定是1,而是某位上的1对应的数
19             if ( (nArray[j >> 5] & (1 << (j % 32))) != 0 )
20             {
21                 nArray[j >> 5] ^= 1 << (j % 32);
22             }
23         }
24     }
25     int j = 0;
26     for (int i = 2; i <= n; ++i)
27     {
28         //判断某位是否为0,非零则是素数,输出
29         if ( (nArray[i >> 5] & (1 << (i % 32)) ) != 0 )
30         {
31             printf("%d ",i);
32             ++j;
33             if (j % 10 == 0)
34             {
35                 printf("\n");
36             }
37         }
38         
39     }
40     free(nArray);
41     nArray = NULL;
42 }

 

下面是打印1~1000的素数

posted @ 2013-05-12 23:07  hust_枫  阅读(364)  评论(0编辑  收藏  举报