给定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 (" First list is ");
- printList (head1);
- printf (" Second list is ");
- printList (head2);
- printf (" Intersection list is ");
- printList (intersecn);
- printf (" Union list is ");
- printList (unin);
- printf(" ");
- 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为此元素出现的次数。
具体代码可参考下面代码修改后实现
package com.xtfggef.hashmap; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * 打印在数组中出现n/2以上的元素 * 利用一个HashMap来存放数组元素及出现的次数 * @author erqing * */ public class HashMapTest { public static void main(String[] args) { int [] a = {2,3,2,2,1,4,2,2,2,7,9,6,2,2,3,1,0}; Map<Integer, Integer> map = new HashMap<Integer,Integer>(); for(int i=0; i<a.length; i++){ if(map.containsKey(a[i])){ int tmp = map.get(a[i]); tmp+=1; map.put(a[i], tmp); }else{ map.put(a[i], 1); } } Set<Integer> set = map.keySet();//------------1------------ for (Integer s : set) { if(map.get(s)>=a.length/2){ System.out.println(s); } }//--------------2--------------- } }
这个方法的效率取决与hash表的实现技术,一般情况下,这个方法都比上面两种要好。