堆排序:
与归并排序一样,但不同于插入排序的是,堆排序的时间复杂度为O(n*lgn);
而与插入排序一样,不同于归并排序的是,堆排序具有空间原址性。
因此,堆排序集合了归并排序与插入排序的优点。
算法导论上的代码:
HeapSort.h
#define PARENT(i) (i-1)/2
#define LEFTCHILD(i) i*2+1
#define RIGHTCHILD(i) (i+1)*2
void max_heapify(int* arr, int i);
void build_max_heap(int* arr, int num);
void heapSort(int* arr, int heapSize);
void max_heapify(int* arr, int i, int heapSize)
{
if (i > (heapSize / 2 - 1)) return;
int largestIndex = i;
if (arr[i] < arr[LEFTCHILD(i)])
largestIndex = LEFTCHILD(i);
if (RIGHTCHILD(i) <= heapSize-1 && arr[largestIndex] < arr[RIGHTCHILD(i)])
largestIndex = RIGHTCHILD(i);
if (largestIndex != i) //若largestIndex == i,说明以i为根的子树已经满足最大堆得性质了。
{
int temp = arr[largestIndex];
arr[largestIndex] = arr[i];
arr[i] = temp;
max_heapify(arr, largestIndex, heapSize); //此时,以largestIndex为根节点的子树未必满足最大堆性质,所以递归调用。
}
}
void build_max_heap(int* arr, int heapSize)
{
for (int i = (heapSize / 2 - 1); i >= 0; --i)
{
max_heapify(arr, i, heapSize);
}
}
void heapSort(int* arr, int heapSize)
{
build_max_heap(arr, heapSize);
for (int i = 1; i < heapSize; ++i)
{
int temp = arr[0];
arr[0] = arr[heapSize - i];
arr[heapSize - i] = temp;
max_heapify(arr, 0, heapSize-i);
}
}
快速排序:
一种最坏情况时间复杂度为O(n*n)的排序算法。但是快排通常是实际排序应用中最好的选择,因为它的平均性能好:期望时间复杂度为O(n*lgn),且隐含的常数因子非常小,同时也能进行原址排序。
QuickSort.h
int partition(int* arr, int p, int r);
int quickSort(int* arr, int p, int r);
int partition(int* arr, int p, int r)
{
int cmp = arr[r];
int j = p - 1;
for (int i = p; i < r; ++i)
{
if (arr[i] < cmp)
{
j++;
if (i != j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
arr[r] = arr[j + 1];
arr[j + 1] = cmp;
return j + 1;
}
int quickSort(int* arr, int p, int r)
{
if (p < r)
{
int q = partition(arr, p, r);
quickSort(arr, p, q - 1);
quickSort(arr, q + 1, r);
}
return 0;
}