代码改变世界

C#两路list数组归并去重

2015-07-29 14:57  Nicolas.wang  阅读(1765)  评论(0编辑  收藏  举报

两个相同类型已排序数据进行合并,虽然list数组中有AddRange方法,但它只是把第二个数组从第一个数组末尾插入,假如两个数组有重复数据,保存进去。
还有Union方法合并去重,首先会从第一个数组进行检查然后再把第二个数组数据从第一个数组依次从末尾插入,但相对于自定义类型排序还是不能有效解决问题。

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

Examples

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 
 5 namespace Examples.Utils
 6 {
 7     public static class CollectionUtils
 8     {
 9         public static IList<T> MergeSortedLists<T>(Comparison<T> comparision, IList<T> list1, IList<T> list2)
10         {
11             var mergedList = new List<T>(list1.Count + list2.Count);
12             int i = 0, j = 0;
13             while (i < list1.Count && j < list2.Count)
14             {
15                 var result = comparision(list1[i], list2[j]);
16                 if (result <= 0)
17                 {
18                     if (result == 0)
19                     {
20                         j++;
21                     }
22                     mergedList.Add(list1[i++]);
23                 }
24                 else
25                 {
26                     mergedList.Add(list2[j++]);
27                 }
28             }
29             while (i < list1.Count)
30             {
31                 mergedList.Add(list1[i++]);
32             }
33             while (j < list2.Count)
34             {
35                 mergedList.Add(list2[j++]);
36             }
37             return mergedList;
38         }
39     }
40 }

TestExamples

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using NUnit.Framework;
 5 
 6 namespace Examples.Utils.Tests
 7 {
 8     [TestFixture]
 9     public class CollectionUtilsTests
10     {
11         [Test]
12         public void Merge2TestNoDuplicate()
13         {
14             var list1 = new List<int> {100, 50, 20, 10, 1};
15             var list2 = new List<int> {500, 70, 30, 15, 5};
16             var mergedList = CollectionUtils.MergeSortedLists(IntegerComparision, list1, list2);
17             var expectedList = GetExpectedMergedList(IntegerComparision, list1, list2);
18             Assert.AreEqual(expectedList.Count, mergedList.Count);
19             CollectionAssert.AreEqual(expectedList, mergedList);
20         }
21 
22         [Test]
23         public void Merge2TestWithDuplicates()
24         {
25             var list1 = new List<int> {100, 50, 20, 10, 1};
26             var list2 = new List<int> {500, 70, 50, 15, 1};
27             var mergedList = CollectionUtils.MergeSortedLists(IntegerComparision, list1, list2);
28             var expectedList = GetExpectedMergedList(IntegerComparision, list1, list2);
29             Assert.AreEqual(expectedList.Count, mergedList.Count);
30             CollectionAssert.AreEqual(expectedList, mergedList);
31         }
32 
33         [Test]
34         public void Merge2TestNoOverlap1()
35         {
36             var list1 = new List<int> {500, 300, 250, 150, 120};
37             var list2 = new List<int> {100, 50, 20, 10, 1};
38             var mergedList = CollectionUtils.MergeSortedLists(IntegerComparision, list1, list2);
39             var expectedList = GetExpectedMergedList(IntegerComparision, list1, list2);
40             Assert.AreEqual(expectedList.Count, mergedList.Count);
41             CollectionAssert.AreEqual(expectedList, mergedList);
42         }
43 
44         [Test]
45         public void Merge2TestNoOverlap2()
46         {
47             var list1 = new List<int> {100, 50, 20, 10, 1};
48             var list2 = new List<int> {500, 300, 250, 150, 120};
49             var mergedList = CollectionUtils.MergeSortedLists(IntegerComparision, list1, list2);
50             var expectedList = GetExpectedMergedList(IntegerComparision, list1, list2);
51             Assert.AreEqual(expectedList.Count, mergedList.Count);
52             CollectionAssert.AreEqual(expectedList, mergedList);
53         }
54 
55         private static IList<T> GetExpectedMergedList<T>(Comparison<T> comparision, params IList<T>[] lists)
56         {
57             var set = new SortedSet<T>(new ComparisionComparer<T>(comparision));
58             foreach (var list in lists)
59             {
60                 foreach (var item in list)
61                 {
62                     if (!set.Contains(item))
63                     {
64                         set.Add(item);
65                     }
66                 }
67             }
68             return set.ToList();
69         }
70 
71         private static int IntegerComparision(int x, int y)
72         {
73             return y - x;
74         }
75 
76         private class ComparisionComparer<T> : IComparer<T>
77         {
78             private readonly Comparison<T> _comparision;
79 
80             public ComparisionComparer(Comparison<T> comparision)
81             {
82                 _comparision = comparision;
83             }
84 
85             public int Compare(T x, T y)
86             {
87                 return _comparision(x, y);
88             }
89         }
90     }
91 }