求链表的并集和交集

论坛 期权论坛 脚本     
匿名技术用户   2021-1-3 14:51   47   0

给定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,如果结果链表中没有该元素,则插入,否则跳过该元素。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. /*Link list node*/
  4. struct node
  5. {
  6. int data;
  7. struct node* next;
  8. };
  9. /* A utility function to insert a node at the begining of a linked list */
  10. void push(struct node **head_ref, int new_data);
  11. /* A utility function to chec if given data is present in a list */
  12. bool isPresent(struct node *head, int data);
  13. /* Function to get union of two linked lists head1 and head2*/
  14. struct node *getUnion(struct node *head1, struct node *head2)
  15. {
  16. struct node *result = NULL;
  17. struct node *t1 = head1, *t2 = head2;
  18. //Insert all elements of list1 to result list
  19. while(t1 != NULL)
  20. {
  21. push(&result, t1->data);
  22. t1 = t1->next;
  23. }
  24. //Insert those elements of list2 which are not present in result list
  25. while(t2 != NULL)
  26. {
  27. if(!isPresent(result, t2->data))
  28. push(&result, t2->data);
  29. t2 = t2->next;
  30. }
  31. return result;
  32. }
  33. /* Function to get intersection of two linked lists head1 and head2 */
  34. struct node *getIntersection(struct node *head1, struct node *head2)
  35. {
  36. struct node *result = NULL;
  37. struct node *t1 = head1;
  38. //Traverse list1 and search each element of it in list2. If the element
  39. //is present in list2, then insert the element to result
  40. while( t1 != NULL )
  41. {
  42. if(isPresent(head2, t1->data))
  43. push(&result, t1->data);
  44. t1 = t1->next;
  45. }
  46. return result;
  47. }
  48. /* A utility function to insert a node at the begining of a linked list */
  49. void push(struct node**head_ref, int new_data)
  50. {
  51. /*allocate node*/
  52. struct node* new_node = (struct node*)malloc(sizeof(struct node));
  53. /* put in the data */
  54. new_node->data = new_data;
  55. /*link the old list off the new node*/
  56. new_node->next = (*head_ref);
  57. /* move the head to point to the new node*/
  58. (*head_ref) = new_node;
  59. }
  60. /*A utility function fto print a linked list*/
  61. void printList(struct node *node)
  62. {
  63. while( node != NULL )
  64. {
  65. printf("%d ", node->data);
  66. node = node->next;
  67. }
  68. }
  69. /*A utility function that returns true if data is present in
  70. linked list else reurn false */
  71. bool isPresent(struct node *head, int data)
  72. {
  73. struct node *t = head;
  74. while(t != NULL)
  75. {
  76. if( t->data == data )
  77. return 1;
  78. t = t->next;
  79. }
  80. return 0;
  81. }
  82. /* Drier program to test above function*/
  83. int main()
  84. {
  85. /* Start with the empty list */
  86. struct node* head1 = NULL;
  87. struct node* head2 = NULL;
  88. struct node* intersecn = NULL;
  89. struct node* unin = NULL;
  90. /*create a linked lits 10->15->5->20 */
  91. push (&head1, 20);
  92. push (&head1, 4);
  93. push (&head1, 15);
  94. push (&head1, 10);
  95. /*create a linked lits 8->4->2->10 */
  96. push (&head2, 10);
  97. push (&head2, 2);
  98. push (&head2, 4);
  99. push (&head2, 8);
  100. intersecn = getIntersection (head1, head2);
  101. unin = getUnion (head1, head2);
  102. printf ("\n First list is \n");
  103. printList (head1);
  104. printf ("\n Second list is \n");
  105. printList (head2);
  106. printf ("\n Intersection list is \n");
  107. printList (intersecn);
  108. printf ("\n Union list is \n");
  109. printList (unin);
  110. printf("\n");
  111. return 0;
  112. }

时间复杂度:在这个程序中,链表的并和交操作的时间复杂度都是O(mn),m是链表1的元素个数,n是链表2的元素个素。

方法2(使用归并排序):

使用这个方法,求2个链表的并集和交集的操作非常相似。首先,将对2个链表进行排序,然后遍历2个链表,得到2个了表的交集和并集。

下面是具体实现步骤:

  1. 用归并排序对第1个链表进行排序,这个操作的时间复杂度为O(mLogm).[点击这里查看详细]

  2. 用归并排序堆第2个链表进行排序,这个操作的时间复杂度为O(nLogn).

  3. 线性遍历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表的实现技术,一般情况下,这个方法都比上面两种要好。

原文地址:http://www.geeksforgeeks.org/archives/18615?utm_source=rss&utm_medium=rss&utm_campaign=union-and-intersection-of-two-linked-lists

转载于:https://www.cnblogs.com/bendantuohai/p/4496559.html

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP