/*
* sort.cpp
*/
#include
#include "fatal.h"
#include "sort.h"
void Swap(ElementType *Lhs, ElementType *Rhs)
{
/* if Lhs && Rhs point to same variable, *Lhs && *Rhs will be all 0 */
if (Lhs == Rhs)
{
return;
}
*Lhs ^= *Rhs;
*Rhs ^= *Lhs;
*Lhs ^= *Rhs;
}
/*---------------------------InsertionSort------------------------------*/
/*
* For pass P = 1 through N - 1, insertion sort ensures that
* elements in position 0 through P are in sorted order.
* In Pass P, we move the element in position P left until
* its right place is found among the first P + 1 elements.
*/
void InsertionSort(ElementType A[], int N)
{
int j, P;
ElementType Tmp;
/* The element in position P is saved in Tmp, and all larger elements */
/* (prior to position P) are moved one spot to the right. */
/* Then Tmp is placed in the correct spot. */
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;
}
}
/*---------------------------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;
}
}
}
/*---------------------------HeapSort------------------------------*/
/*
* The array for HeapSort contains data from position 0.
*/
#define LeftChild(i) (2 * (i) + 1)
static void PercolateDown(ElementType A[], int i, int N)
{
int Child;
ElementType Tmp;
/* Two comparisons: one to find the smaller child */
/* and one to compare the smaller child with the node*/
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;
/* Build heap */
for (i = N / 2; i >= 0; --i)
{
PercolateDown(A, i, N);
}
/* Delete Max */
for (i = N - 1; i > 0; --i)
{
Swap(&A[0], &A[i]);
PercolateDown(A, 0, i);
}
}
/*---------------------------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 <= LeftEnd && Rpos <= RightEnd)
{
if (A[Lpos] <= A[Rpos])
{
TmpArray[TmpPos++] = A[Lpos++];
}
else
{
TmpArray[TmpPos++] = A[Rpos++];
}
}
while (Lpos <= LeftEnd) /* Copy rest of first half */
{
TmpArray[TmpPos++] = A[Lpos++];
}
while (Rpos <= RightEnd) /* Copy rest of second half */
{
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 = (ElementType *)malloc(N * sizeof(ElementType));
if (TmpArray != NULL)
{
MSort(A, TmpArray, 0, N - 1);
free(TmpArray);
}
else
{
FatalError("No space for tmp array!");
}
}
/*-------------------QuickSort && QSelect---------------------------*/
/*
* Return median of Left, Center, and Right.
* Order these and hide the pivot.
*/
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)
{
/* Place the pivot in A[Right - 1] and initialize i and j to */
/* Left + 1 and Right -2 */
Pivot = Median3(A, Left, Right);
i = Left;
j = Right - 1;
while (1)
{
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);
}
}
void QuickSort(ElementType A[], int N)
{
QSort(A, 0, N - 1);
}
/*
* Places the kth smallest element in the kth position.
* Because arrays start at 0, this will be index k - 1.
*/
void QSelect(ElementType A[], int k, 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 */
if (k <= i)
{
QSelect(A, k, Left, i - 1);
}
else if (k > i + 1)
{
QSelect(A, k, i + 1, Right);
}
}
else
{
/* Do an insertion sort on the subarray */
InsertionSort(A + Left, Right - Left + 1);
}
}
/*-------------------RadixSort Inefficient------------------------*/
/*
* Digit = Num / (Base ^ SpecifiedExponent) % Base
*/
int GetDigit(ElementType Num, int Base, int SpecifiedExponent)
{
int i, Tmp;
Tmp = 1;
for (i = 0; i < SpecifiedExponent; ++i)
{
Tmp *= Base;
}
return (Num / Tmp % Base);
}
#define BASE (10)
#define MAX_EXPONENT (10)
/*
* We assume elements in array A not bigger than 10 ^ 10.
* And all elements is in base 10.
*/
void RadixSort(ElementType A[], int N)
{
int i, j, k, Exponent, Digit;
ElementType *Buckets[BASE];
for (i = 0; i < BASE; ++i)
{
/* Alloc one more space for Count elements in Bucket */
Buckets[i] = (ElementType *)malloc(sizeof(ElementType) * (N + 1));
if (Buckets[i] == NULL)
{
FatalError("Out of space!");
}
Buckets[i][N] = 0;
}
/* BucketSort on the least significant digit, than two least significant digit, */
/* until most significant digit */
for (Exponent = 0; Exponent < MAX_EXPONENT; ++Exponent)
{
/* Place N elements in Buckets */
for (i = 0; i < N; ++i)
{
Digit = GetDigit(A[i], BASE, Exponent);
j = Buckets[Digit][N]++;
Buckets[Digit][j] = A[i];
}
/* When all elements are placed in Buckets[0], terminated */
if (Buckets[0][Digit] == N)
{
break;
}
/* Retrieve elements from Buckets(totally BASEs) orderly, into A[] */
for (i = 0, k = 0; i < BASE; ++i)
{
for (j = 0; j < Buckets[i][N]; ++j)
{
A[k++] = Buckets[i][j];
}
/* Reset counter */
Buckets[i][N] = 0;
}
}
for (i = 0; i < BASE; ++i)
{
free(Buckets[i]);
}
}