(二叉树下)堆的一些简单操作(建堆、堆实现优先队列、堆排序、用堆实现的一种比快排时间复杂度还低的算法)

几个基础概念:

优先队列:支持插入元素寻找最大(小)值元素的数据结构。

根结点为第一层

满二叉树:树高为h且     2^{^{h}}-1 = 结点总数 

完全二叉树:树高为h且     2^{^{h-1}} \leq 结点总数 < 2^{^{h}}-1

扫描二维码关注公众号,回复: 12733994 查看本文章

完全二叉树:最后一个非叶结点是第n/2个结点

下面的程序是建堆(最小堆、最大堆),利用堆来设计优先队列,而后设计堆进行排序。

可以看到,建堆时间复杂度为\large O(nlog_{2}n),利用堆设计的优先队列时间复杂度为\large O(nlog_{2}n),堆排序的时间复杂度为\large O(nlog_{2}n)

测试程序:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int a[100];
int sum=0;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        int t;
        scanf("%d",&t);
        sum++;
        a[sum]=t;
        int k=sum;
        while(k>1)
        {
            if(k/2>=1&&a[k/2]>=a[k])
            {
                swap(a[k/2],a[k]);
                k=k/2;
            }
            else
                break;
        }

    }
    int m;
    scanf("%d",&m);
    while(m--)
    {
        int x;
        scanf("%d",&x);
        cout<<a[1]<<endl;
        a[1]=x;
        int t=1;
        int flag=t;
        while(2*flag<=n)
        {
            t=flag;
            if(a[t]>=a[2*t])
            {
                flag=2*t;
            }
            if(2*t+1<=n)
            {
                if(a[flag]>=a[2*t+1])
                {
                    flag=2*t+1;
                }
            }

            if(flag==t)
                break;
            else
            {
                swap(a[t],a[flag]);
            }

        }

    }
    for(int i=1; i<=n; i++)
    {
        printf("%d ",a[i]);
    }


    cout<<endl;
    while(1)
    {
        cout<<a[1]<<" ";
        a[1]=a[n];
        n--;
        if(n==0)
            break;
        int t=1;
        int flag=t;
        while(2*flag<=n)
        {
            t=flag;
            if(a[t]>=a[2*t])
            {
                flag=2*t;
            }
            if(2*t+1<=n)
            {
                if(a[flag]>=a[2*t+1])
                {
                    flag=2*t+1;
                }
            }

            if(flag==t)
                break;
            else
            {
                swap(a[t],a[flag]);
            }

        }

    }


}

测试结果:

如果有一个大小为n的数列,从中选择第k大的数据,使用堆将会大大提升缀合速度,时间可以优化到\large O(nlog_{_{_{_{2}}}}k)

如果使用快排处理,需要\large O(nlog_{2}n)

如果使用冒泡,需要\large O(n^{^{2}})

测试程序:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int a[100];
int sum=0;
int main()
{
    int n,k;
    scanf("%d %d",&n,&k);
    for(int i=1; i<=n; i++)
    {
        int x;
        scanf("%d",&x);
        sum++;
        if(sum<=k)
        {
            a[sum]=x;

            int flag=sum;
            while(flag>1)
            {
                if(flag/2>=1&&a[flag]<a[flag/2])
                {
                    swap(a[flag],a[flag/2]);
                    flag=flag/2;
                }
                else
                    break;
            }
        }
        else
        {
            if(x>a[1])
            {
                a[1]=x;
                int flag=1;
                int t;
                t=flag;
                while(flag*2<=k)
                {
                    if(a[flag]>a[2*flag])
                    {
                        t=2*flag;
                    }
                    if(flag*2+1>=k)
                    {
                        if(a[t]>a[2*flag+1])
                        {
                            t=2*flag+1;
                        }
                    }
                    if(t==flag)
                        break;
                    else
                    {
                        swap(a[t],a[flag]);
                        flag=t;
                    }
                }

            }

        }
    }

    cout<<a[1]<<endl;
}

测试结果

猜你喜欢

转载自blog.csdn.net/nyist_yangguang/article/details/113487505
今日推荐