目录
1.1二叉树的顺序结构
普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。
1.2堆的概念及结构
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储
在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
1.3堆的实现
1.3.1堆向下调整算法
现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。
向下调整算法有一个前提条件:左右子树必须是一个堆,才能调整。
代码实现:
// n指数组元素个数,root指初始的根节点下标。
//向下调整算法
//示例为大堆,(想变为小堆只要选出小孩子,将大父亲换下去)
//除了第一个数据,其他的都是正确的堆形式,可以用向下调整算法。变成正确的完整的堆
void ADjustDown(HPDatatype*arr, int n, int root)
{
int parents = root;
int child = parents * 2 + 1; //二叉树的左孩子是双亲节点的二倍加1
//二叉树的右孩子是双亲节点的二倍加2
while (child < n) //一次交换是不够的,可能会破坏下面的堆 。所以直到第一个数据找到合适的位置才停止。
{
if (arr[child] < arr[child+1] && child + 1 < n)//选出大孩子, 防止+1越界。
{
child++;
}
if (arr[child] > arr[parents]) //如果父亲小于孩子则交换,
{
swap(&arr[child], &arr[parents]);
parents = child; //下一次循环进来, 继续向该节点的孩子进行检测,是否破坏了原本的堆,所以要调整下标
child = parents * 2 + 1;
}
else
{
break; //找到了合适的位置。
}
}
}
1.3.2堆的创建
下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始向下调整算法,一直调整到根节点的树,就可以调整成堆。
代码实现:
void MyHeapCreate(Heap *php, HPDatatype *arr, int n)
{
assert(php);
//初始化
if (php != NULL)
{
//======================如果录入的数据是在单独接口录入,录入的数据是局部变量时,采用malloc保证生命周期。记得释放(Destory)
php->_arr = (HPDatatype*)malloc(sizeof(HPDatatype)*n);
memcpy(php->_arr, arr, sizeof(HPDatatype)*n);
//======================
//php->_arr = arr; //数据是使用时的全局变量时。直接指向即可,也不需要释放(Destory)。
php->_size = n;
php->_capacity = n;
}
//构建堆
//从最后一个双亲节点开始向下调整,直至第一个。当所有的双亲节点都调整好了,就是堆了。
int lastparents = (n - 1 - 1) / 2;//为什么减两次一呢? lastchild=n-1,之前证明了child=parents*2+1; lastparents=(lastchild-1)/2;
int i = 0;
for (i = lastparents; i >= 0; i--) // i要等于0,因为数组下标为0,而且a【0】是第一个双亲节点,一定要调整
{
ADjustDown(php->_arr, n, i);
}
}
1.3.2堆排序算法
创建好堆以后,我们会发现,堆顶这个数据是这个堆的最值,(大根堆为最大,小根堆为最小)我们将这个最值与最后一个数组元素交换,然后无视掉它,你会发现,刚好满足向下调整算法,使用向下调整算法后,又构造了一个新的堆顶2,再交换,向下调整。直到只剩一个节点,无法构成堆。
代码实现:
// 对数组进行堆排序
void HeapSort(HPDatatype *arr, int n)
{
int lastparents = (n - 1 - 1) / 2;