链表有关算法

1.判断两个链表是否相交

     解题思路:

    1、先求两个链长m1,m2,令d=|m1-m2|,想让长的链走d个节点,然后两个链表同步往后走,边走边比较,若出现相同的节点则两个链表有相交,否则就不想交。。。;

    2、遍历两个链表到最后节点,若相交 则这两个节点相等;

View Code
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <malloc.h>
  4 
  5 /**
  6 判断两个链表是否相交
  7 */
  8 struct Node
  9 {
 10     int data;
 11     struct Node* next;
 12 };
 13 typedef struct Node*  pNode;
 14 typedef struct Node   Link;
 15 /**
 16    创建长度为n的链表;
 17 */
 18 pNode create( int n)
 19 {
 20     pNode head = NULL;
 21     pNode p1 = head, p2 = head;
 22     head = (pNode)malloc(sizeof(Link));  //空头节点
 23     p1 = head;
 24     while(n--)
 25     {
 26         p2  = (pNode) malloc(sizeof(Link));
 27         printf("please input a num__\b");
 28         scanf("%d",&(p2->data));
 29         p1->next = p2;
 30         p2->next = NULL;
 31         p1 = p2;
 32     }
 33     head->data = n;
 34     return (head);
 35 }
 36 int print(pNode head)
 37 {
 38     pNode p1 = head;
 39     pNode p2 = p1->next;
 40     while(p2)
 41     {
 42         printf("%d ",p2->data);
 43         p1= p2;
 44         p2 = p2->next;
 45     }
 46     return 0;
 47 }
 48 
 49 int testIntersect(pNode h1, pNode h2)
 50 {
 51     /**
 52        思想1:
 53             计算h1的长度length1,h2的长度length2
 54 
 55             if length1 > length2         //与length2>length1相同
 56                 len = length1 - length2
 57             while(len--) h1= h1->next;   //先移动长链len个
 58             while(length2--)
 59             {
 60                 if(h1 = h2 )  return h1  //若相等 && <> NULL 则相交
 61                 else
 62                   h1 = h1->next;
 63                   h2 = h2->next;         //同时移动
 64             }
 65             //能得到公共部分
 66         思想2:
 67             遍历h1到末尾,
 68             遍历h2到末尾,若h1 = h2 则相交。
 69             //仅判断是否相交
 70     */
 71 
 72 
 73     //1的实现
 74     #if  0
 75        pNode p1 = h1->next;
 76        pNode p2 = h2->next;
 77        int len;
 78        if(h1->data -  h2->data > 0)
 79        {
 80            len = h1->data - h2->data;
 81            while(len--)
 82            {
 83                p1 = p1->next;
 84            }
 85            len = h2->data;
 86        }
 87        else
 88        {
 89            len = h2->data - h1->data;
 90            while(len--)
 91            {
 92                p2 = p2->next;
 93            }
 94            len = h1->data;
 95        }
 96        while(len--)
 97        {
 98            if(p1 == p2 ) return 1;
 99            else
100            {
101                p1 = p1->next;
102                p2 = p2->next;
103            }
104        }
105        return 0;
106     #endif
107 
108     //2的实现
109     #if 2
110         pNode p1 = h1;
111         pNode p2 = h2;
112         int len = h1->data;
113         while(len--)
114         {
115             p1 = p1->next;
116         }
117         len = h2->data;
118         while(len--)
119         {
120             p2 =p2->next;
121         }
122         if(p1 == p2) return 1;
123         else  return 0;
124     #endif // 2
125 }
126 
127 int main()
128 {
129     pNode head  = create(3);
130     print(head);
131     return 0;
132 }

2、判断链表是否有环

    解题思路:

    1、

  1. 用两个指针p1和p2分别指向表头结点,即p1=p2=head
  2. p1和p2分别采用1和2作为步长遍历该链表。(注意,p2应该检查当前结点的下一个结点是否为NULL)
  3. 如果p1或者p2遇到了NULL,则证明该链表没有环;若p1和p2在某时刻指向同一结点,则说明该链表有环。

   

View Code
 1 int testCircle(pNode h)
 2 {
 3     pNode slow = h;
 4     pNode fast = h;
 5     while(fast && fast->next)
 6     {
 7         slow = slow->next;
 8         fast = fast->next->next;
 9         if(slow == fast)
10         {
11             printf("相交\n");
12             //break;
13             return 1;
14         }
15     }
16     if(fast==NULL || fast->next == NULL)
17     {
18         printf("不相交\n");
19         return 0;
20     }
21     return 0;
22 }
  1. (a)设从表头结点(包括)开始到环开始的结点(不包括)共 有l1个结点;设从环开始结点(包括)到它们相遇的结点(不包括)共有l2个结点;设从他们第一次相遇的结点开始(包括)到环开始结点(不包括)共有l3个结点;设整个环共有c个结点。则有c=l2+l3,且l1+l2即为它们第一次相遇时,p1所遍历的结点个数。
  2. (b)当它们第一次相遇时,固定p2,然后p1以1为步长继续遍历此表,则他们再次相遇时,p1从上次相遇到这次相遇所经过的总步长即为环中结点的个数c。
  3. (c)可以证明,当他们第一次相遇时,p1不可能经过环开始结点两次,即不可能开始第二次遍历环。设当它们第一次相遇时,p2已经把环遍历了k遍(k>=1)则有:2(l1+l2) = l1+l2+kc,即l1+l2=kc
  4. (d)l1+l2=kc=>l1=(k-1)c+l3
  5. (e)固定p2在它们第一次相遇的结点,然后p1回到表头,然后它们均以1为步长遍历链表,则它们第一次相遇时,即为环开始结点

2、

    1. (a)p从表头结点开始以1为步长遍历表,边遍历边将表反向
    2. (b)如果p遇到NULL,则说明表没有环
    3. (c)如果p最后等于head,则说明表有环,且记此时p所经过的表的结点数为l(l=2l1+c,l1和c的定义见方法一)
    4. (d)p再从表头结点开始以1为步长遍历表,边遍历边反向,当遍历到l/2时,停止,设两个指针p1,p2均指向当前结点,然后分别从两个方向同时以1为步长遍历表(其中一个需要边遍历,边反向链表),当他们第相遇时,当前结点即为环头结点。且此时链表还原成原来的链表。

 

 

posted on 2013-03-19 16:54  lijianl  阅读(410)  评论(0)    收藏  举报

导航