给定2个链表,求这2个链表的并集(链表)和交集(链表)。不要求并集(链表)和交集(链表)中的元素有序。
如,输入:
List1: 10->15->4->20
List2: 8->4->2->10
输出:
交集(链表):4->10
并集(链表):2->8->20->4->15->10
方法一(简单、直观的方法):
下面是得到2个链表的并集和交集的简单算法。
InterSection(list1,list2): 初始化结果链表为空,遍历链表1,在链表2中查找它的每一元素,如果链表2中也有这个元素,则将该元素插入到结果链表中。
Union(list1,list2): 初始化结果链表为空,将链表1中的所有元素都插入到结果链表中。遍历链表2,如果结果链表中没有该元素,则插入,否则跳过该元素。
#include <stdio.h> #include <stdlib.h> /*Link list node*/ struct node { int data; struct node* next; }; /* A utility function to insert a node at the begining of a linked list */ void push(struct node **head_ref, int new_data); /* A utility function to chec if given data is present in a list */ bool isPresent(struct node *head, int data); /* Function to get union of two linked lists head1 and head2*/ struct node *getUnion(struct node *head1, struct node *head2) { struct node *result = NULL; struct node *t1 = head1, *t2 = head2; //Insert all elements of list1 to result list while(t1 != NULL) { push(&result, t1->data); t1 = t1->next; } //Insert those elements of list2 which are not present in result list while(t2 != NULL) { if(!isPresent(result, t2->data)) push(&result, t2->data); t2 = t2->next; } return result; } /* Function to get intersection of two linked lists head1 and head2 */ struct node *getIntersection(struct node *head1, struct node *head2) { struct node *result = NULL; struct node *t1 = head1; //Traverse list1 and search each element of it in list2. If the element //is present in list2, then insert the element to result while( t1 != NULL ) { if(isPresent(head2, t1->data)) push(&result, t1->data); t1 = t1->next; } return result; } /* A utility function to insert a node at the begining of a linked list */ void push(struct node**head_ref, int new_data) { /*allocate node*/ struct node* new_node = (struct node*)malloc(sizeof(struct node)); /* put in the data */ new_node->data = new_data; /*link the old list off the new node*/ new_node->next = (*head_ref); /* move the head to point to the new node*/ (*head_ref) = new_node; } /*A utility function fto print a linked list*/ void printList(struct node *node) { while( node != NULL ) { printf("%d ", node->data); node = node->next; } } /*A utility function that returns true if data is present in linked list else reurn false */ bool isPresent(struct node *head, int data) { struct node *t = head; while(t != NULL) { if( t->data == data ) return 1; t = t->next; } return 0; } /* Drier program to test above function*/ int main() { /* Start with the empty list */ struct node* head1 = NULL; struct node* head2 = NULL; struct node* intersecn = NULL; struct node* unin = NULL; /*create a linked lits 10->15->5->20 */ push (&head1, 20); push (&head1, 4); push (&head1, 15); push (&head1, 10); /*create a linked lits 8->4->2->10 */ push (&head2, 10); push (&head2, 2); push (&head2, 4); push (&head2, 8); intersecn = getIntersection (head1, head2); unin = getUnion (head1, head2); printf ("\n First list is \n"); printList (head1); printf ("\n Second list is \n"); printList (head2); printf ("\n Intersection list is \n"); printList (intersecn); printf ("\n Union list is \n"); printList (unin); printf("\n"); return 0; }
时间复杂度:在这个程序中,链表的并和交操作的时间复杂度都是O(mn),m是链表1的元素个数,n是链表2的元素个素。
方法2(使用归并排序):
使用这个方法,求2个链表的并集和交集的操作非常相似。首先,将对2个链表进行排序,然后遍历2个链表,得到2个了表的交集和并集。
下面是具体实现步骤:
用归并排序对第1个链表进行排序,这个操作的时间复杂度为O(mLogm).[点击这里查看详细]
用归并排序堆第2个链表进行排序,这个操作的时间复杂度为O(nLogn).
线性遍历2个有序的链表,得到2个链表的交集和并集。这个操作的时间复杂度为O(m+n).[这步类似于求有序数组的交集和并集,后者之前已经实现过,点击这里查看详细]
这个方法的时间复杂度是O(mLogm+ nLogn),优于第一种方法。
方法3(hash法):
Union(list1, list2)
首先初始化结果链表为NULL,创建一个空的hash表,遍历两个链表,将链表中的元素插入到hash表,插入元素的时候同时检查hash表中时候是否已经存在该元素,如果hash表中不存在该元素,则同时将该元素插入到结果链表中,如果hash表中已经存在,则忽略该元素,继续遍历下一个元素。
InterSection(list1, list2)
首先初始化结果链表为NULL,创建一个空的hash表,遍历list1,将list1中的每一个元素都插入到hash表中。然后遍历list2,对于list2中的元素,如果已经存在于hash表中,则将该元素插入到结果链表,如果不存在与hash表中,则忽略该元素,继续遍历下一个元素。
这个方法的效率取决与hash表的实现技术,一般情况下,这个方法都比上面两种要好。
原文地址:http://www.geeksforgeeks.org/archives/18615?utm_source=rss&utm_medium=rss&utm_campaign=union-and-intersection-of-two-linked-lists