概念:

堆:从逻辑角度上来看是一棵完全二叉树,从物理结构来看,一般是顺序存储结构(数组)。

堆保证一种性质:堆中某个节点的值总是不大于或不小于其父节点的值;             我们通常使用的都是二叉树,二叉堆,因此用二叉堆进行讲解。

分类:大根堆(根结点的权值大于等于子结点的权值),小根堆。

基本数据结构:

  • 因为堆是完全二叉树,完全能够使用数组来实现。
1 vector<int> heap;  // 最好heap[0]插入一个不用的值,保持2n和2n+1的数学关系
2 int heap[maxn];

两个基本的操作:

  • Top-Down调整堆结构。       将根结点和子结点中最大/小的值进行比较和替换。
  • 时间复杂度:O(logN)         
  • 适用于建堆和删除堆中元素。       
 1 //对[low,high)进行调整;
 2 //以大根堆为例,自顶向下进行调整
 3 void DownAdjust(int low,int high){
 4     int i=low,j=i*2;
 5     // 存在孩子结点
 6     while(j<high){
 7         // 获得孩子结点中最大的值
 8         if(j+1<high && heap[j+1]>heap[j]){
 9             j++;
10         }
11         // 如果孩子结点的值比父节点的值大,进行替换
12         if(heap[j]>heap[i]){
13             swap(heap[i],heap[j]);
14             i=j;
15             j=i*2;
16         }
17         else{
18             break;
19         }
20     }
21 }
  • Down-Top调整堆结构。   只需要将插入的点和父结点进行比较。
  • 适合于堆中插入元素。       
 1 void UpAdjust(int low,int high){
 2      int i=high,j=high/2;
 3      while(i!=low){
 4         if(heap[j]<heap[i]){
 5              swap(heap[i],heap[j]);
 6              i=j;
 7              j/=2;
 8         }
 9          else{
10              break;  //只要有一个大于,后面一定不需要再次调整;
11         }
12      }
13 }

堆的操作:

  • 建堆:如果有n个点,放入数组中,对下标为n/2(向下取整)的结点开始,到下标为1的点,进行调整堆结构。(从上至下)(保证每个小堆成立,然后再建立大堆)。    如果采用UpAdjust,采用后n/2元素进行建堆。
1 void CreateHeap(){
2     for(int i=n/2;i>=1;i++){
3         DownAdjust(i,n);
4     }
5 }
  •  删除堆顶元素:将最后一个元素移到开头,让后重新调整一次堆,即可重新得到堆。 O(logN)
1 void DeleteTop(){
2     heap[1]=heap[n--];
3     DownAdjust(1,n);
4 }
  • 插入结点:将元素插入在最后,然后调整一次堆,即可得到堆。 O(logN)
1 void Insert(int x){
2     heap[++n]=x;
3     UpAdjust(1,n);
4 }
  • 堆排序:一个堆只能保证第一个元素为最大/最小,并不能保证依次递增/递减,可以通过使用高效的堆排序算法,O(NlogN)。 

算法思路:(假设下标从1-N)

  1. swap(heap[1],heap[N])  // 将最值换到最后
  2. DownAdjust(1,N-1);   // 进行重新整理,那么这样N-1个元素重新形成堆,依次下去;
1 void HeapSort(){
2     CreateHeap();
3     for(int i=N;i>1;i++){
4         swap(heap[1],heap[i]);
5         DownAdjust(1,N-1);
6     )
7 }
原文地址:https://www.cnblogs.com/yy-1046741080/p/11475796.html