树和堆

树和堆

先验知识

  1. 二叉树中有两种特殊的二叉树,叫做满二叉树和完全二叉树;

  2. 满二叉树指的是二叉树内部结点都有两个儿子;

  3. 完全二叉树就是叶子结点不完整,从右向左连续缺若干结点,只需要用一个一维数组即可存储完全二叉树;

  4. 已知父亲编号为k,则左儿子是2k,右儿子是2k+1;倘若儿子的编号是x,则父亲结点的编号是x/2;

  5. 堆是一种特殊的二叉树,所有父节点都比子节点小或者大。

堆的创建

堆的创建有两种方式

方法一:插入的时候调整树的结构

    //整体复杂度为O(NlogN)   
    //建立堆的函数
    for(int i = 1; i <= m; i++)
    {   
        scanf("%d", &h[i]);
        siftup(i);
    }
    n = m;

方法二:先存储再调整

  //整体复杂度为O(N)   
    //建立堆的函数
    for(int i = 1; i <= m; i++)
    {   
        scanf("%d", &h[i]);
    }   
    n = m;
    creat();

//建树函数
void creat()
{
    int i;
    for(i = n/2; i >= 1; i--)
    {
        siftdown(i);
    }
}

堆排序

方法一:建立最小堆,pop堆顶

#include<bits/stdc++.h>
using namespace std;

int h[101]={0};
int n=0;

void swap(int x, int y)
{
    int t;
    t = h[x];
    h[x] = h[y];
    h[y] = t;
}

//向下调整
void siftdown(int i)
{
    int flag = 0;
    int t;
    while( i*2 <= n && flag == 0)
    {   
        //存储最小值
        if(h[i] > h[i*2])
            t = i*2;
        else
            t = i;
        
        if(i*2+1 <= n)
        {
            if(h[t] > h[i*2+1])
                t=i*2+1;
        }
        
        if(t!=i)
        {
            swap(t,i);
            i=t;
        }
        else
            flag = 1;
    }
}

//向上调整
void siftup(int i)
{
    int flag = 0;
    if(i == 1)return;
    while(i!=1 && flag== 0)
    {
        if(h[i] < h[i/2])
            swap(i,i/2);
        else
            flag = 1;
        i=i/2;
    }
}

void creat()
{
    int i;
    for(i = n/2; i >= 1; i--)
    {
        siftdown(i);
    }
}


int deleteValue()
{
    int t;
    t = h[1];
    h[1] = h[n];
    n--;
    siftdown(1);
    return t;
}

int main()
{
    int m;
    scanf("%d", &m);
    
    
    // //整体复杂度为O(NlogN)   
    // //建立堆的函数
    // for(int i = 1; i <= m; i++)
    // {   
    //     scanf("%d", &h[i]);
    //     siftup(i);
    // }
    // n = m;
    
    //整体复杂度为O(N)   
    //建立堆的函数
    for(int i = 1; i <= m; i++)
    {   
        scanf("%d", &h[i]);
    }   
    n = m;
    creat();
    
    // for(int i = 1; i <= m; i++)
    // {
    //     printf("%d ", h[i]);    
    // }
    // printf("\n");
    for(int i = 1; i <= m; i++)
        printf("%d ", deleteValue());
    
    return 0;
}

方法二:建立最大堆,归位最大值

#include<bits/stdc++.h>
using namespace std;

int h[101]={0};
int n=0;

void swap(int x, int y)
{
    int t;
    t = h[x];
    h[x] = h[y];
    h[y] = t;
}

//向下调整
void siftdown(int i)
{
    int flag = 0;
    int t;
    while( i*2 <= n && flag == 0)
    {   
        //存储最大值
        if(h[i] < h[i*2])
            t = i*2;
        else
            t = i;
        
        if(i*2+1 <= n)
        {
            if(h[t] < h[i*2+1])
                t=i*2+1;
        }
        
        if(t!=i)
        {
            swap(t,i);
            i=t;
        }
        else
            flag = 1;
    }
}

void creat()
{
    int i;
    for(i = n/2; i >= 1; i--)
    {
        siftdown(i);
    }
}

//堆排序
void heaport()
{
    while(n > 1)
    {
        swap(1,n);
        n--;
        siftdown(1);
    }
}

int main()
{
    int m;
    scanf("%d", &m);
    for(int i = 1; i <= m; i++)
    {   
        scanf("%d", &h[i]);
    }   
    n = m;
    
    //建堆
    creat();
    //堆排序
    heaport();
    
    for(int i = 1; i <= m; i++)
        printf("%d ", h[i]);
    
    return 0;
}

输出结果

14
99 5 36 7 22 17 46 12 2 19 25 28 1 92
1 2 5 7 12 17 19 22 25 28 36 46 92 99
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值