给.NET链表(LinkedList<T>)增加归并排序
给.NET链表(LinkedList<T>)增加归并排序
作者:Henry Ho
排序算法有很多种,常用的有以下几种:
冒泡排序, 插入排序,选择排序 这三种效率低下
希尔排序不错,但是算法复杂度极限是O(N log N)
快速排序很棒,但是不可靠(指在特殊情况下,如倒序时效率极低)
归并排序是可以信赖的,但需要O(N)的空间占用
堆排序也是可信赖的,但不稳定,最坏情况下比快速排序慢4倍。
当你的数据结构是数组时,你可以选择上述任一种排序方法;
但当你的数据结构是链表时,归并排序比其它任何一种排序都要好。
这里介绍一种空间占用为O(1)的归并排序。
代码用了C#3.0的新特性-扩展方法(语法糖),若你用的是C#2.0,稍做改变即可。
算法大概说明:
每次循环,从两个已排序的队列p和q中取最小值,队列有K个元素, 合并为2K个元素,K初始值为1,循环一次K值翻倍
1
using System;
2
using System.Collections.Generic;
3
4
namespace TestSort
5
{
6
class Program
7
{
8
static void Main(string[] args)
9
{
10
LinkedList<int> list = new LinkedList<int>();
11
list.AddLast(100);
12
list.AddLast(10);
13
list.AddLast(2030);
14
list.AddLast(82);
15
list.AddLast(837);
16
17
list.MergeSort();
18
foreach (var i in list)
19
Console.Out.WriteLine(i);
20
Console.ReadKey();
21
}
22
}
23
24
public static class ExternsionFunctions
25
{
26
// MergeSort for LinkedList<T>
27
// 改编自Wiki::Merge Sort By Henry Ho 2008.10
28
public static void MergeSort<T>(this LinkedList<T> list)
29
where T : IComparable<T>
30
{
31
LinkedListNode<T> p, q, e, tail;
32
int psize, qsize, nmerges;
33
// Silly special case: if `list' was passed in as NULL, return NULL immediately.
34
if ((list == null) || (list.Count <= 1))
35
return;
36
37
int insize = 1;
38
39
while (true)
40
{
41
p = list.First;
42
nmerges = 0; /* count number of merges we do in this pass */
43
tail = null;
44
45
while (p != null)
46
{
47
nmerges++; /* there exists a merge to be done */
48
/* step `insize' places along from p */
49
q = p;
50
psize = 0;
51
for (int i = 0; (i < insize) && (q != null); i++)
52
{
53
psize++; q = q.Next;
54
}
55
56
/* if q hasn't fallen off end, we have two lists to merge */
57
qsize = insize;
58
59
/* now we have two lists; merge them */
60
while ((psize > 0) || ((qsize > 0) && (q != null)))
61
{
62
/* decide whether next element of merge comes from p or q */
63
if (psize == 0)
64
{
65
/* p is empty; e must come from q. */
66
e = q; q = q.Next; qsize--;
67
}
68
else if ((qsize == 0) || (q == null))
69
{
70
/* q is empty; e must come from p. */
71
e = p; p = p.Next; psize--;
72
}
73
//else if (cmp(p, q) <= 0)
74
else if (p.Value.CompareTo(q.Value) <= 0)
75
{
76
/* First element of p is lower (or same); e must come from p. */
77
e = p; p = p.Next; psize--;
78
}
79
else
80
{
81
/* First element of q is lower; e must come from q. */
82
e = q; q = q.Next; qsize--;
83
}
84
85
list.Remove(e);
86
if (tail == null)
87
list.AddFirst(e);
88
else
89
list.AddAfter(tail, e);
90
tail = e;
91
}
92
93
/* now p has stepped `insize' places along, and q has too */
94
p = q;
95
}
96
//swap list<=>new_list
97
//temp_list = list; list = new_list; new_list = temp_list;
98
/* If we have done only one merge, we're finished. */
99
if (nmerges <= 1) /* allow for nmerges==0, the empty list case */
100
return; // list;
101
/* Otherwise repeat, merging lists twice the size */
102
insize *= 2;
103
}
104
}
105
}
106
}
107
using System;2
using System.Collections.Generic;3

4
namespace TestSort5
{6
class Program7
{8
static void Main(string[] args)9
{10
LinkedList<int> list = new LinkedList<int>();11
list.AddLast(100);12
list.AddLast(10);13
list.AddLast(2030);14
list.AddLast(82);15
list.AddLast(837);16

17
list.MergeSort();18
foreach (var i in list)19
Console.Out.WriteLine(i);20
Console.ReadKey();21
}22
}23

24
public static class ExternsionFunctions25
{26
// MergeSort for LinkedList<T>27
// 改编自Wiki::Merge Sort By Henry Ho 2008.1028
public static void MergeSort<T>(this LinkedList<T> list)29
where T : IComparable<T>30
{31
LinkedListNode<T> p, q, e, tail;32
int psize, qsize, nmerges;33
// Silly special case: if `list' was passed in as NULL, return NULL immediately.34
if ((list == null) || (list.Count <= 1))35
return;36

37
int insize = 1;38

39
while (true)40
{41
p = list.First;42
nmerges = 0; /* count number of merges we do in this pass */43
tail = null;44

45
while (p != null)46
{47
nmerges++; /* there exists a merge to be done */48
/* step `insize' places along from p */49
q = p;50
psize = 0;51
for (int i = 0; (i < insize) && (q != null); i++)52
{53
psize++; q = q.Next;54
}55

56
/* if q hasn't fallen off end, we have two lists to merge */57
qsize = insize;58

59
/* now we have two lists; merge them */60
while ((psize > 0) || ((qsize > 0) && (q != null)))61
{62
/* decide whether next element of merge comes from p or q */63
if (psize == 0)64
{65
/* p is empty; e must come from q. */66
e = q; q = q.Next; qsize--;67
}68
else if ((qsize == 0) || (q == null))69
{70
/* q is empty; e must come from p. */71
e = p; p = p.Next; psize--;72
}73
//else if (cmp(p, q) <= 0)74
else if (p.Value.CompareTo(q.Value) <= 0)75
{76
/* First element of p is lower (or same); e must come from p. */77
e = p; p = p.Next; psize--;78
}79
else80
{81
/* First element of q is lower; e must come from q. */82
e = q; q = q.Next; qsize--;83
}84

85
list.Remove(e);86
if (tail == null)87
list.AddFirst(e);88
else89
list.AddAfter(tail, e);90
tail = e;91
}92

93
/* now p has stepped `insize' places along, and q has too */94
p = q;95
}96
//swap list<=>new_list97
//temp_list = list; list = new_list; new_list = temp_list;98
/* If we have done only one merge, we're finished. */99
if (nmerges <= 1) /* allow for nmerges==0, the empty list case */100
return; // list;101
/* Otherwise repeat, merging lists twice the size */102
insize *= 2;103
}104
}105
}106
}107



浙公网安备 33010602011771号