最常见的几种排序算法原理和C#实现类库

本文尽量用简单直白通俗易懂深入浅出详实通透的手法将常见的几种排序算法的原理和代码呈现给众位,欢迎批评指教!

为简单起见,本文所述排序默认都以升序排序为例。(当然最后给出的源代码是升序降序都有的)

冒泡排序(Bubble sort)

冒泡排序每轮都得到数列中的最大值,同时将其置于最后,然后对剩余部分进行排序。

Bubble sort
 1         /// <summary>
 2         /// 当某轮比较没有发生移动时,就可以确定排序完成了
 3         /// <para>稳定排序</para>
 4         /// </summary>
 5         /// <typeparam name="T"></typeparam>
 6         /// <param name="arr"></param>
 7         private static void BubbleSortAscending1<T>(this IList<T> arr)
 8             where T : IComparable
 9         {
10             bool exchanges;
11             do
12             {
13                 exchanges = false;
14                 for (int i = 0; i < arr.Count - 1; i++)
15                 {
16                     if (arr[i].CompareTo(arr[i + 1]) > 0)
17                     {
18                         T temp = arr[i];
19                         arr[i] = arr[i + 1];
20                         arr[i + 1] = temp;
21                         //当某轮比较没有发生移动时,就可以确定排序完成了
22                         //否则应该继续排序
23                         exchanges = true;
24                     }
25                 }
26             } while (exchanges);
27         }

 

堆排序(Heap sort)

堆排序总是建立这样一个二叉树:其父结点总大于其子结点。

首先建堆。

每轮将根结点与最后一个结点互换,然后对剩余部分建堆。

Heap sort
 1         private static void HeapSortAscending1<T>(this IList<T> arr)
 2             where T : IComparable
 3         {
 4             for (int i = arr.Count / 2 - 1; i >= 0; i--)
 5             {
 6                 arr.HeapAdjustAscending1(i, arr.Count);
 7             }
 8             for (int i = arr.Count - 1; i > 0; i--)
 9             {
10                 T temp = arr[0];
11                 arr[0] = arr[i];
12                 arr[i] = temp;
13                 arr.HeapAdjustAscending1(0, i);
14             }
15         }
16         private static void HeapAdjustAscending1<T>(this IList<T> arr, int nonLeafNodeToBeAdjusted, int unRangedCount)
17             where T:IComparable
18         {
19             int leftChild = nonLeafNodeToBeAdjusted * 2 + 1;
20             int rightChild = nonLeafNodeToBeAdjusted * 2 + 2;
21             int max = nonLeafNodeToBeAdjusted;
22             if (nonLeafNodeToBeAdjusted < unRangedCount / 2) // 是非叶节点
23             {
24                 if (leftChild < unRangedCount && arr[leftChild].CompareTo(arr[max]) > 0)
25                 { max = leftChild; }
26                 if (rightChild < unRangedCount && arr[rightChild].CompareTo(arr[max]) > 0)
27                 { max = rightChild; }
28                 if (max!=nonLeafNodeToBeAdjusted)
29                 {
30                     T temp = arr[max];
31                     arr[max] = arr[nonLeafNodeToBeAdjusted];
32                     arr[nonLeafNodeToBeAdjusted] = temp;
33                     arr.HeapAdjustAscending1(max, unRangedCount);
34                 }
35             }
36         }

 

插入排序(Insertion sort)

每轮将数列未排序部分的第一个数字插入已排好的部分。

Insertion sort
 1         /// <summary>
 2         /// 插入排序算法
 3         /// <para>稳定排序</para>
 4         /// </summary>
 5         /// <typeparam name="T"></typeparam>
 6         /// <param name="arr"></param>
 7         private static void InsertionSortAscending1<T>(this IList<T> arr)
 8             where T : IComparable
 9         {
10             for (int i = 1; i < arr.Count; i++)
11             {
12                 T temp = arr[i];
13                 int j = i;
14                 while ((j > 0) && (temp.CompareTo(arr[j - 1]) < 0))
15                 {
16                     arr[j] = arr[j - 1];
17                     j--;
18                 }
19                 arr[j] = temp;
20             }
21         }

 

归并排序(Merge sort)

递归方法。将数列均分为前后两部分,分别对其进行归并排序,然后将分别完成排序的前后两部分归并。

Merge sort
 1         /// <summary>
 2         /// 归并排序,自顶向下的方法
 3         /// <para>稳定排序</para>
 4         /// </summary>
 5         /// <typeparam name="T"></typeparam>
 6         /// <param name="arr"></param>
 7         private static void MergeSortAscending1<T>(this IList<T> arr)
 8             where T : IComparable
 9         {
10             MergeSortAscending1_Split(arr, 0, arr.Count - 1);
11         }
12         private static void MergeSortAscending1_Split<T>(IList<T> arr, int first, int last)
13             where T : IComparable
14         {
15             if (first < last)
16             {
17                 int mid = (first + last) / 2;
18                 MergeSortAscending1_Split(arr, first, mid);
19                 MergeSortAscending1_Split(arr, mid + 1, last);
20                 MergeSortAscending1_Combine(arr, first, mid, last);
21             }
22         }
23         /// <summary>
24         /// 将两个有序的左右子表(以mid区分),合并成一个有序的表
25         /// </summary>
26         /// <typeparam name="T"></typeparam>
27         /// <param name="arr"></param>
28         /// <param name="first"></param>
29         /// <param name="mid"></param>
30         /// <param name="last"></param>
31         private static void MergeSortAscending1_Combine<T>(IList<T> arr, int first, int mid, int last)
32             where T : IComparable
33         {
34             int indexA = first;//左侧子表的起始位置
35             int indexB = mid + 1;//右侧子表的起始位置
36             //声明数组(暂存左右子表的所有有序数列)
37             //长度等于左右子表的长度之和。
38             IList<T> tempList = new List<T>(arr.AsEnumerable());
39 
40             int tempIndex = 0;
41             //进行左右子表的遍历,如果其中有一个子表遍历完,则跳出循环
42             while (indexA <= mid && indexB <= last)
43             {
44                 //此时左子表的数 <= 右子表的数
45                 if (arr[indexA].CompareTo(arr[indexB]) <= 0)
46                 {//将左子表的数放入暂存数组中,遍历左子表下标++
47                     tempList[tempIndex++] = arr[indexA++];
48                 }
49                 else//此时左子表的数 > 右子表的数
50                 {//将右子表的数放入暂存数组中,遍历右子表下标++
51                     tempList[tempIndex++] = arr[indexB++];
52                 }
53             }
54             //有一侧子表遍历完后,跳出循环,
55             //将另外一侧子表剩下的数一次放入暂存数组中(有序)
56             while (indexA <= mid)
57             {
58                 tempList[tempIndex++] = arr[indexA++];
59             }
60             while (indexB <= last)
61             {
62                 tempList[tempIndex++] = arr[indexB++];
63             }
64             //将暂存数组中有序的数列写入目标数组的指定位置,
65             //使进行归并的数组段有序
66             tempIndex = 0;
67             for (int i = first; i <= last; i++)
68             {
69                 arr[i] = tempList[tempIndex++];
70             }
71         }

 

快速排序(Quick sort)

选择一个数(比如第一个),依次右、左、右、左地将它右侧比它小的与之互换,将它左侧比它大的与之互换,最后这个数就排好了。

分别对这个数左右两部分进行快速排序。

Quick sort
 1         /// <summary>
 2         /// 快速排序算法
 3         /// <para>不稳定排序</para>
 4         /// </summary>
 5         /// <typeparam name="T"></typeparam>
 6         /// <param name="arr"></param>
 7         private static void QuickSortAscending1<T>(this IList<T> arr)
 8             where T : IComparable
 9         {
10             QuickSortAscending1_Do(arr, 0, 0, arr.Count - 1);
11         }
12         private static void QuickSortAscending1_Do<T>(IList<T> arr, int indexOfRightPlaceToFind, int first, int last)
13             where T : IComparable
14         {
15             if (first < last)
16             {
17                 int rightPlace = QuickSortAscending1_Find(indexOfRightPlaceToFind, arr, first, last);
18                 if (first + 1 < last)
19                 {
20                     QuickSortAscending1_Do(arr, first, first, rightPlace - 1);
21                     QuickSortAscending1_Do(arr, rightPlace + 1, rightPlace + 1, last);
22                 }
23             }
24         }
25         private static int QuickSortAscending1_Find<T>(int indexOfRightPlaceToFind, IList<T> arr, int first, int last)
26             where T : IComparable
27         {
28             bool searchRight = true;
29             int indexOfLeftSearch = first;
30             int indexOfRightSearch = last;
31             do
32             {
33                 if (searchRight)
34                 {
35                     while (arr[indexOfRightPlaceToFind].CompareTo(arr[indexOfRightSearch]) <= 0)
36                     {
37                         indexOfRightSearch--;
38                         if (indexOfRightPlaceToFind == indexOfRightSearch)
39                         {
40                             searchRight = false;
41                             break;
42                         }
43                     }
44                     if (searchRight)
45                     {
46                         T temp = arr[indexOfRightPlaceToFind];
47                         arr[indexOfRightPlaceToFind] = arr[indexOfRightSearch];
48                         arr[indexOfRightSearch] = temp;
49                         indexOfRightPlaceToFind = indexOfRightSearch;
50                         searchRight = false;
51                     }
52                 }
53                 else
54                 {
55                     while (arr[indexOfRightPlaceToFind].CompareTo(arr[indexOfLeftSearch]) >= 0)
56                     {
57                         indexOfLeftSearch++;
58                         if (indexOfRightPlaceToFind == indexOfLeftSearch)
59                         {
60                             searchRight = true;
61                             break;
62                         }
63                     }
64                     if (!searchRight)
65                     {
66                         T temp = arr[indexOfRightPlaceToFind];
67                         arr[indexOfRightPlaceToFind] = arr[indexOfLeftSearch];
68                         arr[indexOfLeftSearch] = temp;
69                         indexOfRightPlaceToFind = indexOfLeftSearch;
70                         searchRight = true;
71                     }
72                 }
73             } while (indexOfLeftSearch < indexOfRightPlaceToFind || indexOfRightPlaceToFind < indexOfRightSearch);
74             return indexOfRightPlaceToFind;
75         }

 

选择排序(Selection sort)

每轮找到最小的数,与未排序部分的第一个互换。

Selection sort
 1         /// <summary>
 2         /// 选择排序算法
 3         /// <para>不稳定排序</para>
 4         /// </summary>
 5         /// <typeparam name="T"></typeparam>
 6         /// <param name="arr"></param>
 7         private static void SelectionSortAscending1<T>(this IList<T> arr)
 8             where T : IComparable
 9         {
10             for (int i = 0; i < arr.Count - 1; i++)
11             {
12                 int min = i;
13                 for (int j = i + 1; j < arr.Count; j++)
14                 {
15                     if (arr[j].CompareTo(arr[min]) < 0)
16                     {
17                         min = j;
18                     }
19                 }
20                 if (min != i)
21                 {
22                     T temp = arr[i];
23                     arr[i] = arr[min];
24                     arr[min] = temp;
25                 }
26             }
27         }

 

希尔排序(Shell sort)

缩小增量法。从大到1设置一系列增量,将序号之差等于增量的数字进行之间插入排序。

Shell sort
 1         /// <summary>
 2         /// 希尔排序算法
 3         /// <para>不稳定排序</para>
 4         /// </summary>
 5         /// <typeparam name="T"></typeparam>
 6         /// <param name="arr"></param>
 7         private static void ShellSortAscending1<T>(this IList<T> arr)
 8             where T : IComparable
 9         {
10             int inc;
11             for (inc = 1; inc <= arr.Count / 9; inc = 3 * inc + 1) ;
12             for (; inc > 0; inc /= 3)
13             {
14                 for (int i = inc + 1; i <= arr.Count; i += inc)
15                 {
16                     T temp = arr[i - 1];
17                     int j = i;
18                     while ((j > inc) && (temp.CompareTo(arr[j - inc - 1]) < 0))
19                     {
20                         arr[j - 1] = arr[j - inc - 1];
21                         j -= inc;
22                     }
23                     arr[j - 1] = temp;
24                 }
25             }
26         }

 

为了使用方便,我用如下的方式进行包装,这样就尽可能多的自动成为了可排序类型的扩展方法,并且不需要写 "using ...;"之类的东西,只需引用此类库就行了。

namespace System下的扩展排序算法
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Collections; 
  6 
  7 namespace System
  8 {
  9     /// <summary>
 10     /// 冒泡排序算法
 11     /// <para>稳定排序</para>
 12     /// </summary>
 13     public static partial class _BubbleSort
 14     {
 15         /// <summary>
 16         /// 冒泡排序(降序)
 17         /// 请勿传null给本函数,否则将发生异常
 18         /// <para>稳定排序</para>
 19         /// <para>冒泡排序(降序)原理:</para>
 20         /// <para>从左到右以此比较两个相邻的数,若左小右大顺序则交换一下。</para>
 21         /// <para>这样,当一轮比较结束,最小的数就排在了最右边。</para>
 22         /// <para>下一轮比较前N-1个数即可。</para>
 23         /// <para>经过N-1轮比较,数列就是大->小排序的了。</para>
 24         /// <para>改进的冒泡排序:当某轮比较没有发生移动时,就可以确定排序完成了,从而减少了排序的轮数。</para>
 25         /// </summary>
 26         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
 27         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
 28         public static void BubbleSort<T>(this IList<T> arr)
 29             where T : IComparable
 30         {
 31             arr.BubbleSortDescending();
 32         }
 33         /// <summary>
 34         /// 冒泡排序
 35         /// 请勿传null给本函数,否则将发生异常
 36         /// <para>稳定排序</para>
 37         /// <para>冒泡排序(降序)原理:</para>
 38         /// <para>从左到右以此比较两个相邻的数,若左小右大顺序则交换一下。</para>
 39         /// <para>这样,当一轮比较结束,最小的数就排在了最右边。</para>
 40         /// <para>下一轮比较前N-1个数即可。</para>
 41         /// <para>经过N-1轮比较,数列就是大->小排序的了。</para>
 42         /// <para>改进的冒泡排序:当某轮比较没有发生移动时,就可以确定排序完成了,从而减少了排序的轮数。</para>
 43         /// </summary>
 44         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
 45         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
 46         /// <param name="descending">true为降序排序,false为升序排序</param>
 47         public static void BubbleSort<T>(this IList<T> arr, bool descending)
 48             where T : IComparable
 49         {
 50             if (descending)
 51                 arr.BubbleSortDescending();
 52             else
 53                 arr.BubbleSortAscending();
 54         }
 55     }
 56     /// <summary>
 57     /// 插入排序算法
 58     /// <para>稳定排序</para>
 59     /// </summary>
 60     public static partial class _InsertionSort
 61     {
 62         /// <summary>
 63         /// 插入排序(降序)
 64         /// 请勿传null给本函数,否则将发生异常
 65         /// <para>稳定排序</para>
 66         /// <para>插入排序(降序)原理:</para>
 67         /// <para>这是玩扑克牌的排序方法。</para>
 68         /// <para>一张一张地拿牌,拿到一张新牌时,就跟之前手里的牌从右到左地比较。</para>
 69         /// <para>若新牌大,则将此处的旧牌向右移动,原位置空了出来。</para>
 70         /// <para>当新牌不再大时,插入空位。</para>
 71         /// <para>当全部牌拿完,顺序就排好了。</para>
 72         /// </summary>
 73         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
 74         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
 75         public static void InsertionSort<T>(this IList<T> arr)
 76             where T : IComparable
 77         {
 78             arr.InsertionSortDescending();
 79         }
 80         /// <summary>
 81         /// 插入排序
 82         /// 请勿传null给本函数,否则将发生异常
 83         /// <para>稳定排序</para>
 84         /// <para>插入排序(降序)原理:</para>
 85         /// <para>这是玩扑克牌的排序方法。</para>
 86         /// <para>一张一张地拿牌,拿到一张新牌时,就跟之前手里的牌从右到左地比较。</para>
 87         /// <para>若新牌大,则将此处的旧牌向右移动,原位置空了出来。</para>
 88         /// <para>当新牌不再大时,插入空位。</para>
 89         /// <para>当全部牌拿完,顺序就排好了。</para>
 90         /// </summary>
 91         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
 92         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
 93         /// <param name="descending">true为降序排序,false为升序排序</param>
 94         public static void InsertionSort<T>(this IList<T> arr, bool descending)
 95             where T : IComparable
 96         {
 97             if (descending)
 98                 arr.InsertionSortDescending();
 99             else
100                 arr.InsertionSortAscending();
101         }
102     }
103     /// <summary>
104     /// 归并排序算法
105     /// <para>稳定排序</para>
106     /// </summary>
107     public static partial class _MergeSort
108     {
109         /// <summary>
110         /// 归并排序(降序)
111         /// 请勿传null给本函数,否则将发生异常
112         /// <para>稳定排序</para>
113         /// <para>归并排序(降序)原理:</para>
114         /// <para>利用了递归进行排序的方法。</para>
115         /// <para>将数列等分为左右两部分,先分别对其排序,再将分别排好的两个数列归并为一个排好的序列。</para>
116         /// <para>循环之,直到这部分只有1个数,那么这部分已经排好序了。</para>
117         /// <para>归并过程,将排好的两部分列队,从第一个数开始比较,将较大的放到最终要排的数列。</para>
118         /// <para>若最后剩下一些数,直接接到数列最后即可。</para>
119         /// </summary>
120         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
121         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
122         public static void MergeSort<T>(this IList<T> arr)
123             where T : IComparable
124         {
125             arr.MergeSortDescending();
126         }
127         /// <summary>
128         /// 归并排序
129         /// 请勿传null给本函数,否则将发生异常
130         /// <para>稳定排序</para>
131         /// <para>归并排序(降序)原理:</para>
132         /// <para>利用了递归进行排序的方法。</para>
133         /// <para>将数列等分为左右两部分,先分别对其排序,再将分别排好的两个数列归并为一个排好的序列。</para>
134         /// <para>循环之,直到这部分只有1个数,那么这部分已经排好序了。</para>
135         /// <para>归并过程,将排好的两部分列队,从第一个数开始比较,将较大的放到最终要排的数列。</para>
136         /// <para>若最后剩下一些数,直接接到数列最后即可。</para>
137         /// </summary>
138         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
139         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
140         /// <param name="descending">true为降序排序,false为升序排序</param>
141         public static void MergeSort<T>(this IList<T> arr, bool descending)
142             where T : IComparable
143         {
144             if (descending)
145                 arr.MergeSortDescending();
146             else
147                 arr.MergeSortAscending();
148         }
149     }
150     /// <summary>
151     /// 快速排序算法
152     /// <para>不稳定排序</para>
153     /// </summary>
154     public static partial class _QuickSort
155     {
156         /// <summary>
157         /// 快速排序(降序)
158         /// 请勿传null给本函数,否则将发生异常
159         /// <para>不稳定排序</para>
160         /// </summary>
161         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
162         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
163         public static void QuickSort<T>(this IList<T> arr)
164             where T : IComparable
165         {
166             arr.QuickSortDescending();
167         }
168         /// <summary>
169         /// 快速排序
170         /// 请勿传null给本函数,否则将发生异常
171         /// <para>不稳定排序</para>
172         /// </summary>
173         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
174         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
175         /// <param name="descending">true为降序排序,false为升序排序</param>
176         public static void QuickSort<T>(this IList<T> arr, bool descending)
177             where T : IComparable
178         {
179             if (descending)
180                 arr.QuickSortDescending();
181             else
182                 arr.QuickSortAscending();
183         }
184     }
185     /// <summary>
186     /// 选择排序算法
187     /// <para>不稳定排序</para>
188     /// </summary>
189     public static partial class _SelectionSort
190     {
191         /// <summary>
192         /// 选择排序(降序)
193         /// 请勿传null给本函数,否则将发生异常
194         /// <para>不稳定排序</para>
195         /// </summary>
196         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
197         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
198         public static void SelectionSort<T>(this IList<T> arr)
199             where T : IComparable
200         {
201             arr.SelectionSortDescending();
202         }
203         /// <summary>
204         /// 选择排序
205         /// 请勿传null给本函数,否则将发生异常
206         /// <para>不稳定排序</para>
207         /// </summary>
208         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
209         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
210         /// <param name="descending">true为降序排序,false为升序排序</param>
211         public static void SelectionSort<T>(this IList<T> arr, bool descending)
212             where T : IComparable
213         {
214             if (descending)
215                 arr.SelectionSortDescending();
216             else
217                 arr.SelectionSortAscending();
218         }
219     }
220     /// <summary>
221     /// 希尔排序算法
222     /// <para>不稳定排序</para>
223     /// </summary>
224     public static partial class _ShellSort
225     {
226         /// <summary>
227         /// 希尔排序(降序)
228         /// 请勿传null给本函数,否则将发生异常
229         /// <para>不稳定排序</para>
230         /// </summary>
231         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
232         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
233         public static void ShellSort<T>(this IList<T> arr)
234             where T : IComparable
235         {
236             arr.ShellSortDescending();
237         }
238         /// <summary>
239         /// 希尔排序
240         /// 请勿传null给本函数,否则将发生异常
241         /// <para>不稳定排序</para>
242         /// </summary>
243         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
244         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
245         /// <param name="descending">true为降序排序,false为升序排序</param>
246         public static void ShellSort<T>(this IList<T> arr, bool descending)
247             where T : IComparable
248         {
249             if (descending)
250                 arr.ShellSortDescending();
251             else
252                 arr.ShellSortAscending();
253         }
254     }
255     /// <summary>
256     /// 堆排序算法
257     /// <para>不稳定排序</para>
258     /// </summary>
259     public static partial class _HeapSort
260     {
261         /// <summary>
262         /// 堆排序(降序)
263         /// 请勿传null给本函数,否则将发生异常
264         /// <para>不稳定排序</para>
265         /// </summary>
266         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
267         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
268         public static void HeapSort<T>(this IList<T> arr)
269             where T : IComparable
270         {
271             arr.HeapSortDescending();
272         }
273         /// <summary>
274         /// 堆排序
275         /// 请勿传null给本函数,否则将发生异常
276         /// <para>不稳定排序</para>
277         /// </summary>
278         /// <typeparam name="T">实现了IComparable的类型<para>例如int</para></typeparam>
279         /// <param name="arr">请勿传null给本参数,否则将发生异常</param>
280         /// <param name="descending">true为降序排序,false为升序排序</param>
281         public static void HeapSort<T>(this IList<T> arr, bool descending)
282             where T : IComparable
283         {
284             if (descending)
285                 arr.HeapSortDescending();
286             else
287                 arr.HeapSortAscending();
288         }
289     }
290 }

 

介绍完毕,上源码:

https://files.cnblogs.com/bitzhuwei/SmileWei.Sorting.rar

您可以在GitHub上下载最新的源码(https://github.com/bitzhuwei/SortingExtension

posted @ 2012-10-27 17:08  BIT祝威  阅读(4050)  评论(4编辑  收藏  举报
canvas start.

canvas end.