PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)

 
 堆的详细创建过程:参考: https://www.jianshu.com/p/21bef3fc3030
 
 
明白堆的详细创建过程的前提是要理解Shift Down。
PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第1张图片
 

但是这明显不符合最大堆的定义,所以我们需要让该完全二叉树转换成最大堆!怎么转换成一个最大堆呢?
  最大堆有一个特点就是 其各个子树都是一个最大堆,那么我们就可以从把最小子树转换成一个最大堆,然后依次转换它的父节点对应的子树,直到最后的根节点所在的整个完全二叉树变成最大堆。那么从哪一个子树开始调整?

 

我们从该完全二叉树中的最后一个非叶子节点为根节点的子树进行调整,然后依次去找倒数第二个倒数第三个非叶子节点...

具体步骤

在做最大堆的创建具体步骤中,我们会用到最大堆删除操作中结点位置互换的原理,即关键字值较小的结点会做下沉操作

  • 1)、就如同上面所说找到二叉树中倒数第一个非叶子结点87,然后看以该非叶子结点为根结点的子树。查看该子树是否满足最大堆要求,很明显目前该子树满足最大堆,所以我们不需要移动结点。该子树最大移动次数为1
     
    PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第2张图片
     
  • 2)、现在来到结点30,明显该子树不满足最大堆。在该结点的子结点较大的为72,所以结点72和结点30进行位置互换。该子树最大移动次数为1
     
    PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第3张图片
     
  • 3)、同样对结点83做类似的操作。该子树最大移动次数为1
     
    PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第4张图片
     
  • 4)、现在来到结点43,该结点的子结点有{87,38,9},对该子树做同样操作。由于结点43可能是其子树结点中最小的,所以该子树最大移动次数为2
     
    PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第5张图片
     
  • 5)、结点66同样操作,该子树最大移动次数为2
     
    PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第6张图片
     
  • 6)、最后来到根结点79,该二叉树最高深度为4,所以该子树最大移动次数为3
     
    PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第7张图片
     

自此通过上诉步骤创建的最大堆为:


 
PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第8张图片
 

所以从上面可以看出,该二叉树总的需要移动结点次数最大为:10

PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程)_第9张图片

 

 

#include 
#include 
#include 
#include 
using namespace std;
const int N = 111;
int origin[N],tempOri[N],changed[N];//原始数组,原始数组备份及目标数组
int n;//元素个数
bool isSame(int A[],int B[]){
    for(int i=1;i<=n;++i){
        if(A[i] != B[i]){
            return false;
        }
    }
    return true;
}
bool showArray(int A[]){
    for(int i=1;i<=n;++i){
        printf("%d",A[i]);
        if(i<n){
            printf(" ");
        }
    }
}
bool insertSort(){//插入排序
    bool flag =false;
    for(int i=2;i<=n;++i){
        if(i != 2 && isSame(tempOri,changed)){
            flag = true;
        }
        //插入部分直接用sort代替
        sort(tempOri,tempOri + i + 1);
        if(flag == true){
            return true;
        }
    }
    return false;
}

//对heap数组在[low,high]范围进行调整
void downAdjust(int low,int high){
    int i = low,j = i * 2;
    while(j <= high){//存在孩子节点
        if(j + 1 <= high && tempOri[j+1] > tempOri[j]){
            j = j + 1;
        }
        if(tempOri[j] > tempOri[i]){
            swap(tempOri[j],tempOri[i]);
            i = j;
            j = i * 2;
        }else{
            break;
        }
    }
}
void heapSort(){
    bool flag = false;
    for(int i=n /2;i>=1;i--){//建堆
        downAdjust(i,n);
    }
    for(int i=n;i>1;--i){
        if(i != n && isSame(tempOri,changed)){
            flag = true;
        }
        swap(tempOri[i],tempOri[1]);
        downAdjust(1,i-1);//调整堆顶
        if(flag == true){
            showArray(tempOri);
            return;
        }
    }
    
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&origin[i]);
        tempOri[i] = origin[i];
    }
    for(int i=1;i<=n;++i){
        scanf("%d",&changed[i]);
    }
    if(insertSort()){
        printf("Insertion Sort\n");
        showArray(tempOri);
    }else{
        printf("Heap Sort\n");
        for(int i=1;i<=n;++i){//还原tempOri数组
            tempOri[i] = origin[i];
        }
        heapSort();
    }
    system("pause");
    return 0;
}

 

你可能感兴趣的:(PAT 堆——A1098.Insertion or Heap Sort(25)(内涵堆的详细创建过程))