您的位置:首页 > 职场人生

经典面试题之单链表找环

2014-05-14 22:01 260 查看
大概的题意是,给出一个单向链表的头节点,求这么链表是否有环。有环的定义是,链表的尾节点指向了链接中间的某个节点。单链表的定义如下:
struct Node {
  Node(): next(NULL) {}
  Node *next;
};


这道题目还有一些变种,比如求链接的长度,求链表的尾节点等,不过大同小异。第一次听说这个题目,是在大三的时候,从一个刚面完试的学长那里。他当时的做法是对这个链表求逆,求逆的结果链表上每一个指针都反向,如果逆序完之后,链表的头节点不变,即说明链接有环。具体的证明过程略。这个方法的复杂也是O(N),但是需要修改原链表,或者使用O(N)的额外空间。

标准做法是使用两个指针,一个每次往前走2步,一个每次往前走1步,如果两个指针相遇,即说明链表有环,时间复杂度为O(N),空间复杂度为O(1)。

代码如下:
bool TestCircle(Node *p){
  if (p == NULL){
    return false;
  }
  if (p->next == NULL){
    return false;
  }
  if (p->next == p){
    return true;
  }
 
  Node *y = p->next;
  Node *x = p->next->next;
 
  while(x != NULL && y != NULL){
    x = x->next;
    if (x == NULL) break;
    x = x->next;
    y = y->next;
    if (x == y) break;
  }
 
  return x == y;
}


测试数据也比较简单,考虑一下空指针、单个节点成环、整条链表成环就可以了:
void RunTest() {
  Node *p = NULL;
  Node *q = NULL;
 
  cout << "empty list" << endl;
  cout << TestCircle(NULL) << endl;
 
  cout << "one node not circle" << endl;
  p = new Node;
  cout << TestCircle(p) << endl;
  delete p;
  p = NULL;
 
  cout << "one node circle" << endl;
  p = new Node;
  p->next = p;
  cout << TestCircle(p) << endl;
  delete p;
  p = NULL;
 
  cout << "two nodes not circle" << endl;
  p = new Node;
  p->next = new Node;
  cout << TestCircle(p) << endl;
  delete p->next;
  delete p;
  p = NULL;
 
  cout << "two nodes circle" << endl;
  p = new Node;
  p->next = new Node;
  p->next->next = p;
  cout << TestCircle(p) << endl;
  delete p->next;
  delete p;
  p = NULL;
 
  cout << "two nodes circle case 2" << endl;
  p = new Node;
  p->next = new Node;
  p->next->next = p->next;
  cout << TestCircle(p) << endl;
  delete p->next;
  delete p;
  p = NULL;
 
  cout << "5 nodes not circle" << endl;
  p = new Node;
  q = p;
  for (int i = 0; i < 4; ++i) {
    q->next = new Node;
    q = q->next;
  }
  cout << TestCircle(p) << endl;
  while (p->next != NULL) {
    q = p->next->next;
    delete p->next;
    p->next = q;
  }
  delete p;
  p = NULL;
 
  cout << "5 nodes circle" << endl;
  p = new Node;
  q = p;
  for (int i = 0; i < 4; ++i) {
    q->next = new Node;
    q = q->next;
  }
  q->next = p;
  cout << TestCircle(p) << endl;
  q->next = NULL;
  while (p->next != NULL) {
    q = p->next->next;
    delete p->next;
    p->next = q;
  }
  delete p;
  p = NULL;
 
  cout << "5 nodes circle case 2" << endl;
  p = new Node;
  q = p;
  for (int i = 0; i < 4; ++i) {
    q->next = new Node;
    q = q->next;
  }
  q->next = p->next->next;
  cout << TestCircle(p) << endl;
  q->next = NULL;
  while (p->next != NULL) {
    q = p->next->next;
    delete p->next;
    p->next = q;
  }
  delete p;
  p = NULL;
 
  cout << "5 nodes circle case 3" << endl;
  p = new Node;
  q = p;
  for (int i = 0; i < 4; ++i) {
    q->next = new Node;
    q = q->next;
  }
  q->next = q;
  cout << TestCircle(p) << endl;
  q->next = NULL;
  while (p->next != NULL) {
    q = p->next->next;
    delete p->next;
    p->next = q;
  }
  delete p;
  p = NULL;
 
  cout << "100000000 nodes not circle" << endl;
  p = new Node;
  q = p;
  for (int i = 0; i < 100000000; ++i) {
    q->next = new Node;
    q = q->next;
  }
  cout << TestCircle(p) << endl;
  while (p->next != NULL) {
    q = p->next->next;
    delete p->next;
    p->next = q;
  }
  delete p;
  p = NULL;
 
  cout << "100000000 nodes circle" << endl;
  p = new Node;
  q = p;
  for (int i = 0; i < 100000000; ++i) {
    q->next = new Node;
    q = q->next;
  }
  q->next = p;
  cout << TestCircle(p) << endl;
  q->next = NULL;
  while (p->next != NULL) {
    q = p->next->next;
    delete p->next;
    p->next = q;
  }
  delete p;
  p = NULL;
 
  cout << "100000000 nodes circle case 2" << endl;
  p = new Node;
  q = p;
  for (int i = 0; i < 100000000; ++i) {
    q->next = new Node;
    q = q->next;
  }
  Node *t = p;
  for (int i = 0; i < 16; ++i) {
    t = t->next;
  }
  q->next = t;
  cout << TestCircle(p) << endl;
  q->next = NULL;
  while (p->next != NULL) {
    q = p->next->next;
    delete p->next;
    p->next = q;
  }
  delete p;
  p = NULL;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: