1.随机排列数组
很多随机算法都通过对给定的输入变换排列以使输入随机化。一种通常的方法是为数组的每个元素赋一个随机的优先级,然后根据优先级对数组中的元素排序。另一个更好地办法是原址排列给定数组,将原数组随机排列。
2.堆
二叉堆是一个数组,可以看成是一个近似的完全二叉树,除了底层之外,其余层都是满的。表示堆的数组一般有两个属性,数组元素个数A.length以及有多少堆元素在该数组中A.heap-size,0≤A.heap-size≤A.length。将根节点记为A[1],可以方便计算某一结点i的父结点以及左右孩子的下标:
PARENT(i)
return i/2
LEFT(i)
return 2i
RIGHT(i)
return 2i+1
大多数计算机中,左移一位可以代表乘以2,右移一位可以代表除以2,取商的整数部分,因此上述函数通常采用宏或者内联函数实现。
堆分为最大堆和最小堆,最大堆是父结点大于孩子结点,根结点为最大值;最小堆相反,根结点为最小值。堆排序算法中采用最大堆,最小堆通常用于构造优先队列。
3.堆排序算法
对一个数组A进行排序,首先将这个数组构造成一个最大堆,A[1]为最大,为了方便处理,将A[1]与A[n]互换,并从堆中去掉A[n],A.heap-size减一,由于去掉根结点,最大堆性质可能被破坏,因此要重新维护最大堆,然后继续将A[1]与A[n-1]互换,重复上述步骤,直到A.heap-size降到2,排序完成。
//堆排序算法
//数组是从下标0开始的,因此需要先加1,方便处理
#define PARENT(x) ((x+1)>>1)-1
#define LEFT(x) ((x+1)<<1)-1
#define RIGHT(x) (x+1)<<1
//维护最大堆的性质
template<class T>
void maxHeapify(T a[], int i,int heapSize)
{
int l = LEFT(i);
int r = RIGHT(i);
int largest = i;
if (l < heapSize&&a[l] > a[i])
{
largest = l;
}
if (r < heapSize&&a[r] > a[largest])
{
largest = r;
}
if (largest != i)
{
T temp = a[i];
a[i] = a[largest];
a[largest] = temp;
maxHeapify(a, largest, heapSize);
}
}
//建堆
template<class T>
void buildMaxHeap(T a[],int n)
{
//采用自底向上的方法,数组在第(n / 2)-1个元素之后都为叶结点,单个元素不必执行maxHeapify函数
for (int i = (n / 2)-1; i >= 0; i--)
{
maxHeapify(a, i,n);
}
}
template<class T>
void heapSort(T a[],int n)
{
buildMaxHeap(a, n);
int heapSize = n;
T temp = 0;
for (int i = n - 1; i > 0; i--)
{
temp = a[0];
a[0] = a[i];
a[i] = temp;
heapSize -= 1;
maxHeapify(a, 0,heapSize);
}
}
maxHeapify函数运行时间为O(logn),buildMaxHeap函数运行时间为O(n),排序算法运行时间为O(nlogn)。
4.优先队列
一种用来维护由一组元素构成的集合S的数据结构,每个元素都有一个相关的值,成为关键字,最大优先队列应该支持以下操作:
INSERT(S,x):把元素x插入到集合S中。
MAXIMUN(S):返回S中具有最大关键字的元素。
EXTRACT-MAX(S):去掉并返回S中具有最大关键字的元素。
INCREASE-KEY(S,x,k):将元素x的关键字增加到k,k的值假设大于x.key。
相应的可以了解最小优先队列所支持的操作。具体的实现依赖于具体的应用,在后续的学习中应该可以看到,这里只简单了解一下。