zoukankan      html  css  js  c++  java
  • DS实验题 融合软泥怪-2 Heap实现

    题目和STL实现:DS实验题 融合软泥怪-1

    用堆实现优先队列

    引言和堆的介绍摘自:Priority Queue(Heaps)--优先队列(堆)

    引言:

    优先队列是一个至少能够提供插入(Insert)和删除最小(DeleteMin)这两种操作的数据结构。对应于队列的操作,Insert相当于Enqueue,DeleteMin相当于Dequeue。

    链表,二叉查找树,都可以提供插入(Insert)和删除最小(DeleteMin)这两种操作,但是为什么不用它们而引入了新的数据结构的。原因在于应用前两者需要较高的时间复杂度。对于链表的实现,插入需要O(1),删除最小需要遍历链表,故需要O(N)。对于二叉查找树,这两种操作都需要O(logN);而且随着不停的DeleteMin的操作,二叉查找树会变得非常不平衡;同时使用二叉查找树有些浪费,因此很多操作根本不需要。

    因此这里引入一种新的数据结构,它能够使插入(Insert)和删除最小(DeleteMin)这两种操作的最坏时间复杂度为 O(N) ,而插入的平均时间复杂度为常数时间,即O(1)。同时不需要引入指针。

    二叉堆

    Heap有两个性质:结构性质(structure property),堆的顺序性(heap order property)。看英文应该比较好理解。

    structure property

    Heap(堆)是一个除了底层节点外的完全填满的二叉树,底层可以不完全,左到右填充节点。(a heap is a binary tree that completely filled, with the exception of bottom level, which is filled from left to right.)这样的树叫做完全二叉树。

    一个高度为h 的完全二叉树应该有以下的性质:

    a) 有2^h到2^h-1个节点

    b) 完全二叉树的高度为logN

    鉴于完全二叉树是一个很整齐的结构,因此可以不用指针而只用数组来表示一颗完全二叉树。 对于处于位置i 的元素,

    a)他的左子节点在2i,右子节点在(2i+1)

    b) 它的父节点在【i/2】(向下取整)

    下图显示了完全二叉树与数组的对应关系:

    实现

    有了上面的基础之后,其实建堆和维护堆并不是一件难事,这里大概描述下我的思路。

    1.我们使用数组模拟堆,i是当前节点,i/2是它的父亲节点,i2和i2+1或者i*2-1(如果存在的话)是它的左右儿子。

    2.刚刚开始建堆的时候,从size到1遍历一遍,每一个节点向上进行维护,进行初始化。

    3.维护的方法:比较当前节点和父亲节点 => 如果父亲节点的值大于当前节点的值,则进行交换,同时当前节点来到此时的父亲节点处,父亲节点找它的父亲节点 || 如果父亲节点的值小于当前节点的值,结束。

    4.加入一个元素的方法:在堆尾,也就是Heap[size+1],插入新的节点 => size++ => 步骤3。

    5.删除最小节点的方法:将最后一个节点和最小的节点交换 => 删除最后一个节点 => 执行步骤2。

    代码

    //
    //  main.cpp
    //  Heap
    //
    //  Created by wasdns on 16/12/25.
    //  Copyright © 2016年 wasdns. All rights reserved.
    //
    
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    int size = 0;
    
    int Heap[100005];
    
    /*
         维护函数keep
     */
    void keep(int son)
    {
        int fa = son/2;
        
        while (fa >= 1 && Heap[fa] > Heap[son])
        {
            int t = Heap[fa];
            Heap[fa] = Heap[son];
            Heap[son] = t;
            
            son = fa;
            fa = fa/2;
        }
    }
    
    /*
        初始化函数IniHeap
     */
    void IniHeap()
    {
        int i;
        
        for (i = size; i >= 1; i--)
        {
            keep(i);
        }
    }
    
    /*
        InsProtect函数:插入新节点并维护
     */
    void InsProtect(int a)
    {
        Heap[++size] = a;
        
        keep(size);
    }
    
    /*
        DelMin函数:删除最小元并维护
     */
    int DelMin()
    {
        int minum = Heap[1];
        
        int t = Heap[size];
        
        Heap[1] = t;
        
        size--;
        
        IniHeap();
        
        return minum;
    }
    
    int main()
    {
        cin >> size;
        
        for (int i = 1; i <= size; i++)
        {
            cin >> Heap[i];
        }
        
        IniHeap();
        
        int cnt = 0;
        
        while (size != 1)
        {
            int a = DelMin();
            int b = DelMin();
            
            cnt += a+b;
            
            InsProtect(a+b);
        }
        
        cout << cnt << endl;
        
        return 0;
    }
    
    /*
     14
     4 3 2 6 7 1 3 5 4 3 8 2 1 7
     */
    
    

    2016/12/25

  • 相关阅读:
    Weblogic学习笔记
    Shiro权限使用
    Shiro权限框架使用总结
    支付宝接口文档说明
    代码模拟实现十六进制转二进制
    代码模拟实现十六进制转换十进制
    四种内部类详细解释和代码示例
    Struts2_struts.xml写法和用法例子
    spring一些方法和用法例子
    Hibernate一些_方法_@注解_代码示例
  • 原文地址:https://www.cnblogs.com/qq952693358/p/6219174.html
Copyright © 2011-2022 走看看