链表面试汇总

来源:互联网 发布:成都美食 知乎 编辑:程序博客网 时间:2024/04/27 20:30

参考:http://blog.sina.com.cn/s/blog_725dd1010100tqwp.html

http://www.360doc.com/content/15/1122/15/1317564_515001533.shtml

以下都是针对单链表:

1.    给定一个单链表,如何判断是否存在环?

结论:第一个指针以步长v1为1,第二个指针以步长v2为2同时出发,则它们会在某一节点相遇;充分必要;单链表中存在环。

证明:讨论当v1和v2存在什么关系,在单链表中有环时一定会相遇。


这里k表示当两个指针同时在环中时(t是从此刻计时的),快的指针距离环中的连接点的距离,慢的指针此时刚好处于连接点,这里是指相对距离。

Node* collisionnode=NULL;//碰撞点bool JudgeCircleExist(Node* head){if(!head || head->next==0)return false;Node *p1=head,*p2=head;bool result=false;while(p2 && p2->next){p1=p1->next;p2=p2->next->next;if(p1==p2){collisionnode=p1;    result=true;break;}}return result;}

2.    若存在环,判断是6型环,还是o型环。

  答:判断头节点是否在环中

3.   若存在环,则如何知道环的长度?

int Circlelength(Node* head){JudgeCircleExist(head);if(!collisionnode)return 0;int count=0;Node *p1=collisionnode, *p2=collisionnode;while(p2 && p2->next){    ++count;p1=p1->next;p2=p2->next->next;if(p1==p2)break;}return count;}


4.   若存在环,如何找出环的连接点在哪里?

结论:两个指针分别从头节点 和碰撞点以步长为1出发,则它们会在环的连接点相遇。

证明:设头节点到连接点的距离是a,连接点到碰撞点的距离是b,环的长度是l。则s=a+b;2s=a+b+nl(根据问题1,s是慢指针从头节点出发到相遇在碰撞点时走过的距离),可推出 a=nl-b。所以结论正确。

Node* FindLoopPort(Node* head){JudgeCircleExist(head);Node *p1=head, *p2=collisionnode,*result=0;while(p1 && p2){p1=p1->next;p2=p2->next;if(p1==p2){result=p1;break;}}return result;}


5.   带环的单链表的长度是多少?

答:环的长度 + 头节点到连接点的长度 

6.   给定两个单链表(head1, head2),检测两个链表是否有交点,如果有返回第一个交点。(第一个公共结点问题)

答:判断是否相交,可通过判断尾节点是否一样

7.   只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点。

8.   只给定单链表中某个结点p(非空结点),在p前面插入一个结点。***

void InsertNode_before(Node* p,int x){Node* node=new Node(p->val);node->next=p->next;p->next=node;p->val=x;}


9.   给定单链表头结点,删除链表中倒数第k个结点。

10. 链表排序(归并排序)

  答:链表排序可用:归并、插入、冒泡及选择(单向链表);归并、快排、插入、冒泡及选择(双向链表);优先考虑归并,时间复杂度低(nlogn),实现简单。

//链表排序1 冒泡  由小到大Node* Bubble(Node* head){if(head==NULL)return 0;Node *p,*p_pre,*node=head;int temp;while(node){p_pre=head;p=head->next;while(p){if(p_pre->val>p->val){temp=p_pre->val;p_pre->val=p->val;p->val=temp;}p_pre=p;    p=p->next;}node=node->next;}return head;}//将链表从中间分开Node* Middle(Node* head){ Node* p1=head;    Node* p2=head;Node* mid;while(p2 &&p2->next){//注意检查p2->next是否为空mid=p1;p1=p1->next;p2=p2->next->next;}mid->next=NULL;return p1;}//将两个有序链表链接成一个新的有序链表Node* Merge(Node* head1, Node* head2){    Node* p=0;if(!head1)return head2;if(!head2)return head1;    if(head1->val<head2->val){p=head1;p->next=Merge(head1->next,head2);}else{p=head2;p->next=Merge(head1,head2->next);}return p;}// 归并排序Node* mergeSortList(Node* head){if(!head || !(head->next))return head;Node* middle=Middle(head);Node* first=mergeSortList(head);Node* second=mergeSortList(middle);return Merge(first,second);}


11. 反转单链表(额外的指针记录节点的前驱和后继)

Node* ReverseList(Node* head){if(!head || !(head->next))return head;Node* pre=0,*cur=head,*next=0,*newhead=0;while(cur){next=cur->next;if(next==0)newhead=cur;cur->next=pre;pre=cur;cur=next;}return newhead;}


12. 两个有序链表的合并

13. 找出链表的中间元素

14. 从尾到头打印单链表

void Print_reverse(Node* head){if(!head)return;Print_reverse(head->next);    cout<<head->val<<' ';}

15. 0,1,3...,n - 1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里第m个数字。求出这个圆圈里剩下的最后一个数字。(环形链表)

16. 请实现一个函数实现该链表的复制,其中m_pSibling指向的是链表中任意一个结点或者NULL。(复杂链表的复制)

//复杂链表的复制struct RandomListNode {    int label;    struct RandomListNode *next, *random;    RandomListNode(int x) :            label(x), next(NULL), random(NULL) {}};//链接链表void f1(RandomListNode* pHead){if(!pHead)return;RandomListNode* node=pHead;while(node){RandomListNode* p=new RandomListNode(node->label);RandomListNode* pnext=node->next;node->next=p;p->next=pnext;node=pnext;}}//设置兄弟指针void f2(RandomListNode* pHead){if(!pHead)return;RandomListNode* node=pHead;while(node){if(!(node->random))node->next->random=NULL;elsenode->next->random=node->random->next;node=node->next->next;}}//拆分链表RandomListNode* f3(RandomListNode* pHead){if(!pHead)return 0;RandomListNode* head=pHead->next;RandomListNode* node=pHead;while(node){RandomListNode* p=node->next;node->next=p->next;node=node->next;if(node) //检查节点是否为空 p->next=node->next;}return head;}RandomListNode* Clone(RandomListNode* pHead){f1(pHead);f2(pHead);return f3(pHead);}



17. 删除链表重复元素

Node* DeleteRepeat(Node* head){if(!head || !(head->next))return head;set<int> temp;//遍历链表的时候将不同的元素插入set容器内,以作参考temp.insert(head->val);Node* p=head->next;Node* pre=head;while(p){if(temp.find(p->val)!=temp.end()){pre->next=p->next;    delete p;p=pre->next;}else{temp.insert(p->val);pre=p;        p=p->next;}}return head;}

18. 链表和数组的区别在哪里?

答:数组静态分配内存,链表动态分配内存;数组在内存中连续存放,链表不连续;数组查找元素时间复杂度为O(1),链表查找元素时间复杂度为O(n);数组删除或插入元素时间复杂度为O(n),链表删除或插入元素时间复杂度为O(1)

补充:数组和指针的区别:

1.身份不同,数组贵族身份,是一种数据结构;指针贫民身份,4个字节的变量。但是当数组作函数形参时,则会退化成指针。

2.内存容量不同。char a[10]="abnffgg",char * p="abnffgg",sizeof(a)和sizeof(p)不同。

3.修改方式不同。char a[10]="abnffgg",char * p="abnffgg",可用a[0]='d'修改,但p[0]='d'不行。因为a表示字符数组,但是p只是一个指针变量,不能通过其修改字符串常量(位于全局区)


0 0
原创粉丝点击