排序问题:
In:n个数<a1, a2, ... , an>;
Out:输入序列的一个排列(重新排序,升或降)<a1', a2', ... an'>,使得a1'<=a2'<=...<=an'。
1. 插入排序:这是一个对少量元素进行排序的有效算法。
工作机理:
与人平时打牌时整理手中的牌的做法相似,在开始摸牌时,我们左手是空的,接着一次从桌面上摸起一张牌,并将牌插入到左手一把牌中的正确位置上。为了找到正确位置,要将它与手中已有的每一张牌从右到左进行比较。关键要知道的是,左手中的牌都是已排好序的。
最坏情况运行时间Θ(n^2)
![]()
InsertionSorting
1
public 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[0
j-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
1
public 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
1
public 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
1
public 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
1
public 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)