单链表
上次百度面试问到了单链表逆置的问题,和两个链表如何判相交的问题
现在有空把碰到过的跟单链表相关的面试题整理一下
1.单链表原地逆置
#include<iostream> using namespace std; class node { public: node(int n) { data = n;
next = NULL; } node(){}; int data; node *next; }; class list { private: node* head; public: list() { head = new node(); head->next = NULL; } void add(node *n) { node *p = head; while(p->next!=NULL) { p = p->next; } p->next = n; } void show() { node *p = head; while(p->next!=NULL) { p = p->next; cout<<p->data<<endl; } } void reverse() { if(head->next == NULL) return; node *temp, *p, *pnext; p=head->next; pnext = p->next; p->next = NULL; while(pnext!=NULL) { temp = pnext->next; pnext->next = p; p = pnext; pnext = temp; } head->next = p; } }; int main() { list *l = new list(); l->add(new node(1)); l->add(new node(2)); l->add(new node(3)); l->add(new node(4)); l->add(new node(5)); l->add(new node(6)); l->show(); l->reverse(); cout<<"reverse"<<endl; l->show(); system("pause"); }
2.判断两个单链表是否相交
先考虑单链表没有环的情况
扩展:如果相交的话求出交点
#include<iostream> using namespace std; class node { public: node(int n) { data = n;
next = NULL; } node(){}; int data; node *next; }; class list { private: node* head; public: list() { head = new node(); head->next = NULL; } void add(node *n) { node *p = head; while(p->next!=NULL) { p = p->next; } p->next = n; } void show() { node *p = head; while(p->next!=NULL) { p = p->next; cout<<p->data<<endl; } } node *getHead() { return head; } }; bool judge(node *a, node *b) { node *p = a->next; node *q = b->next; int cnta=0, cntb=0; while(p!=NULL) { cnta++; p = p->next; } while(q!=NULL) { cntb++; q = q->next; } if(cnta>cntb) { p=a->next; int step = cnta-cntb; while(step--) { p = p->next; } q = b->next; } else { q=b->next; int step = cntb-cnta; while(step--) { q = q->next; } p = a->next; } while(p->next!=NULL && q->next!=NULL) { if(p==q) { cout<<"cross point is "<<p->data<<endl; return 1; } else { p=p->next; q=q->next; } } cout<<"no cross"<<endl; return 0; } int main() { list *l = new list(); list *ll = new list(); node *a = new node(1);node *b = new node(2);node *c = new node(3); node *d = new node(4);node *e = new node(5);node *f = new node(6);node *g = new node(7);
l->add(a);l->add(b);l->add(c);l->add(f);l->add(g); ll->add(d);ll->add(e);ll->add(c);ll->add(f);ll->add(g);
judge(l->getHead(),ll->getHead());
list *l1 = new list(); l1->add(a);l1->add(b);l1->add(c); list *l2 = new list(); l2->add(d);l2->add(e);l2->add(f);l2->add(g); judge(l1->getHead(), l2->getHead());
system("pause"); }
3.判断单链表是否有环
#include<iostream> using namespace std; class node { public: node(int n) { data = n; next = NULL; } node(){}; int data; node *next; }; class list { private: node* head; public: list() { head = new node(); head->next = NULL; } void add(node *n) { node *p = head; while(p->next!=NULL) { p = p->next; } p->next = n; } void show() { node *p = head; while(p->next!=NULL) { p = p->next; cout<<p->data<<endl; } } node *getHead() { return head; } bool isCircle() { node *p = head; node *q = head; while(q->next->next!=NULL && q->next!=NULL) { p = p->next; q = q->next->next; cout<<p->data<<" "<<q->data<<endl; if(p==q) { cout<<"circle exists"<<endl; return 1; } } cout<<"no circle exists"<<endl; return 0; } }; int main() { list *l = new list();list *ll = new list(); node *a = new node(1);node *b = new node(2);node *c = new node(3);node *d = new node(4); node *e = new node(5);node *f = new node(6);node *g = new node(7); l->add(a);l->add(b);l->add(c);l->add(d);l->add(e);l->add(f);l->add(g); l->isCircle(); l->add(e); l->isCircle(); system("pause"); }
扩展:
判断是否有环,如果有环的话找到环的入口
思路:假设单链表中有环,并且从链表头到环的入口长度为k,环的大小为n
在上述方法的基础上改进
可以把整个过程分为三步:
1.当较慢的指针走到环入口时走了k个位置,较快指针已经走了2k个,比较慢指针多走k个位置
2.在1的基础上较慢指针再走n-k个位置,此时较快指针又会多走n-k个位置,那么较快指针一共多走了n个位置,此时两指针相遇
3.在2的基础上,用一个新的指针从头开始和较慢指针同时前进,一次一个位置,两指针相遇时,刚好前进了k个位置,同时到达环的入口点。
#include<iostream> using namespace std; class node { public: node(int n) { data = n; next = NULL; } node(){}; int data; node *next; }; class list { private: node* head; public: list() { head = new node(); head->next = NULL; } void add(node *n) { node *p = head; while(p->next!=NULL) { p = p->next; } p->next = n; } void show() { node *p = head; while(p->next!=NULL) { p = p->next; cout<<p->data<<endl; } } node *getHead() { return head; } node *findCircleEntrance() { node *p = head; node *q = head; while(q->next->next!=NULL && q->next!=NULL) { p = p->next; q = q->next->next; cout<<p->data<<" "<<q->data<<endl; if(p==q) { cout<<"circle exists"<<endl; break; } } if(q->next->next!=NULL && q->next!=NULL) { node *t = head; while(t!=q) { t=t->next; q=q->next; } cout<<"the start of a circle is "<<t->data<<endl; return t; } cout<<"no circle exists"<<endl; return 0; } }; int main() { list *l = new list(); list *ll = new list(); node *a = new node(1);node *b = new node(2);node *c = new node(3);node *d = new node(4); node *e = new node(5);node *f = new node(6);node *g = new node(7); l->add(a);l->add(b);l->add(c);l->add(d);l->add(e);l->add(f);l->add(g); l->findCircleEntrance(); l->add(d); l->findCircleEntrance(); system("pause"); }
4.两个带环的链表求交点
如果两个链表相交,其中一个有环,那么另一个肯定也有环
上面已经找到了环的入口,那么沿着环绕一圈,如果能到另一个链表的环上,那么就是相交了,同时也能找到交点。
#include<iostream> using namespace std; class node { public: node(int n) { data = n; next = NULL; } node(){}; int data; node *next; }; class list { private: node* head; public: list() { head = new node(); head->next = NULL; } void add(node *n) { node *p = head; while(p->next!=NULL) { p = p->next; } p->next = n; } void show() { node *p = head; while(p->next!=NULL) { p = p->next; cout<<p->data<<endl; } } node *getHead() { return head; } node *findCircleEntrance() { node *p = head; node *q = head; while(q->next!=NULL && q->next->next!=NULL) { p = p->next; q = q->next->next; if(p==q) { cout<<"circle exists"<<endl; break; } } if(p->next==NULL || p->next->next ==NULL) { cout<<"no circle exists"<<endl; return NULL; } if(q->next->next!=NULL && q->next!=NULL) { node *t = head; while(t!=q) { t=t->next; q=q->next; } cout<<"the start of a circle is "<<t->data<<endl; return t; } return NULL; } }; bool judge(list *l, list *k) { node *p = l->findCircleEntrance(); node *q = k->findCircleEntrance(); if(p==NULL || q==NULL) { cout<<"no cross"<<endl; return 0; } node *temp = p->next; while(temp != p) { if(temp == q) { cout<<"the cross is "<<temp->data<<endl; return 1; } else temp = temp->next; } return 0; } int main() { list *l = new list();list *ll = new list(); node *a = new node(1);node *b = new node(2);node *c = new node(3);node *d = new node(4); node *e = new node(5);node *f = new node(6);node *g = new node(7); l->add(a);l->add(b);l->add(c);l->add(d);l->add(e);l->add(b); ll->add(f);ll->add(g);ll->add(e); judge(l, ll); cout<<endl; list *lll = new list(); node *h = new node(8);node *i = new node(9); lll->add(h);lll->add(i); judge(l,lll); system("pause"); }
这种方式只能判定交点在环上的情况
如果是交点不在环上,那么用前文中两个无环链表相交的方法可以判定
即在进入环之前找到交点