一篇读书笔记

  书籍简评:《ACM/ICPC 算法训练教程》这本书是余立功主编的,代码来自南京理工大学ACM集训队代码库,所以小编看过之后发现确实很实用,适合集训的时候刷题啊~~,当时是听了集训队final的意见买的,感觉还是不错滴。

  相对于其他ACM书籍来说,当然如书名所言,这是一本算法训练书,有着大量的算法实战题目和代码,尽管小编还是发现了些许错误= =,有部分注释的语序习惯也有点不太合我的胃口。实战题目较多是比较水的题,但也正因此才能帮助不少新手入门,个人认为还是一本不错的算法书,当然自学还是需要下不少功夫的。

  小编认为这本书主要针对的对象是想要全面了解算法竞赛内容的入门选手,想要单纯研习算法的同学可以啃啃《算法导论》,ACM的大神们加油消灭掉刘汝佳的大黑书吧

  刚刚入门的孩纸们要和我一起fighting啊= =


  话不多说,进入正题咯, (本节部分概念来源本书P25-2.1.3 堆,其余均为原创)

  堆的概念:

    数据结构中所说的堆(heap)指的就是一个完全二叉树,当然可以用链表来实现,也可以用一维数组(线性)来模拟实现。

    依照堆中存放的数据大小,堆分为两大类,一类是最大堆,一类是最小堆。

  • 最大堆:任意一个结点的值都大于等于任一子结点的值,所以最大堆的根(root)一定是maximun。
  • 最小堆:任意一个结点的值都小于等于任一子结点的值,所以最小堆的根(root)一定是minimun。

  堆的实现

  我们经常听说,heap是一种高效紧凑的数据结构,那么为什么高效而紧凑呢。用一张图来简单介绍吧。(下图中 上下分别为heap数组(用heap[]表示),heap的图示)

    

    ps:上图中的完全二叉树可以作为heap的图示,上面绿色一栏是对应的数组(array),例如16就是heap[1],14就是heap[2]...依次类推。

    我们习惯上把 14 和 10 叫做 16 的子结点,14为16的左儿子,10为16的右儿子。

    那么像这样,我们就可以从数组(array)中得到heap[2],heap[3]为heap[1]的子结点,heap[4],heap[5]为heap[2]的子结点....

      通过c/c++整形除法规则,得到2/2 = 1 , 3/2 = 1;因此我们把 数据所在位置 满足 s/2 =f 公式的 s 称作 f 的子结点(son), f 称作 s 的父结点(father),这样我们就可以利用数组来紧凑整齐地存储这一系列数据,下一次要调用某一位置 p 的父结点时,直接采用p/2就可以找到 p 的父结点了,同理,子结点就是p*2和p*2+1,这样存储数据是不是很整齐也很便于查找呢。(虽然小编觉得手写这个数据结构的功能时依然会有些繁琐啦= =)

   


   堆的操作:

   那么下面我们来看一下这个数据结构的一般操作怎样通过代码实现呢?(多代码预警~~)(入门的孩纸们记得多调试就容易理解了~~fighting!)

  • 删除优先级最高的元素-DeleteMin()  ——  例如删除-最小堆的heap[1]

    此操作分为三步:

  1. 直接删除根(root);
  2. 用最后一个元素代替root;
  3. 将heap向下重新调整;————第三步表示为下方被调用的 调整堆函数 - down(
     /* 删除优先级最高的元素 */
    /* 最小堆为例 */ /* heap - down_adjustment */
    void down(int p) //current_node
    {
    int q = p*; //left_son_node
    int a = heap[p]; while (q < hlength) //hlength指的是heap数组的长,也就是堆中元素总数
    {
    if(heap[q] > heap[q+]) //find_min_son
    q++; if(heap[q] < a) //complete_adjustment
    break;
    else
    {
    heap[p] = heap[q];
    p = q;
    q = p*;
    }
    }
    heap[p] = a;
    return;
    } /* delete_minimun_node */
    int DleteMin()
    {
    int r = heap[]; //delete_root
    heap[] = heap[hlength--];
    down(); //this is the key point!!
    return r;
 /* 删除优先级最高的元素 */
/* 最小堆为例 */ /* heap - down_adjustment */
void down(int p) //current_node
{
int q = p*; //left_son_node
int a = heap[p]; while (q <= hlength) //hlength指的是heap数组的长,也就是堆中元素总数
{
if(q < hlength && heap[q] > heap[q+]) //find_min_son
q++; if(heap[q] < a) //complete_adjustment
break;
else
{
heap[p] = heap[q];
p = q;
q = p*;
}
}
heap[p] = a;
return;
} /* delete_minimun_node */
int DleteMin()
{
int r = heap[]; //delete_root
heap[] = heap[hlength--];
down(); //this is the key point!!
return r;
}

View Heap-Code

  • 在堆中插入新元素-Insert(x)——依然以最小堆为例  (不懂的依然记得一步一步地来理解,最好自己调试)

    操作步骤为:

  1. 将待insert的元素x添加到末尾;
  2. 向上调整;————第二步用被调用的 up() 函数表示;
 /* 堆中插入新元素 */
/* 最小堆为例 */ /* heap - up_adjustment */
void up(int p) //current_node
{
int q = p/; //partner_node
int a = heap[p]; while(q > && a < heap[q])
{
heap[p] = heap[q];
p = q;
q = p/;
}
heap[p] = a;
return;
} /* Insert_new_node */
void Insert(int a)
{
heap[++hlength] = a; //加长并将a加到末尾
up(hlength);
}

View Heap-Code

  •  将x位置的优先级提升到 p 值:IncreaseKey(x,p);
 /* 堆中将x优先级提至p */
void IncreaseKey(int x,int p)
{
if (heap[x] < p) //若heap[x]本身小于p,那么x的优先级本来就比p高
return;
heap[x] = p; //否则将heap[x]赋值为 p
up(x); //调用上方函数up()
}

View Heap-Code

  • 数组模拟建堆:Build()——(⊙o⊙)额,原谅我最后才建堆,其实这也是正常顺序啦= =
 /* 数组建堆 */
void Build()
{
for (int i = hlength / ; i > ; i++)
down(i); //调用第一次的 调整堆函数
}

View Build_heap-Code


  堆的时间度分析:
  • 向上和向下调整每层都是常数级别,共log n层,因此 调整堆 的时间度O(log n);
  • 插入/删除 只调用一次向上或向下调整,因此都是O(log n);
    现在大家明白为什么堆的时间效率如此高了吧~~
 

  
  最小堆的例子:          ————实战是检验真理的唯一标准= =,其实也是学习代码的唯一标准
    Source:POJ 2051  ————  倘若cin和scanf在算法竞赛中大量使用最好选用后者,因为说不定前者会为你贡献十几个TLE= =
 
  题意就是:
      输入数据每一行给你一个编号,再给你它每一次出现的间隔时间,最后以“#”结束
       在文件末尾还有一个k,然后让你根据他们出现的时间从早到晚把前k个编号打印出来,若在同一时间有多个编号,那么先输出小的编号。
  最小堆结构可行性分析: 
       1.首先读入数据,边读入边把它插入堆,读入数据后就建成了一个初始堆。
      2.然后输出堆顶元素,再把堆顶元素的值加上它出现的时间间隔,接着把它往下降,直到它在堆中找到一个合适的位置。
      3.重复步骤 2 直到前k个编号输出完毕。
 
 //Argus-中文貌似是一个神话人物 阿尔戈斯 号称百眼巨人~~
//吼吼吼= =(此情节与题目无关) //循环维持最小堆
//Time:32Ms Memory:176K
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std; #define MAX 1001 struct Argument {
int name; //编号
int now; //当前执行时间
int period; //周期
friend bool operator < (Argument &a, Argument &b) {
return a.now < b.now || (a.now == b.now && a.name < b.name);
}
}arg[MAX]; int len = ; /*从x向下调整*/
void down(int x)
{
Argument tmp = arg[x];
int next = * x;
for (int next = * x; next < len;next *= )
{
//比较子结点优先级
if (next + < len && arg[next + ] < arg[next])
next++;
//不可下调
if (tmp < arg[next]) break;
//下调
arg[x] = arg[next];
x = next;
}
arg[x] = tmp;
} void createHeap()
{
for (int i = len / ; i > ; i--)
down(i);
} int main()
{ char command[];
while (scanf("%s", command), strcmp(command, "#"))
{
scanf("%d%d", &arg[len].name, &arg[len].period);
arg[len++].now = arg[len].period;
} createHeap(); int k;
scanf("%d", &k);
for (int i = ; i < k; i++)
{
printf("%d\n", arg[].name);
arg[].now += arg[].period;
down();
} return ;
}
 

 
  嗯,就是这样了= =,借此希望记录下 某一种 我的大学,也希望能给眼下正在默默刷题的ACM新人们 or 算法入门新人们一些建议和一些相关整理
  希望我没有误人子弟就好,hhhhhhhhhhh
——————————From 小墨

算法手记 之 数据结构(堆)(POJ 2051)的更多相关文章

  1. 算法手记 之 数据结构(线段树详解)(POJ 3468)

    依然延续第一篇读书笔记,这一篇是基于<ACM/ICPC 算法训练教程>上关于线段树的讲解的总结和修改(这本书在线段树这里Error非常多),但是总体来说这本书关于具体算法的讲解和案例都是不 ...

  2. 算法手记 之 数据结构(并查集详解)(POJ1703)

    <ACM/ICPC算法训练教程>读书笔记-这一次补上并查集的部分.将对并查集的思想进行详细阐述,并附上本人AC掉POJ1703的Code. 在一些有N个元素的集合应用问题中,通常会将每个元 ...

  3. 基本数据结构——堆(Heap)的基本概念及其操作

    基本数据结构――堆的基本概念及其操作 小广告:福建安溪一中在线评测系统 Online Judge 在我刚听到堆这个名词的时候,我认为它是一堆东西的集合... 但其实吧它是利用完全二叉树的结构来维护一组 ...

  4. C 数据结构堆

    引言 - 数据结构堆 堆结构都很耳熟, 从堆排序到优先级队列, 我们总会看见它的身影. 相关的资料太多了, 堆 - https://zh.wikipedia.org/wiki/%E5%A0%86%E7 ...

  5. java数据结构----堆

    1.堆:堆是一种树,由它实现的优先级队列的插入和删除的时间复杂度都是O(logn),用堆实现的优先级队列虽然和数组实现相比较删除慢了些,但插入的时间快的多了.当速度很重要且有很多插入操作时,可以选择堆 ...

  6. 在 Prim 算法中使用 pb_ds 堆优化

    在 Prim 算法中使用 pb_ds 堆优化 Prim 算法用于求最小生成树(Minimum Spanning Tree,简称 MST),其本质是一种贪心的加点法.对于一个各点相互连通的无向图而言,P ...

  7. 算法设计和数据结构学习_5(BST&AVL&红黑树简单介绍)

    前言: 节主要是给出BST,AVL和红黑树的C++代码,方便自己以后的查阅,其代码依旧是data structures and algorithm analysis in c++ (second ed ...

  8. 数据结构-堆 Java实现

    数据结构-堆 Java实现. 实现堆自动增长 /** * 数据结构-堆. 自动增长 * */ public class Heap<T extends Comparable> { priva ...

  9. 数据结构 - 堆(Heap)

    数据结构 - 堆(Heap) 1.堆的定义 堆的形式满足完全二叉树的定义: 若 i < ceil(n/2) ,则节点i为分支节点,否则为叶子节点 叶子节点只可能在最大的两层出现,而最大层次上的叶 ...

随机推荐

  1. org.hibernate.QueryException: could not resolve property

    org.hibernate.QueryException: could not resolve property HibernateSQLXML  org.hibernate.QueryExcepti ...

  2. Apple Pay

    Apple Pay运行环境:iPhone6以上设备,操作系统最低iOS9.0以上,部分信息设置需要iOS9.2以上.目前还不支持企业证书添加. 环境搭建好后可以在模拟器上面运行,xcode7.2.1+ ...

  3. [Angularjs]系列——学习与实践

    写在前面 这个系列是来这家公司到现在,边用边学,以及在工作中遇到的问题进行的总结.深入的东西不多,大多是实际开发中用到的东西. 这里做一个目录,方便查看. 系列文章 [Angularjs]ng-sel ...

  4. JavaScript基础整理(1)

    最近读了<JavaScript权威指南>这本书,闲来无事对自认为重要的知识做了些整理,方便以后查阅. JavaScript中的最重要的类型就是对象,对象是名/值对的集合,或字符串到值映射的 ...

  5. 完全迁移到red hat来的相关问题解决和配置

    默认从光盘iso镜像安装iso-1 时, yum.repos.d只有 packagekit-media.repo, 要从网上下载一个 CentOS-Base.repo文件放到这里. redhat上下载 ...

  6. [设计模式] javascript 之 迭代子模式

    迭代子模式:定义 迭代子模式,又称游标模式,是一种用于对聚集进行顺序访问规则的模式,是一种行为模式:它用于提供对聚集对象的一种统一的访问接口,使客户能够在不了解聚集对象内部结构的情况对聚集对象进行访问 ...

  7. Ubuntu 14 常用“快捷键”,Ctrl + Alt + F1 进入终端,按 Ctrl + Alt + F7 回到界面

    Ubuntu中所谓 Super键,就是 Windows建,一般在键盘的 ctrl 和 alt 2个键之间,一个微软窗口的图标. 1.持续按住 Super键,会弹出“键盘快捷键”大全: 2.修改快捷键路 ...

  8. Swift3.0P1 语法指南——基本操作符

    原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...

  9. OpenCV imread读取图片,imshow展示图片,出现cv:Exception at memory location异常

    问题如上.环境:VS2013. 代码如下: #include "stdafx.h" #include "opencv2\opencv.hpp" using na ...

  10. IDEA之maven(springmvc)项目

    1.在idea下创建maven项目(参考IDEA之web项目(maven项目)创建) 2.项目结构 3.web.xml <!DOCTYPE web-app PUBLIC "-//Sun ...