求链表的并集和交集

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

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

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

时间: 2024-10-12 21:40:22

求链表的并集和交集的相关文章

求两个数组的交集

问题: 给你两个排序的数组,求两个数组的交集. 比如: A = 1 3 4 5 7, B = 2 3 5 8 9, 那么交集就是 3 5. 思路: 1. 每一次从B数组中取一值,然后在A数组里逐个比较,如果有相等的,则保存.该算法复杂度为 O(MN). M, N 分别为数组 A B 的长度. 2. 因为A B 都排过序,所以,每一次从B数组取值后,可以利用二分查找看是否在数组A里有B所对应的值,这样复杂度变成了O(N lg M). 这里,如果N 比 M 大,可以从A中取值,然后在B中判断是否有A

linux ---用uniq实现文件的并集和交集

1. 取出两个文件的并集(重复的行只保留一份) 2. 取出两个文件的交集(只留下同时存在于两个文件中的文件) 3. 删除交集,留下其他的行 1. cat file1 file2 | sort | uniq 2. cat file1 file2 | sort | uniq -d 3. cat file1 file2 | sort | uniq -u – c 显示输出中,在每行行首加上本行在文件中出现的次数.它可取代- u和- d选项. – d 只显示重复行. – u 只显示文件中不重复的各行. –

Java求两个List的交集

1 package demo; 2 3 import java.util.List; 4 5 public class Demo { 6 7 @SuppressWarnings("unchecked") 8 public static void main(String[] args) { 9 List array1=new ArrayList(); 10 array1.add("1");array1.add("2"); 11 List array

C/C++,数据结构实现两个链表的合并(尾插法建立单链表,求链表长度,直接插入排序)

1题目 实现两个链表的合并 2基本功能要求: 1.建立两个链表A和B,链表元素个数分别为m和n个. 2.假设元素分别为(x1,x2,-xm),和(y1,y2, -yn).把它们合并成一个线性表C,使得: 当m>=n时,C=x1,y1,x2,y2,-xn,yn,-,xm 当n>m时,C=y1,x1,y2,x2,-ym,xm,-,yn 3.输出线性表C: 用直接插入排序法对C进行升序排序,生成链表D,并输出链表D. 3测试数据: (1)A表(30,41,15,12,56,80) B表(23,56,

求链表倒数第几个节点

使用两个指针,和判断一个链表是否形成环类似 代码: #include <iostream> #include <list> using namespace std; typedef struct node { int data; struct node *next ; }Node,*pNode; void creatNode( pNode &pHead ){ bool isFirst=true; pNode p,q; int temp; scanf("%d&quo

leetcode——Longest Substring Without Repeating Characters 求链表中无重复字符的最大字串长度(AC)

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

求链表的中心节点

#include<iostream> using namespace std; class node{ public: node():value(0),next(NULL){} ~node(){} int value; node* next; };///be careful this ; node* createlist(int a[],int n) { node* startnode = new node[n]; node* ret = startnode; for(int i = 0;i&

求链表的倒数第N个节点

最近看一本书上有求链表的倒数第N个节点,简单实现了下 链表,实现方案如下 1.不借助链表长度顺序遍历倒数第N个节点 GetReserveN就是如此实现. 2.当然如果链表记录了节点长度也可以直接正序遍历出来 第lenth-N个节点就是倒数节点. template<class T> class LinkedList { public: operator T(){return m_data;} virtual ~LinkedList() { if(m_size!=0) Clear(); } voi

求两个集合的交集和并集C#

我是用hashset<T>来实现的 具体如代码所示 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace JiaoJi { class Program { static void Main(string[] args) { int [] arrA=new int[8]{1,2,3,4,5,6,7,8}; int [] arrB=new int[5]{4,5,