堆--LogN的数据结构

我们这里的堆是指用来表示元素集合的一种数据结构

一个二叉树是一个堆是由堆的两个性质决定的(以小根堆为例)

1:任何节点的值都小于或等于其子节点的值

2:该二叉树最多在两层上具有叶节点,其中最底层的叶节点尽可能的靠左分布

我们可以从数学上约束这两个性质

x[i/2]<=x[i](2<=i<=n)

从这个性质我们可以定义heap(l,u):x[i/2]<=x[i](2l<=i<=u)

下面我们考虑两种情况:

1:当x[1,...n-1]是堆时,在x[n]中放置一个任何的元素可能无法产生heap(1,n)

2:当x[1...n]是一个堆时,给x[1]分配一个新值得到heap(2,n),如何得到heap(1,n)

现在我们来探讨这两个问题:

x[n]即为图中带圈的元素,该元素一直往上与父节点交换,知道该节点的值大于等于其父节点(或者位于树根)为止

如果过程中heap(1,n-1)为真,那么heap(1,n)为真

void siftup(int n)//sift 筛选
{
    int i=n;
    while(true) {
        if(i==1) break;
        int p=i/2;
        if(x[p]<=x[i]) break;
        swap(i,p);
        i=p;
    }
}

x[1]即为图中带圈的元素,x[1]向下筛选,直到它没有子节点或者小于等于它的子节点

void siftdown(int n)
{
    int i=1;
    while(true) {
        int c=2*i;
        if(c>n) break;//no child node
        if(c+1<=n)//c+1 is the right child,c+1<=n,i has right child
            if(x[c+1]<x[c]) c++;//select lesser one
        //c is the lesser child
        if(x[i]<=x[c]) break;
        swap(c,p);
        i=c;
    }
}

通过解决这两个问题,我们实现了给堆增加一个元素或者删除最小的元素(最小堆)

现在我们考虑用堆的这两个操作来实现另一个数据结构--优先级队列

优先级队列(priority queue) 是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有(1)查找(2)插入一个新元素 (3)删除

一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素 。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。

如果用我们上面讨论的最小堆来实现的话,那么对应的操作如下:

查找:返回x[1]

插入:插入新元素是将n+1,然后将新元素放在x[n]处,这样我们就具备了调用siftup的前提:heap(1,n-1)

删除:由于是最小堆,x[1]即为优先权最高的元素,删除x[1],我们可以将x[n]移动到x[1]并将n-1,这样集合中的元素都在x[1..n]中了,并且heap(2,n)为真,那我们就可以调用siftdown了

template<class T>
class priqueue
{
private:
    int n,maxsize;
    T *x;
    void swap(int i,int j){ T t = x[i];x[i]=x[j];x[j]=t;}
public:
    priqueue(int m)
    {
        maxsize=m;
        x= new int[maxsize+1];
        n=0;
    }
    void insert(T t)
    {
        int i,p;
        x[++n]=t;
        for(i=n;i>1 && x[p=i/2]>x[i];i=p) swap(i,p);
    }
    T extractmin()
    {
        int i,c;
        T t = x[1];
        x[1]=x[n--];
        for(i=1;(c=2*i)<=n;i=c)
        {
            if(c+1<=n&&x[c+1]<x[c])
                c++;
            if(x[i]<=x[c]) break;
            swap(i,c);
        }
        return t;
    }
    ~priqueue();

};

优先级队列的实现为我们提供了一种简单的向量排序算法:首先在优先级队列中依次插入每个元素,然后排序删除它们

然而这种想法需要额外的一个数组的内存,但我们分析可知,是可以在一个数组上操作的,想法如下:

第一阶段:在原数组上建立堆,

第二阶段:使用堆来建立有序序列,由于x[1]是最小的元素,交换x[1]和x[n--],然后把新的顶部元素向下筛选来重新获得堆性质,循环。

不过这样得到的是一个降序的有序序列,如果要得到升序的有序序列,我们要使用最大堆而不是最小堆

下面是实现的最小堆排序的代码:

#include <iostream>
#include "stdlib.h"
#include "time.h"
using namespace std;
int x[101]= {0};
int co=0;
void swap(int f,int s)
{
    int temp=x[f];x[f]=x[s];x[s]=temp;
    co++;
}
void siftup(int n)//sift 筛选
{
    int i=n;
    while(true)
    {
        if(i==1) break;
        int p=i/2;
        if(x[p]<=x[i]) break;
        swap(i,p);
        i=p;
    }
}
void siftdown(int n)
{
    int i=1;
    while(true) {
        int c=2*i;
        if(c>n) break;//no child node
        if(c+1<=n)//c+1 is the right child,c+1<=n,i has right child
            if(x[c+1]<x[c]) c++;//select lesser one
        //c is the lesser child
        if(x[i]<=x[c]) break;
        swap(c,i);
        i=c;
    }
}
int main(int argc, char const *argv[])
{
    srand(unsigned(time(NULL)));
    for(int i=1;i<101;i++)
    {
        x[i]=rand()%100;
        cout<<x[i]<<" ";
    }
    cout<<endl;
    //sort
    for(int i=2;i<=100;i++) siftup(i);
    for(int i=100;i>=2;i--)
    {
        swap(i,1);
        siftdown(i-1);
    }
    for(int i=1;i<101;i++)
    {
        cout<<x[i]<<" ";
    }
    cout<<endl<<co;
    return 0;
}
时间: 2024-10-11 16:30:30

堆--LogN的数据结构的相关文章

使用堆和队列数据结构解决迷宫问题

python实现迷宫问题的栈和队列的解决方法: #迷宫问题#表示迷宫的颜色,0表示路通,1表示围墙maze=[ [1,1,1,1,1,1,1,1,1,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,1,0,0,0,1,0,1], [1,0,0,0,0,1,1,0,0,1], [1,0,1,1,1,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,1], [1,0,1,0,0,0,1,0,0,1], [1,0,1,1,1,0,1,1,0,1], [1,1,0,0,0

4-2-串的堆存储结构-串-第4章-《数据结构》课本源码-严蔚敏吴伟民版

课本源码部分 第4章  串 - 堆串 ——<数据结构>-严蔚敏.吴伟民版        源码使用说明  链接??? <数据结构-C语言版>(严蔚敏,吴伟民版)课本源码+习题集解析使用说明        课本源码合辑  链接??? <数据结构>课本源码合辑        习题集全解析  链接??? <数据结构题集>习题解析合辑        本源码引入的文件  链接? Status.h        相关测试数据下载  链接? 无数据       文档中源码及

数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉搜索树.红黑树.线索二叉树,它们在解决实际问题中有着非常重要的应用.本文主要从概念和一些基本操作上进行分类和总结. 一.概念总揽 (1) 堆 堆(heap order)是一种特殊的表,如果将它看做是一颗完全二叉树的层次序列,那么它具有如下的性质:每个节点的值都不大于其孩子的值,或每个节点的值都不小于其孩子的值

从一个集合中查找最大最小的N个元素——Python heapq 堆数据结构

Top N问题在搜索引擎.推荐系统领域应用很广, 如果用我们较为常见的语言,如C.C++.Java等,代码量至少也得五行,但是用Python的话,只用一个函数就能搞定,只需引入heapq(堆队列)这个数据结构即可.今天偶然看到这个库,特意记下之. 先看一个例子: 1 >>> import heapq 2 >>> nums = [1,8,2,23,7,-4,18,23,42,37,2] 3 >>> print heapq.nlargest(3, nums

[数据结构学习备忘录]堆及其堆排序

[数据结构学习备忘录] 堆 一种数据结构,物理存储方式:数组 逻辑存储方式:近似于完全二叉树,假定i为堆元素的序数[Index],那么i/2就是该元素的左子树,(i/2 + 1)就是该元素的右子树,分为两种堆:大根堆.小根堆:这两种堆的区别是:大根堆的根节点元素的值比左右子树的值都要大,小根堆则相反. 可用这种数据结构进行排序,称为堆排序. 与该数据结构相关的关键算法: ①   MaxHeaplfy 当堆的元素顺序出现错误时的调整函数 ②   BulidMax[min]Heap 建立大[小]根堆

数据结构之二叉堆、堆排序

前言 上一篇写了数据结构之二叉搜索树.AVL自平衡树,这次来写堆. 堆的创造者 很久以前排序算法的时间复杂度一直是O(n^2), 当时学术界充斥着"排序算法不可能突破O(n^2)"的声音,直到1959年,由D.L.Shell提出了一种排序算法,希尔排序(Shell Sort),才打破了这种不可能的声音,把排序算法的时间复杂度提升到了O(n^3/2)! 当科学家们知道这种"不可能"被突破之后,又相继有了更快的排序算法,"不可能超越O(n^2)"彻底

[大、小根堆应用总结一]堆排序的应用场景

前言 在整理算法题的时候发现,大根堆(小根堆)这种数据结构在各类算法中应用比较广泛,典型的堆排序,以及利用大小根堆这种数据结构来找出一个解决问题的算法最优解.因此,我打算单独将关于堆的应用独立总结出来,后面每遇到一种跟堆结构相关的应用都放到这个目录下. 堆的定义 n个关键字序列L[1-n]称为堆,当且仅当该序列满足: 1. L(i)<=L(2i)且L(i)<=L(2i+1)或 2. L(i)>=L(2i)且L(i)>=L(2i+1) 满足第一个条件的成为小根堆(即每个结点值小于它的

【数据结构和算法16】堆排序

堆排序,顾名思义就是利用堆这个数据结构对数据项进行排序.前面提到过.堆数据结构中.节点大于或等于自己的子节点.那么我们能够将待排序的数据项依次加入到堆中,然后再依次取出根节点就可以.从堆中取出的数据项是从大到小排列的.由于根节点永远是最大的.而堆中永远是取根节点.假设对堆这样的数据结构不太了解的话,能够先看这篇博文:数据结构和算法之 堆.这里不再赘述. 以下我们来看看堆排序的实现(假设程序有不清楚的地方.也能够參考上面那篇博文). public class HeapSort { private

数据结构中的堆

一:堆排序      堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种.可以利用数组的特点快速定位指定索引的元素.堆分为大根堆和小根堆,是完全二叉树.大根堆的要求是每个节点的值都不大于其父节点的值,即A[PARENT[i]] >= A[i].在数组的非降序排序中,需要使用的就是大根堆,因为根据大根堆的要求可知,最大的值一定在堆顶.下面附上简单C#简单实现: using System; using System.Collections.Generi