给定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 
#include 
/*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表中,则忽略该元素,继续遍历下一个元素。

具体实现可以用hashMap,将链表中的元素当做key,value为此元素出现的次数。

具体代码可参考下面代码修改后实现

packagecom.xtfggef.hashmap;importjava.util.HashMap;importjava.util.Map;importjava.util.Set;/*** 打印在数组中出现n/2以上的元素

* 利用一个HashMap来存放数组元素及出现的次数
*@authorerqing
**/
public classHashMapTest {public static voidmain(String[] args) {int [] a = {2,3,2,2,1,4,2,2,2,7,9,6,2,2,3,1,0};
Map map = new HashMap();for(int i=0; i
tmp+=1;
map.put(a[i], tmp);
}else{
map.put(a[i],1);
}
}
Set set = map.keySet();//------------1------------
for(Integer s : set) {if(map.get(s)>=a.length/2){
System.out.println(s);
}
}//--------------2---------------
}
}

这个方法的效率取决与hash表的实现技术,一般情况下,这个方法都比上面两种要好。