#include<iostream>
using namespace std;
//堆是一颗完全二叉树,如果父亲结点大于等于孩子结点,那么就是大顶堆;如果父亲结点小于等于孩子结点,那么就是小顶堆
//这里以大顶堆为例
const int maxn=100;
int heap[maxn],n=10;
//向下调整,low指的是欲调整的数组下标,high为最后一个元素的数组下标
void downAdjust(int low,int high)
{
int i=low,j=i*2;//用j存储左孩子
while(j<=high)//判断是否有孩子结点,如果没有,则可以跳过
{
//判断有没有右孩子,如果右,再判断右孩子和左孩子之间的大小,用j存储较大结点的下标
if(j+1<=high&&heap[j+1]>heap[j])
{
j=j+1;
}
//判断孩子结点和父亲结点的大小,如果孩子结点比父亲结点大,那么交换它们的值,接着将要比较的下标移动到它的左孩子
if(heap[j]>heap[i])
{
swap(heap[j],heap[i]);
i=j;
j=j*2;
}
else
{
break;
}
}
}
//建堆
//建堆其实就是不断地向下调整,其中只需要将非叶子结点向下调整即可
//在完全二叉树中,非叶子结点的个数为n/2,叶子结点的个数为n-n/2
void createHeap()
{
for(int i=n/2;i>=1;i--)
{
downAdjust(i,n);
}
}
//删除堆中最大元素(堆顶元素),将堆的最后一个元素覆盖堆顶元素,然后进行向下调整
void deleteTop()
{
heap[1]=heap[n--];
downAdjust(1,n);
}
//插入
//将要插入的元素放在堆中的最后一个位置上,然后进行向上调整,直到到堆顶或者父亲结点的权值较大为止
//low一般指的是1,high指的是欲调整结点的数组下标
void upAdjust(int low,int high)
{
int i=high,j=high/2;
while(j>=low)//保证父亲结点在堆的范围内
{
if(heap[i]>heap[j])
{
swap(heap[j],heap[i]);
i=j;
j=i/2;
}
else
{
break;
}
}
}
void insert(int x)
{
heap[++n]=x;
upAdjust(1,n);
}
//堆排序
//因为建的是大顶堆,所以这里的堆排序就是将它进行从小到大进行排序
void heapsort()
{
for(int i=n;i>1;i--)
{
//堆顶是最大元素,所以将堆顶元素和堆的最后一个元素进行交换
swap(heap[i],heap[1]);
//交换完之后,再对堆顶元素进行向下调整
//最后一个元素是最大的,所以对前面n-1个元素进行调整
downAdjust(1,i-1);
}
}
堆的几个基本操作以及堆排序
最新推荐文章于 2024-07-18 17:57:16 发布