微软面试题 5

题:两个链表,一升一降。合并为一个升序链表。

分析假设升序的链表为链表1,降序的链表为链表2,p1,p2分别作为它们的迭代器,还有一个合并链表用于存放合并后的数据

法一、最容易想到的且容易实现的就是使两个表都变成升序,然后就是经典的合并排序算法的步骤了,步骤是构建p1,p2两个迭代器,分别用于迭代两个链表,每次遍历,若p1所指的节点数据大于p2所指的节点数据则将p1所指的节点数据插入到要合并链表中去且使p1指向下一个节点,否则将p2将所指的节点数据插入到合并链表中去且使p2指向下一个节点,直到p1和p2任意一个指向了NULL为止。最后可能两个链表中尚有剩余的节点,将其逐个插入到合并链表中去即可。

法二、使用递归方法后序遍历降序链表2,遍历顺序就相当于升序的顺序了。在递归遍历链表2的过程中,需要处理有以下三件事:(注意顺序)

(1) 如果p2的数据小于p1的就插入到合并链表中
(2) 如果p2的数据大于p1,那么就对链表1循环遍历,每次将p1中的数据插到合并链表中,直到p2不大于p1,且p1不为空

(3) 如果p1为空,就直接将p2插入到合并链表中

(这个方法你想到了没!)

完整实现代码:
  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.youkuaiyun.com/zhanxinhang 
  4. **/  
  5.    
  6. #include <stdio.h>  
  7. #include <malloc.h>  
  8. #include <stdlib.h>   
  9.   
  10. typedef struct list_node  
  11. {  
  12.   int data;  
  13.   struct list_node * next;  
  14. }list_node;  
  15.    
  16. list_node *list1=NULL; //链表头结点  
  17. list_node *list2=NULL; //链表头结点  
  18.   
  19. void list_print(const list_node *p)//打印该链表函数  
  20. {  
  21.   if(p==NULL)return;  
  22.   while(p!=NULL)     
  23.     {  
  24.       printf("%d ",p->data);  
  25.       p=p->next;  
  26.     }  
  27.   printf("\n");  
  28. }  
  29.   
  30. void list_create(list_node* &head, int data[], int N)  
  31. {  
  32.   if(data == NULL) return;  
  33.   
  34.   int i;  
  35.   list_node *p;  
  36.   p = (list_node*)malloc(sizeof(list_node));  
  37.   p->data = data[0];  
  38.   p->next = NULL;  
  39.   head = p;   
  40.   for(i=1;i<N; i++)   
  41.     {  
  42.       p->next = (list_node*)malloc(sizeof(list_node));  
  43.       p->next->data = data[i];  
  44.       p->next->next = NULL;  
  45.       p=p->next;  
  46.     }  
  47. }  
  48.   
  49. void list_reverse(list_node* &head)  //使链表反序  
  50. {  
  51.   if(head == NULL) return ;//如果head1为空,则返回  
  52.   list_node *p,*q;  
  53.   q=head;  
  54.   p=head->next;  
  55.    
  56.   while(p!=NULL)  
  57.     {  
  58.     head->next=p->next; //将头指针的next指向p的下一个节点  
  59.     p->next=q;          //将p的next值反指向它的前一个节点q  
  60.     q=p;                //q移向p的位置  
  61.     p=head->next;       //p移向它的下一个位置  
  62.     }  
  63.   
  64.     head = q;  
  65. }  
  66.   
  67. void list_destroy(list_node *head)  //销毁函数  
  68. {  
  69.   list_node *pmove=NULL,*pdel=NULL;  
  70.   pmove=head;  
  71.    
  72.  while(pmove!=head)  
  73.    {  
  74.      pdel=pmove;  
  75.      free(pdel);    
  76.      pmove=pmove->next;  
  77.    }  
  78. }  
  79.   
  80. list_node* merge_two_list() //合并链表1和链表2(法一)  
  81. {  
  82.     list_reverse(list2);    //反转链表使之与链表一样升序排列  
  83.     list_node *list_merged;  //和并后的链表  
  84.     list_node *p1,*p2,*p0;        
  85.     list_merged = (list_node*)malloc(sizeof(list_node));  
  86.     list_merged->data = 0;  
  87.     list_merged->next = NULL;  
  88.     p0 = list_merged;  
  89.   
  90.     p1=list1;  
  91.     p2=list2;  
  92.     while(p1!=NULL && p2!=NULL)  
  93.     {  
  94.         if(p1->data < p2->data)  
  95.         {  
  96.             p0->next=(list_node*)malloc(sizeof(list_node));  
  97.             p0->next->data=p1->data;  
  98.             p0->next->next=NULL;  
  99.             p0=p0->next;  
  100.             p1=p1->next;  
  101.         }  
  102.         else  
  103.         {  
  104.             p0->next=(list_node*)malloc(sizeof(list_node));  
  105.             p0->next->data=p2->data;  
  106.             p0->next->next=NULL;  
  107.             p0=p0->next;  
  108.             p2=p2->next;  
  109.         }  
  110.     }  
  111.     while(p1!=NULL)  
  112.     {  
  113.             p0->next=(list_node*)malloc(sizeof(list_node));  
  114.             p0->next->data=p1->data;  
  115.             p0->next->next=NULL;  
  116.             p0=p0->next;  
  117.             p1=p1->next;  
  118.     }  
  119.     while(p2!=NULL)  
  120.     {  
  121.             p0->next=(list_node*)malloc(sizeof(list_node));  
  122.             p0->next->data=p2->data;  
  123.             p0->next->next=NULL;  
  124.             p0=p0->next;  
  125.             p2=p2->next;  
  126.     }  
  127.     return list_merged;  
  128. }  
  129.   
  130.   
  131.   
  132. list_node* p0=(list_node*)malloc(sizeof(list_node));  
  133. list_node* phead=p0;  
  134. list_node* &p1=list1; //p1与list1绑定  
  135. list_node* foreach(list_node* p2) //递归合并(法二)  
  136. {  
  137.     if(p2==NULL) return phead;  
  138.   
  139.     foreach(p2->next);   
  140.   
  141.     if(p1->data > p2->data)  
  142.     {  
  143.         p0->next = (list_node*)malloc(sizeof(list_node));  
  144.         p0->next->data = p2->data;  
  145.         p0->next->next = NULL;   
  146.         p0=p0->next;  
  147.         return phead;  
  148.     }  
  149.     while(p1!=NULL && p1->data<=p2->data)  
  150.     {  
  151.         p0->next = (list_node*)malloc(sizeof(list_node));  
  152.         p0->next->data = p1->data;  
  153.         p0->next->next = NULL;   
  154.         p0=p0->next;  
  155.         p1 = p1->next;  
  156.     }  
  157.     if(p1==NULL)  
  158.     {  
  159.         p0->next = (list_node*)malloc(sizeof(list_node));  
  160.         p0->next->data = p2->data;  
  161.         p0->next->next = NULL;   
  162.         p0=p0->next;  
  163.     }  
  164.   
  165.     return phead;  
  166. }  
  167. //Blog:http://blog.youkuaiyun.com/zhanxinhang  
  168. int main()  
  169. {  
  170.     int list1_data[] = {1,4,6,8,10};    //链表数据升序 可在这里该数据进行测试  
  171.     int list2_data[] = {14,9,3,2};      //链表数据降序  
  172.   
  173.     list_create(list1,list1_data,5);   //构建单链表  
  174.     list_create(list2,list2_data,4);   //构建单链表  
  175.     list_print(list1);  
  176.     list_print(list2);  
  177.   
  178.     //list_node *list_merged=merge_two_list(); //合并两个链表  
  179.     //list_print(list_merged->next);      //打印合并后的链表  
  180.   
  181.     list_node *list_merged2=foreach(list2);    //使用递归合并两个链表  
  182.     list_print(list_merged2->next);  
  183.   
  184.     list_destroy(list1);                //销毁链表  
  185.     list_destroy(list2);                //销毁链表  
  186. //  list_destroy(list_merged);          //销毁合并后的链表  
  187.     list_destroy(list_merged2);         //销毁合并后的链表  
  188.     system("pause");  
  189.     return 0;  
  190. }  


:如何删除链表的倒数第m的元素?

分析构建p0,p1两个迭代器,初始使p0和p1指向头结点,接着使p1移动到第m+1项,然后指向头得p0与p1同时前进,当p1指向空节点的时候结束,这时p0所指的位置就是倒数第m个,时间复杂度为O(n)

实现代码:(为了学习的需要,现在C++朋友采用c++实现,不能满足c朋友要采用c实现的愿望,此实为c++朋友的遗憾,不过一切重在思想。^_^

  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.youkuaiyun.com/zhanxinhang 
  4. **/  
  5. #include <iostream>  
  6. #include <list>  
  7. using namespace std;  
  8.   
  9. class App  
  10. {  
  11.     list<int> *plist;   
  12.   
  13.     void delete_node_at_last(int m) //today`s topic  
  14.     {  
  15.         list<int>::iterator p0, p1;  
  16.         p0=p1=p2=plist->begin();  
  17.   
  18.         //使p1移到第m+1项  
  19.         for(int i=1; i<=m; i++)  
  20.             p1++;  
  21.   
  22.         //p0和p1同时前进,当p1到达终点时p0所指向的就是倒数第m个节点  
  23.         while(p1!=plist->end())  
  24.             p0++,p1++;  
  25.   
  26.         //删除节点  
  27.         plist->erase(p0);  
  28.     }  
  29.   
  30.     void create_list()  
  31.     {  
  32.         int list_data[]={1,2,3,4,5,6,7,8,9}; //链表数据  
  33.         plist = new list<int>(list_data, list_data+sizeof(list_data)/sizeof(int));  
  34.     }  
  35.   
  36.     void print_list()  
  37.     {  
  38.         list<int>::iterator it;  
  39.         for(it=plist->begin(); it!=plist->end(); it++)  
  40.             cout<<*it<<' ';  
  41.     }  
  42.   
  43. public:  
  44.     //test in run funtion  
  45.     void run()  
  46.     {  
  47.         create_list();  
  48.         delete_node_at_last(3); //删除倒数第三个节点  
  49.         print_list();  
  50.     }  
  51.   
  52.     ~App()  
  53.     {  
  54.         delete plist;  
  55.     }  
  56. };  
  57. //Blog:http://blog.youkuaiyun.com/zhanxinhang  
  58. int main()  
  59. {  
  60. App myapp;  
  61. myapp.run();  
  62. system("pause");  
  63. return 0;  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值