网易商业智能研究员笔试——算法题

1. 二叉树的中序遍历非递归实现

  1. void InOrderTraverse1(BiTree T)   // 中序遍历的非递归
  2. {      
  3.     if(!T)      
  4.         return ;      
  5.     BiTree curr = T;    // 指向当前要检查的节点      
  6.     stack<BiTree> s;    
  7.     while(curr != NULL || !s.empty())    
  8.     {   
  9.         while(curr != NULL) 
  10.         {    
  11.             s.push(curr);    
  12.             curr = curr->lchild;    
  13.         }  
  14.         if(!s.empty())    //当节点没有左儿子时,开始输出当前节点,同时将当前即当前节点更新为右儿子  
  15.         {    
  16.             curr = s.top();    
  17.             s.pop();    
  18.             cout<<curr->data<<”  “;    
  19.             curr = curr->rchild;    
  20.         }    
  21.     }    
  22. }   

顺便补充下前序和后序遍历:

  1. void PreOrder_Nonrecursive(BiTree T)     //先序遍历的非递归        
  2. {      
  3.     if(!T)        
  4.         return ;        
  5.     stack<BiTree> s;      
  6.     s.push(T);      
  7.     while(!s.empty())      
  8.     {      
  9.         BiTree temp = s.top();      
  10.         cout<<temp->data<<” “;      
  11.         s.pop();      
  12.         if(temp->rchild)    //右儿子先进栈  
  13.             s.push(temp->rchild);      
  14.         if(temp->lchild)      
  15.             s.push(temp->lchild);      
  16.     }        
  1. //双栈法(后序是左——右——根,利用栈反下就是根——右——左,和前序遍历相似)  
  2. void PostOrder_Nonrecursive(BiTree T)  // 后序遍历的非递归           
  3. {        
  4.     stack<BiTree> s1 , s2;        
  5.     BiTree curr ;           // 指向当前要检查的节点      
  6.     s1.push(T);      
  7.     while(!s1.empty())  // 栈空时结束        
  8.     {      
  9.         curr = s1.top();      
  10.         s1.pop();      
  11.         s2.push(curr);      
  12.         if(curr->lchild)    //由于s2负责输出,所以先左儿子进栈  
  13.             s1.push(curr->lchild);      
  14.         if(curr->rchild)      
  15.             s1.push(curr->rchild);      
  16.     }      
  17.     while(!s2.empty())      
  18.     {      
  19.         printf(“%c “, s2.top()->data);      
  20.         s2.pop();      
  21.     }      
  22. }    

2. 输入N,输出是1~N的全排列,非递归实现

基本思想是:
       1.对初始队列进行排序,找到所有排列中最小的一个排列Pmin(1,2,3, … ,N)。
       2.找到刚刚好比Pmin大比其它都小的排列P(min+1)。
       3.循环执行第二步,直到找到一个最大的排列,算法结束。
        如排列123456,这是所有排列中最小的一个排列,刚好比ABCDE大的排列是:123465。
算法如下:
        给定已知序列P =  (A1,A2,A3,…..,An)
        对P按字典排序,得到P的一个最小排列Pmin = A1A2A3….An ,满足Ai > A(i-1) (1 < i <= n)
        从Pmin开始,找到刚好比Pmin大的一个排列P(min+1),再找到刚好比P(min+1)大的一个排列,如此重复。具体方法如下:
        1.从后向前(即从An->A1),找到第一对为升序的相邻元素,即Ai < A(i+1)。若找不到这样的Ai,说明已经找到最后一个全排列,可以返回了。
        2.从后向前,找到第一个比Ai大的数Aj,交换Ai和Aj。
        3.将排列中A(i+1)A(i+2)….An这个序列的数逆序倒置,即An…..A(i+2)A(i+1)。因为由前面第1、2可以得知,A(i+1)>=A(i+2)>=…..>=An,这为一个升序序列,应将该序列逆序倒置,所得到的新排列才刚刚好比上个排列大。
        4.重复步骤1-3,直到返回。

举例如下:

        当序列为162543,找到第一对逆序数为<2,5>,Ai=2;而第一个大于2的数为Aj=3,两者交换后序列为163542;将<542>倒置,序列为163245,刚好大于原序列。

  1. //将数组a中的下标i到下标j之间的所有元素逆序倒置  
  2. void reverse(int a[],int i,int j)  
  3. {  
  4.     for(; i<j; ++i,–j) {  
  5.         swap(a,i,j);  
  6.     }  

  7. //将数组中所以元素按序输出   
  8. void print(int a[],int length)
  9. {  
  10.     for(int i=0; i<length; ++i)  
  11.         cout<<a[i]<<” “;  
  12.     cout<<endl;  
  13. }  
  14.   
  15. //求取全排列,打印结果,可令a[]为[1,2,3,…,N],length=N  
  16. void combination(int a[],int length)  
  17. {  
  18.     if(length<2) return;  
  19.   
  20.     bool end=false;  
  21.     while(true) {  
  22.         print(a,length); //输出数组a
  23.         int i,j;  
  24.         
  25.         for(i=length-2; i>=0; –i) {  //找到不符合趋势的元素的下标i,即首次满足Ai<Ai+1 
  26.             if(a[i]<a[i+1]) break;  
  27.             else if(i==0) return;  //找到最大的排列 
  28.         }  
  29.         for(j=length-1; j>i; –j) {   //从后到前找到第一个满足Aj>Ai
  30.             if(a[j]>a[i]) break;  
  31.         }  
  32.         swap(a,i,j);  //交换Ai和Aj
  33.         reverse(a,i+1,length-1);  //转置Ai+1,…,An
  34.     }  
  35. }  

补充下全排列的递归解法:

        (A、B、C、D)的全排列为:(1)A后面跟(B、C、D)的全排列;(2)B后面跟(A、C、D)的全排列;(3)C后面跟(A、B、D)的全排列;(4)D后面跟(A、B、C)的全排列。

  1. template<typename T>  
  2. void permutation(T array[], int begin, int end)  
  3. {  
  4.     int i;  
  5.     if(begin == end){  
  6.         for(i = 0; i <= end; ++i){  
  7.             cout<<array[i]<<” “;  
  8.         }  
  9.         cout<<endl;  
  10.         return;  
  11.     } else {  
  12.         //for循环遍历该排列中第一个位置的所有可能情况  
  13.         for(i = begin; i <= end; ++i) {  
  14.             swap(array[i], array[begin]);  
  15.             permutation(array, begin + 1, end);  
  16.             swap(array[i], array[begin]);  
  17.         }  
  18.     }  
  19. }  
点赞