链表系列三:操作单链表(续)

(7)检测一个单链表是否有环

单链表有环表示链表中的某个结点指向其前的某个结点从而构成一个环形,若要检测一个链表中是否有环,可以有以下三种方法:

a. 指针数组:所谓指针数组,是指用一个数组存放指针变量。这个思路是在遍历单链表的过程中,将已经遍历的结点放到一个足够大的数组中,然后将当前结点与指针数组中的结点比较,如果已经存在说明单链表中存在环,如果遍历到最后一个结点时还没有得到重复的结点,说明单链表中没有环。

b. 快慢指针:使用两个指针遍历单链表,一个一次走两步的快指针和一个一次走一步的慢指针,快指针每走一次都与慢指针比较,如果二者相等,那么单链表有环,如果快指针走到单链表尾部,即NULL,那么说明单链表没有环:

 1 template<class T>
 2 bool isLoop(myList<T> list)
 3 {
 4     if(list.isEmpty())
 5         return false;
 6     ListNode<T>* fast = list.head->next;
 7     ListNode<T>* slow = list.head->next;
 8 
 9     while(fast->next != NULL && fast->next->next != NULL)
10     {
11         fast = fast->next->next;
12         slow = slow->next;
13 
14         if(slow == fast)
15             return true;        
16     }
17     return false;
18 }
View Code

如果设整个链表的长度为L,环的长度为r,环入口点到相遇点的距离为x,链表头距离环入口点的距离为a,如下图所示:

那么存在关系式:

a = n*r + L-a-x;

它表示如果有两个指针分别从链表头和相遇点出发,最终这两个指针会在环入口点相遇,因而可以利用此点找到环入口点,具体代码如下:

 1 template<class T>
 2 ListNode<T>* GetLoopNode(myList<T> list)
 3 {
 4     if(list.isEmpty())
 5         return false;
 6     ListNode<T>* fast = list.head->next;
 7     ListNode<T>* slow = list.head->next;
 8 
 9     while(fast->next != NULL && fast->next->next != NULL)
10     {
11         fast = fast->next->next;
12         slow = slow->next;
13 
14         if(slow == fast)
15             break;
16     }
17     if(fast->next == NULL || fast->next->next == NULL)
18         return NULL;
19 
20     slow = list.head->next;
21     while(slow != fast)
22     {
23         slow = slow->next;
24         fast = fast->next;
25     }
26     return fast;
27 }
View Code

c. 使用STL库中的map表进行映射,只需要一次遍历即可:

 1 template<class T>
 2 ListNode<T>* GetNodeByMap(myList<T> list)
 3 {
 4     if(list.isEmpty())
 5         return NULL;
 6     map<ListNode<T>*, int> m;
 7     ListNode<T>* curr = list.head->next;
 8     while(curr != NULL)
 9     {
10         m[curr]++;
11         if(m[curr] > 1)
12         {
13             return curr;
14         }
15         curr = curr->next;
16     }
17     return NULL;
18 }
View Code

(8)判断两个链表是否交叉

这里的交叉不是指两个链表有一个结点是重合的然后各自指向不同的方向,而是指两个链表在某个结点开始之后的结点完全重合。判断这两个链表是否交叉有两个方法:

a. 将两个链表首尾相连,如果有交叉那么新的链表必定有环,用上面的方法就可以判断;

b. 如果两个链表交叉,那么最后的一个结点一定相同,因此分别遍历两个链表直到最后一个结点,比较最后的结点是否相等,若想等则相交,代码实现如下:

 1 template<class T>
 2 bool isIntersect(myList<T> list1, myList<T> list2)
 3 {
 4     if(list1.isEmpty() || list2.isEmpty())
 5         return false;
 6     ListNode<T>* ptr1 = list1.head->next;
 7     ListNode<T>* ptr2 = list2.head->next;
 8 
 9     while(ptr1->next != NULL)
10         ptr1 = ptr1->next;
11     while(ptr2->next != NULL)
12         ptr2 = ptr2->next;
13 
14     return ((ptr1 == ptr2) ? true : false);
15 
16 }
View Code

(9)删除单链表中的重复结点

a. 递归方法,比较简单,不详解。

b. map或hash_map映射的方法,它们的差别可以见:http://blog.csdn.net/sws9999/article/details/3081478,具体代码如下:

 1 template<class T>
 2 void DeleteSameNodes(myList<T> list)
 3 {
 4     if(list.isEmpty())
 5         return;
 6 
 7     ListNode<T>* prev = list.head;
 8     ListNode<T>* node = list.head->next;
 9     map<T, int> m;
10     while(node != NULL)
11     {
12         if(m[node->data] != 0)
13         {
14             ListNode<T>* temp = node;
15             node = temp->next;
16             prev->next = node;
17             delete temp;
18         }
19         else
20         {
21             ++m[node->data];
22             prev = prev->next;
23             node = node->next;    
24         }
25     }
26 }
View Code

(10)合并两个有序非交叉单链表
a. 递归合并:

 1 template<class T>
 2 ListNode<T>* MergeRecursive(ListNode<T>* ptr1, ListNode<T>* ptr2)
 3 {
 4     if(ptr2 == NULL)
 5         return ptr1;
 6     if(ptr1 == NULL)
 7         return ptr2;
 8 
 9     if(ptr1->data <= ptr2->data)
10     {
11         ptr1->next = MergeRecursive(ptr1->next, ptr2);
12         return ptr1;
13     }
14     else
15     {
16         ptr2->next = MergeRecursive(ptr1, ptr2->next);
17         return ptr2;
18     }
19 }
View Code

b. 非递归合并:

 1 template<class T>
 2 ListNode<T>* Merge(ListNode<T>* ptr1, ListNode<T>* ptr2)
 3 {
 4     if(ptr2 == NULL)
 5         return ptr1;
 6     if(ptr1 == NULL)
 7         return ptr2;
 8 
 9     ListNode<T>* ptr = NULL;
10     if(ptr1->data <= ptr2->data)
11     {
12         ptr = ptr1;
13         ptr1 = ptr1->next;
14     }
15     else
16     {
17         ptr = ptr2;
18         ptr2 = ptr2->next;
19     }
20     ListNode<T>* resPtr = ptr;
21 
22     while(ptr1 && ptr2)
23     {
24         if(ptr1->data <= ptr2->data)
25         {
26             ptr->next = ptr1;
27             ptr1 = ptr1->next;
28         }
29         else
30         {
31             ptr->next = ptr2;
32             ptr2 = ptr2->next;
33         }
34         ptr = ptr->next;
35     }
36 
37     if(ptr1 == NULL)
38         ptr->next = ptr2;
39     else
40         ptr->next = ptr1;
41     return resPtr;
42 }
View Code

 

 

posted on 2013-06-18 22:04  Sophia-呵呵小猪  阅读(200)  评论(0编辑  收藏  举报