数据结构-堆排序

1.首先,在这个测试中我使用的是用数组表示一个堆,并且每个堆的起始点是从数组下标为1的开始

    大顶堆

#include <iostream>
#include <algorithm>
using namespace std;
int b[100];
int c[100];
void shiftUp(int a[],int k) //将n个元素逐个插入到一个空堆中,时间复杂度 nlgN
{
    b[k+1]=a[k];
    k=k+1;//这里的b数组开始是从1开的是,能够正好对应左孩子是根节点的2倍,右孩子是根节点的2*k+1
    while(k>1&&b[k]>b[k/2]){
        swap(b[k],b[k/2]);
        k=k/2;
    }
}
void shiftDown(int k,int sum)
{
    b[k]=b[sum];//这种 方法是不断的把叶子的值放到根节点上
    sum--;
    while(2*k<=sum) //先判断是不是有孩子,有左孩子肯定说明不是独苗
    {
        int j=2*k;  //
        if(j+1<=sum&&b[j]<b[j+1])
            j=j+1;  //判断是不是有右孩子,判断哪个孩子的数值大,和那个交换
        if(b[k]>b[j])
            break; //如果父节点的值大,那么结束
        swap(b[k],b[j]);
        k=j;
    }
}
void shiftDownArray(int k,int sum) //从非叶子节点开始时间复杂度是 O(n)
{

    while(2*k<=sum) //先判断是不是有孩子,有左孩子肯定说明不是独苗
    {
        int j=2*k;  //
        if(j+1<=sum&&c[j]<c[j+1])
            j=j+1;  //判断是不是有右孩子,判断哪个孩子的数值大,和那个交换
        if(c[k]>c[j])
            break; //如果父节点的值大,那么结束
        swap(c[k],c[j]);
        k=j;
    }
}
int main()
{
    int a[]={2,3,1,5,8};//测试用例的一个简单数组
    for(int i=0;i<5;i++)
    {
        shiftUp(a,i); //这里逐个的向堆中插入元素,进行选择最大的值
        cout<<a[i]<<" ";
    }
    cout<<b[1]<<endl;
    for(int i=0;i<5;i++)
    {

        cout<<b[i+1]<<" ";//输出结果测试
    }
    cout<<endl;
    int sum=5;
    while(sum>0){
            cout<<b[1]<<"->"<<endl;
        shiftDown(1,sum);//这里是不断的取出堆的最大值,然后进行重新构建堆
        sum--;
    }
    int m=5/2; //构建的堆的第一个非叶子节点的,
    for(int i=0;i<5;i++)
    {
        c[i+1]=a[i];
    }
    //从下往上第一个非叶子节点(包括根节点),进行shiftDown操作
    for(int i=m;i>=1;i--){
        shiftDownArray(i,5);//检查节点是否比子节点大,如果不大,那么进行调试,转换
    }
    cout<<c[1]<<endl;
    for(int i=1;i<6;i++)
    {
        cout<<c[i]<<" ";
    }
}

2.一个数组表示堆,数组从下标0开始,顺便进行一次从小到大的排序

那么左孩子就是 2*i+1

        右孩子就是 2*i+2


#include <iostream>
#include <algorithm>
using namespace std;
void shiftDownArray(int a[],int k,int sum) //从非叶子节点开始时间复杂度是 O(n)
{

    while(2*k+1<sum) //先判断是不是有孩子,有左孩子肯定说明不是独苗
    {
        int j=2*k+1;  //
        if(j+1<sum&&a[j]<a[j+1])
            j=j+1;  //判断是不是有右孩子,判断哪个孩子的数值大,和那个交换
        if(a[k]>a[j])
            break; //如果父节点的值大,那么结束
        swap(a[k],a[j]);
        k=j;
    }
}
int main()
{
    int a[]={2,3,1,5,8};
    int n=5;
    for(int i=(n-1)/2;i>=0;i--)
    {
        shiftDownArray(a,i,n);//先构建一个大顶堆,这个是用第一个非叶子节点构建
    }
    for(int i=0;i<n;i++){
        cout<<a[i]<<" ";
    }
    cout<<endl;

    for(int i=n-1;i>0;i--){ //然后堆顶放到数组最后面
        swap(a[0],a[i]);
        for(int j=0;j<n;j++){
        cout<<a[j]<<" ###";
        }
        cout<<endl;
        shiftDownArray(a,0,i); //再一次的进行重新构建大顶堆,但是数组的长度减1,这个是之间用最后一个顶替堆顶,从新构建堆
        for(int j=0;j<n;j++){
        cout<<a[j]<<" ***";
        }
        cout<<endl;
    }


}

猜你喜欢

转载自blog.csdn.net/Sun6Zero/article/details/80215831