• 堆的插入和删除


    堆的定义

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

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

    由于堆存储在下标从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

     

    //建堆时间复杂度O(n)
    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

    //删除堆顶,接着维护堆的性质的时间复杂度为O(lgn)
    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; }

    堆的排序操作

    //堆排序
    //排序的空间复杂度为O(1)
    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;
    }
  • 相关阅读:
    HDUOJ-----Difference Between Primes
    HDUOJ----(4706)Children's Day
    poj-------Common Subsequence(poj 1458)
    poj----Maximum sum(poj 2479)
    scanf/sscanf %[]格式控制串的用法(转)
    HDUOJ--------Text Reverse
    HDUOJ---hello Kiki
    HDUOJ-----X问题
    POJ-----C Looooops
    POJ--Strange Way to Express Integers
  • 原文地址:https://www.cnblogs.com/-citywall123/p/12892042.html
Copyright © 2020-2023  润新知