日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

趣味编程:函数式链表的快速排序(参考答案)

發布時間:2025/3/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 趣味编程:函数式链表的快速排序(参考答案) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前我提出了一個“趣味編程”,模仿Haskell的方式對一個鏈表進行快速排序。在那篇文章中我解釋了Haskell列表的結構,并給出了ImmutableList的基礎實現。快速排序的例子很多,多做也沒有意思。這題雖然打著“快速排序”的旗幟,但事實上這里的關鍵在于實現ImmutableList數據結構的相關操作——否則為什么叫“函數式鏈表”的快速排序呢?。

一開始,我提出使用null來表示一個空鏈表,不過RednaxelaFX指出應該使用Null Object Pattern來表現。因此我修改了文章的代碼示例。不過后來RednaxelaFX同學指出,其實我的做法并沒有按照他的理解進行。我也認為他的做法更確切一些,因此也對代碼進行了修改。于是這次我給出的“參考答案”,便參考了他的部分實現方式。

ImmutableList結構的定義如下:

public abstract class ImmutableList<T> : IEnumerable<T> {public abstract T Head { get; }public abstract ImmutableList<T> Tail { get; }public abstract bool IsEmpty { get; }#region IEnumerable<T> Memberspublic IEnumerator<T> GetEnumerator(){var current = this;while (!current.IsEmpty){yield return current.Head;current = current.Tail;}}#endregion#region IEnumerable MembersIEnumerator IEnumerable.GetEnumerator(){return this.GetEnumerator();}#endregion }

與上一篇文章給出的定義不同,ImmutableList<T>被定義為一個抽象類,包含一個ImmutableList的成員抽象與相關方法。ImmutableList抽象類有兩個具體實現:分別表示空鏈表(EmptyImmutableList)和非空鏈表(NonEmptyImmutableList)。兩種實現都非常簡單:

public abstract class ImmutableList<T> : IEnumerable<T> {public static readonly ImmutableList<T> Empty = new EmptyImmutableList<T>(); ... }internal sealed class EmptyImmutableList<T> : ImmutableList<T> {public EmptyImmutableList() { }public override T Head{get{throw new InvalidOperationException("an empty list has no head.");}}public override ImmutableList<T> Tail{get{throw new InvalidOperationException("an empty list has no tail.");}}public override bool IsEmpty { get { return true; } } }internal class NonEmptyImmutableList<T> : ImmutableList<T> {public NonEmptyImmutableList(T head, ImmutableList<T> tail){this.m_head = head;this.m_tail = tail;}private T m_head;public override T Head { get { return this.m_head; } }private ImmutableList<T> m_tail;public override ImmutableList<T> Tail { get { return this.m_tail; } }public override bool IsEmpty { get { return false; } } }

EmptyImmutableList實現了ImmutableList,并讓其Head和Tail屬性都拋出異常。在整個ImmutableList體系中,EmptyImmutableList和NonEmptyImmutableList類都是對外部隱藏的(因此被定義為internal),用戶可以操作的唯獨只是ImmutableList抽象類。在這里,為了方便起見,我們定義了一個全局唯一的EmptyImmutableList對象,放在ImmutableList的靜態只讀屬性Empty中,在任何需要使用“空鏈表”的情況下,都不需要重新生成EmptyImmutableList類。

接下來便是關鍵了,我們需要創建一些ImmutableList在快速排序中所必要的操作。例如,構建一個鏈表,其中只包含一個元素:

public abstract class ImmutableList<T> : IEnumerable<T> {public static readonly ImmutableList<T> Empty = new EmptyImmutableList<T>();public static ImmutableList<T> Create(T element){return new NonEmptyImmutableList<T>(element, Empty);} }

請注意,由于ImmutableList是唯一對外公開的接口,因此實際上這些方法都是定義在ImmutableList上的。那么再想想,快速排序還需要什么操作?沒錯,就是兩個鏈表的連接操作,這里我把它定義為“+”操作:

public static ImmutableList<T> operator +(ImmutableList<T> headList, ImmutableList<T> tailList) {if (headList == null) throw new ArgumentNullException("headList");if (tailList == null) throw new ArgumentNullException("tailList");if (headList.IsEmpty) return tailList;if (tailList.IsEmpty) return headList;... }

這里我們要想一下,把兩個鏈表連接起來之后結果是怎么樣的?假設有list1和list2兩個鏈表:

1 -> 2 -> 3↖ list1 4 -> 5 -> 6↖ list2

如果執行result = list1 + list2,那么最終的結果是什么呢?應該是這樣的:

1 -> 2 -> 3↖ list1 1 -> 2 -> 3 -> 4 -> 5 -> 6↖ result ↖ list2

由于鏈表是不可變的,因此我們必須把list1的所有元素復制為result的前部,但是list2完全可以直接作為另一個鏈表的尾部。因此,最后兩個鏈表連接后的結果會像上面所示。在這里,我們可以使用這樣的代碼完成這個功能:

public abstract class ImmutableList<T> : IEnumerable<T> {...public static ImmutableList<T> Create(params T[] elements){if (elements == null) throw new ArgumentNullException("elements");return Create(elements, Empty);}public static ImmutableList<T> Create(IEnumerable<T> elements){if (elements == null) throw new ArgumentNullException("elements");return Create(elements, Empty);}private static ImmutableList<T> Create(IEnumerable<T> elements, ImmutableList<T> tail){return NonEmptyImmutableList<T>.FromEnumerable(elements, tail);}public static ImmutableList<T> operator +(ImmutableList<T> headList, ImmutableList<T> tailList){...return Create(headList, tailList);}... }internal class NonEmptyImmutableList<T> : ImmutableList<T> {public static ImmutableList<T> FromEnumerable(IEnumerable<T> elements, ImmutableList<T> tail){NonEmptyImmutableList<T> result = null, last = null;foreach (var item in elements){var newNode = new NonEmptyImmutableList<T>(item, Empty);if (last == null){result = last = newNode;}else{last.m_tail = newNode;last = newNode;}}if (last != null){last.m_tail = tail;}return result ?? tail;}... }

具體的實現方式是NonEmptyImmutableList的FromEnumerable方法。這個方法有些“特別”,因為它直接修改了m_tail私有變量的值。這是因為,由于傳入的IEnumerable是單向的,但是構造一個鏈表時,使用“正常操作”只能“從后往前”構造。這里NonEmptyImmutableList算是“以權謀私”了一回,利用職權便利提高了“性能”。

ImmutableList的連接操作實現完成后,我們便可以為其添加一些額外的輔助方法了。如Filter:

public static class ImmutableListExtensions {public static ImmutableList<T> Filter<T>(this ImmutableList<T> source, Func<T, bool> predicate){if (source == null) throw new ArgumentNullException("source");if (predicate == null) throw new ArgumentNullException("predicate");if (source.IsEmpty) return source;return ImmutableList<T>.Create(source.Where(predicate));}... }

有了Filter之后,QuickSort便是輕而易舉的:

public static class ImmutableListExtensions {...public static ImmutableList<T> QuickSort<T>(this ImmutableList<T> list, Func<T, T, int> compare){if (list == null) throw new ArgumentNullException("list");if (compare == null) throw new ArgumentNullException("compare");return list.IsEmpty ? list :list.Tail.Filter(e => compare(e, list.Head) < 0).QuickSort(compare) +ImmutableList<T>.Create(list.Head) +list.Tail.Filter(e => compare(e, list.Head) >= 0).QuickSort(compare);} }

看一下,是不是和Haskell代碼的含義非常接近?

qsort [] = [] qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs)

使用一下:

var random = new Random(); var source = new List<int>(); for (int i = 0; i < 10; i++) source.Add(random.Next());var sourceList = ImmutableList<int>.Create(source); var sortedList = sourceList.QuickSort((x, y) => x - y);foreach (var i in sourceList) Console.WriteLine(i); Console.WriteLine(); foreach (var i in sortedList) Console.WriteLine(i);

至此,您有什么疑問嗎?本文所有的代碼可以訪問http://gist.github.com/179520。如果您感興趣的話,可以再試試看以下兩個問題。

  • ImmutableList的快速排序已經完成了,那么您是否可以嘗試著進行歸并排序(Merge Sort)?
  • 能否模擬ImmutableList構造一個ImmutableStack?我不是指“封裝ImmutableList”,而是直接編寫一個ImmutableStack,需要實現Pop,Push和Peek三種操作。
  • from:?http://blog.zhaojie.me/2009/09/functinal-list-quick-sort-answer.html

總結

以上是生活随笔為你收集整理的趣味编程:函数式链表的快速排序(参考答案)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。