简单易懂的讲堆排序

来源:互联网 发布:一键传淘宝的弊端 编辑:程序博客网 时间:2024/05/22 06:44

堆排序利用二叉堆来进行排序,而二叉堆用完全二叉树代替(因为易于储存和索引),一个数组就可以存储完全二叉树。(๑╹◡╹)ノ"""

但堆并不一定是完全二叉树,堆还有更复杂的,就不一一列举;

怎么用数组存储呢?对于每一个节点i,其父节点为i/2,其左右子节点分别为i*2,i*2+1;如图:


怎么进行排序呢,我们分为两个大步骤:

1,构建一个最大堆(每一个父节点都大于其子节点)

对于每一个非叶子节点(有叶子的节点),如果其小于子节点,那么就与子节点中较大的进行交换;

对于一个节点数为n的二叉堆来说,最后一个非叶子节点为n/2;

#include<bits/stdc++.h>using namespace std;void sift(int *r,int low,int high){int i=low,j=2*low;int tmp=r[low];while(j<=high){//如果存在左子节点 j代表左节点 if(j<high&&r[j]<r[j+1])j+=1;//如果存在右节点且右节点大于左节点  j+=1 j代表右节点 if(tmp<r[j]){        //如果较大的节点大于父节点就交换 r[i]=r[j];      //交换 i=j;j*=2;   //继续判断子节点的子节点 }else break;     //小于就终止 }r[i]=tmp;}int main(){int a[7]={0,5,2,4,6,1,3};//从1开始为有效,即树根编号为1; for(int i=6/2;i>=1;i--){sift(a,i,6);}for(int i=1;i<=6;i++)cout<<a[i];return 0;}
输出为654213即如图:


所有的父节点都大于其子节点,最大堆构建完成;

2,从最后一个元素开始到第一个元素进行如下操作:

(1)交换当前元素与第一个元素(根据最大堆性质,第一个元素最大);

(2)然后忽视被交换到后面的元素并重构最大堆


(1)最后一个元素编号为6,值为3与第一个元素进行交换:


(2)交换一次后可以看到6已经到达了位置,即6已经排好了序;

排除6重新构建最大堆:


(1)交换倒数第二个元素和第一个元素:

第二个元素到达位置,即5,6已经排好序


(2)忽略5,6并重构最大堆。。。。。。。。

这样一直到排好序,即每一次都有一个元素排好序,每次找堆顶元素(除去已排好序的元素中最大的数)并将其放到其应该待的位置;

完整代码:

#include<bits/stdc++.h> using namespace std;void sift(int *r,int low,int high){int i=low,j=2*low;int tmp=r[low];while(j<=high){//如果存在左子节点 j代表左节点 if(j<high&&r[j]<r[j+1])j+=1;//如果存在右节点且右节点大于左节点  j+=1 j代表右节点 if(tmp<r[j]){        //如果较大的节点大于父节点就交换 r[i]=r[j];      //交换 i=j;j*=2;   //继续判断子节点的子节点 }else break;     //小于就终止 }r[i]=tmp;}void HeapSort(int *r,int n){int i;for(i=n/2;i>=1;i--){       //构建初始最大堆 sift(r,i,n);      }for(i=n;i>=2;i--){         //进行排序的过程 swap(r[1],r[i]);//交换未排好序中最大的数到达其排好序后应在的位置; sift(r,1,i-1);//  思考一下为什么是i-1,文章最后给出解答 }} int main(){int a[7]={0,5,2,4,6,1,3};HeapSort(a,6);for(int i=1;i<=6;i++)cout<<a[i];return 0;} 
彩蛋:i-1即排除已经排好序的那些在末尾的大元素们,在未排序的序列中进行最大堆的重构( ̄▽ ̄)~*



原创粉丝点击