探究单向链表逆置转向及检查成环的问题

来源:互联网 发布:淘宝苏宁买手机可靠吗 编辑:程序博客网 时间:2024/05/16 05:38

假设链表节点的数据结构为:

typedef struct node {  int data;  struct node* next;}ListNode,*pListNode;

要求实现将一个单向链表逆置并检测如果链表成环返回FALSE,从参数返回新的链表头。

BOOL Reverse(pListNode& head);

这个问题看似简单,实际上太能发挥了。首先因为是单向链表,next不能简单的改变方向,要记录下即将被断开的节点,而即将被断开的节点它的next也是同样的问题。再者就是要如何检测有环。

单看逆置问题,通常的方法应该要用到3个指针:当前的p,下一个q,下一个的下一个head。 记下第三个指针,用第二个指向第一个,然后后移一步重复动作直到q没有下一个,再封口。

{  if (head != NULL && head->next != NULL)  {    pListNode p = head;    pListNode q = head->next;    p->next = NULL;    while (q->next != NULL)    {      head = q->next;      q->next = p;      p = q;      q = head;    }    head->next = p;  }  return;   //此法未处理成环问题}

单看检测成环问题,需要两个指针,一个向后一次移动一步,一个向后一次移动两步。假如他们能够相遇就是成环,他们任意一个走完链表都不成环。

{  if( head==NULL)return;  pListNode step1 = head;  pListNode step2 = head;  while(step1->next)  {    step1 = step1->next;    if(step2->next)step2 = step2->next;    else return TRUE;  //不成环    if(step2->next)step2 = step2->next;    else return TRUE;  //不成环    if(step1==step2)return FALSE;  }  return TRUE; //不成环}

以上两种方法都单独解决了部分问题,能不能同时解决两个问题呢?
于是我想到了递归。且不说它的弊端,单就解决问题而言是可行的。

BOOL Reverse(pListNode& head)  //不能处理成环检测{    pListNode p = head;    if(p->next)    {      head = p->next;      Reverse(head);      p->next->next = p;    }    else    {      return FALSE;    }    return FALSE;}

这个方法的问题是没法处理成环的问题。 在递归的背景下,解决成环的思路就想到如何标记一下处理过的node。于是我想到一个另类的做法。使用一个辅助结构体记录前后两个节点,把节点本身的next标为’1’,如果处理过程中发现next为1就是成环啦。

struct aid{  struct node* left;  struct node* next;};BOOL Reverse(pListNode& head) //同时处理逆置和环检测{    if(!head)return FALSE;    pListNode p = head;    if(p->next)    {      if(p->next==1)return TRUE;  //成环      aid *a = new aid;      a->left = p;      a->right = p->next;      head = p->next;      p->next = 1;      if(Reverse(head)==TRUE)      {        delete a;        return TRUE;      }      a->right->next = a->left;      a->left->next = 0;      delete a;    }    else    {      return FALSE;    }    return FALSE;}

注意,以上代码都没有实测!请以思路为主自行参考尝试实现。

0 0
原创粉丝点击