# 基础排序算法

## 2. 插入排序（insertion sort）

void
InsertionSort(ElementType A[], int N)
{
int j, P;

ElementType Tmp;
for (P = 1; P < N; P++)
{
Tmp = A[P];
for (j = P; j > 0 && A[j - 1] > Tmp; j--)
A[j] = A[j - 1];
A[j] = Tmp;
}
}

，去掉常系数项和低阶项，时间复杂度为

## 4. 希尔排序（shellsort）

void
Shellsort(ElementType A[], int N)
{
int i, j, Increment;
ElementType Tmp;

for (Increment = N/2; Increment > 0; Increment /=2)
for (i = Increment; i < N; i++)
{
Tmp = A[i];
for(j = i; j > Increment; j -= Increment)
if(Tmp < A[j - Increment])
A[j] = A[j - Increment];
else
break;
A[j] = Tmp;
}
}

## 5. 堆排序（heapsort）

#define LeftChild(i) (2* (i) + 1)

void
PercDown(ElementType A[], int i, int N)
{
int Child;
ElementType Tmp;

for(Tmp = A[i]; LeftChild(i) < N; i = Child)
{
Child = LeftChild(i);
if(Child != N-1 && A[Child + 1] > A[Child])
Child++;
if(Tmp < A[Child])
A[i] = A[Child];
else
break;
}
A[i] = Tmp;
}

void
Heapsort(ElementType A[], int N)
{
int i;

for(i = N/2; i >= 0; i--)   /* BuildHeap */
PercDown(A, i, N);
for(i = N-1; i > 0; i--)
{
Swap(&A[0], &A[i]);     /* DeleteMax */
PercDown(A, 0, i);
}
}

## 6. 归并排序（mergesort）

/* Lpos = start of left half, Rpos = start of right half */
void
Merge(ElementType A[], ElementType TmpArray[],
int Lpos, int Rpos, int RightEnd)
{
int i, LeftEnd, NumElements, TmpPos;

LeftEnd = Rpos - 1;
TmpPos = Lpos;
NumElements = RightEnd - Lpos + 1;

/* main loop */
while(Lpos <= LefEnd && Rpos <= RightEnd)
if (A[Lpos] <= A[Rpos])
TmpArray[TmpPos++] = A[Lpos++];
else
TmpArray[TmpPos++] = A[Rpos++];
while(Lpos <= LeftEnd)
TmpArray[TmpPos++] = A[Lpos++];
while(Rpos <= RightEnd)
TmpArray[TmpPos++] = A[Rpos++];

/* copy TmpArray back */
for (i = 0; i < NumElements; i++, RightEnd--)
A[RightEnd] = TmpArray[RightEnd];
}

void
MSort(ElementType A[], ElementType TmpArray[],
int Left, int Right)
{
int Center;

if (Left < Right)
{
Center = (Left + Right) / 2;
MSort(A, TmpArray, Left, Center);
Msort(A, TmpArray, Center + 1, Right);
Merge(A, TmpArray, Left, Center + 1, Right);
}
}

void
Mergesort(ElementType A[], int N)
{
ElementType *TmpArray;

TmpArray = malloc(N * sizeof(ElementType));
if (TmpArray != NULL)
{
MSort(A, TmpArray, 0, N-1);
free(TmpArray);
}
else
FatalError("No space for tmp array!!!");
}

## 7. 快速排序（quicksort）

1. 如果中 元素个数是或者，则返回。
2. 中任一元素, 称之为枢纽元（pivot）。
3. 中其余元素）分成两个不相交的集合：
4. 返回

### 7.2 分割策略

1. 将枢纽元与最后的元素交换使得枢纽元离开要被分割的数据段。
2. 从第一个元素开始，从倒数第二个元素开始。
3. 分割阶段要做的就是把所有小元素移到数组的左边而把所有大元素移到数组的右边，小和大是相对于枢纽元而言的。
4. 的左边时，将右移，移过那些小于枢纽元的元素，并将左移，移过那些大于枢纽元的元素。
5. 停止时，指向一个大元素而指向一个小元素。如果的左边，那么将这两个元素互换（结果是小的元素左移，大的元素右移）。
6. 重复(4)和(5)，直到彼此交错为止。此时，已经交错，故不再互换。
7. 分割的最后一步是将枢纽元所指向的元素交换。

### 7.4 快速排序示例

void
Quicksort(ElementType A[], int N)
{
Qsort(A, O, N - 1);
}

ElementType
Median3(ElementType A[], int Left, int Right)
{
int Center = (Left + Right) / 2;

if(A[Left] > A[Center])
Swap(&A[Left], &A[Center]);
if(A[Left] > A[Right])
Swap(&A[Left], &A[Right]);
if(A[Center] > A[Right])
Swap(&A[Center], &A[Right]);

/* Invariant: A[Left] <= A[Center] <= A[Right] */
Swap(&A[Center], &A[Right - 1]);    /* Hide pivot */
return A[Right - 1];                /* Return pivot */
}

#define Cutoff (3)

void
Qsort(ElementType A[], int Left, int Right)
{
int i, j;

ElementType Pivot;

if (Left + Cutoff <= Right)
{
Pivot = Median3(A, Left, Right);
i = Left; j = Right - 1;
for (;;)
{
while(A[++i] < Pivot) {}
while(A[--j] > Pivot) {}
if (i < j)
Swap(&A[i]), &A[j];
else
break;
}
Swap(&A[i], &A[Right - 1]); /* Restore pivot */

Qsort(A, Left, i - 1);
Qsort(A, i + 1, Right);
}
else /* Do an insertion sort on the subarray */
InsertionSort(A + Left, Right - Left + 1);
}

## 9. 排序的一般下界

决策树(decision tree)是用于证明下界的抽象概念。它是一棵二叉树，每个节点表示在元素之间一组可能的排序，它与已经进行的比较一致。比较的结果是树的边。通过只使用比较进行排序的每一种算法都可以用决策树表示。当然，只有输入数据非常少的情况下画决策树才是可行的。由排序算法所使用的比较次数等于最深的树叶的深度

• 多路合并
• 多相合并
• 替换选择

## 12. 总结

N 插入排序

10 0.00044 0.00041 0.00057 0.00052 0.00046
100 0.00675 0.00171 0.00420 0.00284 0.00244
1000 0.59564 0.02927 0.05565 0.03153 0.02587
10000 58.864 0.42998 0.71650 0.36765 0.31532
100000 NA 5.7298 8.8591 4.2298 3.5882
1000000 NA 71.164 104.68 47.065 41.282