机器视觉

自由、创新、技术、经典

给.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值翻倍

  1using System;
  2using System.Collections.Generic;
  3
  4namespace 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

posted on 2008-10-05 07:38  塞伦盖蒂之鹰  阅读(2066)  评论(3)    收藏  举报

导航