排序问题:
In:n个数<a1, a2, ... , an>;
Out:输入序列的一个排列(重新排序,升或降)<a1', a2', ... an'>,使得a1'<=a2'<=...<=an'。
1. 插入排序:这是一个对少量元素进行排序的有效算法。
工作机理:
与人平时打牌时整理手中的牌的做法相似,在开始摸牌时,我们左手是空的,接着一次从桌面上摸起一张牌,并将牌插入到左手一把牌中的正确位置上。为了找到正确位置,要将它与手中已有的每一张牌从右到左进行比较。关键要知道的是,左手中的牌都是已排好序的。
最坏情况运行时间Θ(n^2)
InsertionSorting
1public static void InsertionSorting(int []array)
2 {
3 int key;
4 int index;
5 for (int j = 1; j < array.Length; j++)
6 {
7 key = array[j];
8 //Insert array[j] into the sorted sequence array[0j-1].
9 index = j - 1;
10 while (index >= 0 && array[index] > key)
11 {
12 array[index + 1] = array[index];
13 index--;
14 }
15 array[index + 1] = key;
16 }
17 }
2. 冒泡排序:一种简单流行的排序算法,它重复地交换相邻的两个反序元素。
最坏情况运行时间Θ(n^2)
BubbleSorting
1public static void BubbleSorting(int[] array)
2 {
3 int key;
4 for (int j = 0; j < array.Length; j++)
5 {
6 for (int index = array.Length - 1; index > j; index--)
7 {
8 if (array[index] < array[index - 1])
9 {
10 key = array[index];
11 array[index] = array[index - 1];
12 array[index - 1] = key;
13 }
14 }
15 }
16 }
3. 合并排序:
渐近运行时间Θ(nlgn)
MergeSorting
1public static void MergeSorting(int[] array)
2 {
3 MergeSorting(array, 0, array.Length - 1);
4 }
5
6 public static void MergeSorting(int[] array, int p, int r)
7 {
8 if (p < r)
9 {
10 int q = (p + r) / 2;
11 MergeSorting(array, p, q);
12 MergeSorting(array, q + 1, r);
13 Merge(array, p, q, r);
14 }
15 }
16
17 public static void Merge(int[] array, int p, int q, int r)
18 {
19 int n1 = q - p + 1;
20 int n2 = r - q;
21 int[] L = new int[n1 + 1];
22 int[] R = new int[n2 + 1];
23 int i, j;
24 for (i = 0; i < n1; i++)
25 {
26 L[i] = array[p + i];
27 }
28 q += 1;
29 for (j = 0; j < n2; j++)
30 {
31 R[j] = array[q + j];
32 }
33 L[n1] = R[n2] = int.MaxValue;
34
35 i= j = 0;
36 for (int k = p; k <= r; k++)
37 {
38 if (L[i] <= R[j])
39 {
40 array[k] = L[i];
41 i++;
42 }
43 else
44 {
45 array[k] = R[j];
46 j++;
47 }
48 }
49 }
4. 快速排序:
最坏情况运行时间Θ(n^2)
平均运行时间Θ(nlgn)
分治过程三步骤:
分解:数组A[p..r]被划分成两个(可能空)子数组A[p..q-1]和A[p+1..r],使得A[p..q-]中的每个元素都小于等于A[q],而且小于等于A[q+1..r]中的元素。q也是在划分过程中计算出来。
解决:通过递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]排序。
合并:因为两个子数组是就地排序的,所以整个数组A[p..r]已排序。
QuickSorting
1public static void QuickSorting(int[] array, int p, int r)
2 {
3 if (p < r)
4 {
5 int q = Partition(array, p, r);
6 QuickSorting(array, p, q - 1);
7 QuickSorting(array, q + 1, r);
8 }
9 }
10
11 /**//// <summary>
12 /// 在子数组中,以A[r]为标志,将小于等于A[r]的放在它的左边,将大于它的放在右边;返回最后A[r]的位置
13 /// </summary>
14 /// <param name="array"></param>
15 /// <param name="p"></param>
16 /// <param name="r"></param>
17 /// <returns></returns>
18 public static int Partition(int[] array, int p, int r)
19 {
20 int index = p - 1;
21 int key;
22 for (int j = p; j < r; j++)
23 {
24 if (array[j] <= array[r])
25 {
26 index++;
27 key = array[j];
28 array[j] = array[index];
29 array[index] = key;
30 }
31 }
32 index++;
33 key = array[r];
34 array[r] = array[index];
35 array[index] = key;
36 return index;
37 }
快速排序随机版:在此算法中,不是始终采用A[r]作为主元,而是从子数组A[p..r]中随机选一个元素。
由于主元元素是随机的,所以在平均情况下,对输入数组的划分能够比较对称。
RandomizedQuickSorting
1public static void RandomizedQuickSorting(int[] array, int p, int r)
2 {
3 if (p < r)
4 {
5 int q = RandomizedPartition(array, p, r);
6 RandomizedQuickSorting(array, p, q - 1);
7 RandomizedQuickSorting(array, q + 1, r);
8 }
9 }
10
11 public static int RandomizedPartition(int[] array, int p, int r)
12 {
13 Random rnd = new Random((int)DateTime.Now.Ticks);
14 int index = rnd.Next(p, r);
15 exChange(ref array[index], ref array[r]);
16 return Partition(array, p, r);
17 }
18
19 private static void exChange(ref int a, ref int b)
20 {
21 int k = a;
22 a = b;
23 b = k;
24 }
5. 堆排序:
时间上限O(nlgn)