链表有关算法
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、
- 用两个指针p1和p2分别指向表头结点,即p1=p2=head
- p1和p2分别采用1和2作为步长遍历该链表。(注意,p2应该检查当前结点的下一个结点是否为NULL)
- 如果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 }
- (a)设从表头结点(包括)开始到环开始的结点(不包括)共 有l1个结点;设从环开始结点(包括)到它们相遇的结点(不包括)共有l2个结点;设从他们第一次相遇的结点开始(包括)到环开始结点(不包括)共有l3个结点;设整个环共有c个结点。则有c=l2+l3,且l1+l2即为它们第一次相遇时,p1所遍历的结点个数。
- (b)当它们第一次相遇时,固定p2,然后p1以1为步长继续遍历此表,则他们再次相遇时,p1从上次相遇到这次相遇所经过的总步长即为环中结点的个数c。
- (c)可以证明,当他们第一次相遇时,p1不可能经过环开始结点两次,即不可能开始第二次遍历环。设当它们第一次相遇时,p2已经把环遍历了k遍(k>=1)则有:2(l1+l2) = l1+l2+kc,即l1+l2=kc
- (d)l1+l2=kc=>l1=(k-1)c+l3
- (e)固定p2在它们第一次相遇的结点,然后p1回到表头,然后它们均以1为步长遍历链表,则它们第一次相遇时,即为环开始结点
2、
- (a)p从表头结点开始以1为步长遍历表,边遍历边将表反向
- (b)如果p遇到NULL,则说明表没有环
- (c)如果p最后等于head,则说明表有环,且记此时p所经过的表的结点数为l(l=2l1+c,l1和c的定义见方法一)
- (d)p再从表头结点开始以1为步长遍历表,边遍历边反向,当遍历到l/2时,停止,设两个指针p1,p2均指向当前结点,然后分别从两个方向同时以1为步长遍历表(其中一个需要边遍历,边反向链表),当他们第相遇时,当前结点即为环头结点。且此时链表还原成原来的链表。

浙公网安备 33010602011771号