堆的插入和删除

Posted -citywall123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆的插入和删除相关的知识,希望对你有一定的参考价值。

堆的定义

  堆就是一棵可以自我平衡的完全二叉树

  优先队列的底层数据结构就是堆,实现和堆基本一样

 

技术图片

 

 

 

由于堆存储在下标从0开始计数的数组中,因此,在堆中给定下标为i的结点时:

如果 i = 0,结点 i 是根结点,无父结点;否则结点 i 的父结点为结点 [(i - 2) / 2]

如果 2i + 1 > n - 1,则结点 i 无左子女;否则结点 i 的左子女为结点 2i + 1

如果 2i + 2 > n - 1,则结点 i 无右结点;否则结点 i 的右子女为结点 2i + 2

 

堆特性

 

1、每个父节点都大于等于其所有后代结点。

2、堆的根节点含有堆中最大(或者最小)的对象。

3、堆中以任意节点为根节点的子树仍然是堆。

 

 

堆的分类

最大堆(大根堆,大顶堆):根节点对象是最大对象的堆

最小堆(小根堆,小顶堆):根节点对象是最小对象的堆

 

 

堆的插入操作(以最小堆为例,将一个数组变成堆)

堆的插入操作是自底向上进行的,每次从堆的最后一个结点开始插入(将插入的值放入完全二叉树的最后一个结点),为了维持堆的性质,还要从插入结点开始依次往前递归,去维持堆的三个特性

  ①我们现在有一个长度为n的数组a,里边的元素都没有顺序,把这个数组变成最小堆

  ②然后我们新建一个完全二叉树b,按数组下标0到n-1的顺序依次放入完全二叉树,也就是说现在b[0]=a[0],b[1]=a[1]......。

  ③取插入结点的父节点,比较父节点的值和插入结点的值,将较小的值交换到父节点位置。

  ④再以父节点为当前结点,重复上一步操作,知道遇到父节点比插入结点值小,就可以结束递归0

 

int Heap[MAX_SIZE];
int Cur = 0;

void Insert(int val)     //插入
{
    Heap[++Cur] = val;     //新元素加入堆
    int Temp_Cur = Cur;
    //加入元素后维持堆的性质,一直递归到符合堆性质的结点
    while (Temp_Cur > 1)  
    {
        //找父节点
        int Root = Temp_Cur / 2;   
        //父节点比子节点大-->小根堆
        if (Heap[Root] > val)    
            swap(Heap[Root], Heap[Temp_Cur]);  //交换
        //找到符合性质的堆就退出
        else
            break;  
        //更新当前结点位置
        Temp_Cur = Root;     
    }
}

 

 

 

堆的删除操作

堆的删除操作是只能删除堆顶的元素,删除堆顶元素之后,把堆的最后一个元素放到堆顶,然后不断向下维护堆的特性1、2、3

 

int Pop()    //删除
{
    if (Cur == 0)  //堆空
        return -99999999;
    //保存堆顶
    int Temp_Top = Heap[1];   
    //将末尾结点提到树根
    Heap[1] = Heap[Cur];   
    int Root = 1;
    //从堆顶往下维护堆的特性,一直处理到叶子结点-->小根堆
    while (2 * Root < Cur)   
    {
        //左儿子
        int L_Child = Root * 2;   
        //右儿子
        int R_Child = Root * 2 + 1;   
        //只有左节点或者左节点比右节点的值小
        if (R_Child >= Cur || Heap[L_Child] < Heap[R_Child])  
        {
            //让左结点和根节点比较,把较小值交换到父节点位置上
            if (Heap[Root] > Heap[L_Child])  
            {
                swap(Heap[Root], Heap[L_Child]);  
                //更新位置
                Root = L_Child;  
            }
            else
                break;
        }
        //左结点值比右结点值大,比较父节点和右节点
        else
        {
            if (Heap[Root] > Heap[R_Child])
            {
                swap(Heap[Root], Heap[R_Child]);
                Root = R_Child;
            }
            else
                break;
        }
    }
    Cur--;
    //返回删除的堆顶元素
    return Temp_Top;  
}

 

堆的排序操作

//堆排序
int temp[MAX_SIZE];
int k = 0;
void quick_sort(int n)
{
    for (int i = 1; i <= n; i++)
    {
        temp[k++] = Pop();
    }
}

 

完整代码

#include<iostream>
#include<string>
#define MAX_SIZE 100005
using namespace std;

int Heap[MAX_SIZE];
int Cur = 0;

void Insert(int val)     //插入
{
    Heap[++Cur] = val;     //新元素加入堆
    int Temp_Cur = Cur;
    //加入元素后维持堆的性质,一直递归到符合堆性质的结点
    while (Temp_Cur > 1)  
    {
        //找父节点
        int Root = Temp_Cur / 2;   
        //父节点比子节点大-->小根堆
        if (Heap[Root] > val)    
            swap(Heap[Root], Heap[Temp_Cur]);  //交换
        //找到符合性质的堆就退出
        else
            break;  
        //更新当前结点位置
        Temp_Cur = Root;     
    }
}

int Pop()    //删除
{
    if (Cur == 0)  //堆空
        return -99999999;
    //保存堆顶
    int Temp_Top = Heap[1];   
    //将末尾结点提到树根
    Heap[1] = Heap[Cur];   
    int Root = 1;
    //从堆顶往下维护堆的特性,一直处理到叶子结点-->小根堆
    while (2 * Root < Cur)   
    {
        //左儿子
        int L_Child = Root * 2;   
        //右儿子
        int R_Child = Root * 2 + 1;   
        //只有左节点或者左节点比右节点的值小
        if (R_Child >= Cur || Heap[L_Child] < Heap[R_Child])  
        {
            //让左结点和根节点比较,把较小值交换到父节点位置上
            if (Heap[Root] > Heap[L_Child])  
            {
                swap(Heap[Root], Heap[L_Child]);  
                //更新位置
                Root = L_Child;  
            }
            else
                break;
        }
        //左结点值比右结点值大,比较父节点和右节点
        else
        {
            if (Heap[Root] > Heap[R_Child])
            {
                swap(Heap[Root], Heap[R_Child]);
                Root = R_Child;
            }
            else
                break;
        }
    }
    Cur--;
    //返回删除的堆顶元素
    return Temp_Top;  
}
//堆排序
int temp[MAX_SIZE];
int k = 0;
void quick_sort(int n)
{
    for (int i = 1; i <= n; i++)
    {
        temp[k++] = Pop();
    }
    
}
int main()
{
    int n, x;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> x;
        Insert(x);
    }
    quick_sort(n);
    for (int i = 0; i <k; i++) {
        cout << temp[i] <<  ;
    }
    cout << endl;
    system("pause");
    return 0;
}

 

以上是关于堆的插入和删除的主要内容,如果未能解决你的问题,请参考以下文章

堆的插入和删除

堆的插入和删除

堆的插入和删除

最小堆的建立 插入 与删除

面试题9:数组堆化堆的插入堆的删除堆排序

栈和队列的区别,栈和堆的区别