堆和栈及其实现方法

                                         关于堆和栈

- 以前学习程序设计的时候都是将堆栈合起来一起说的,后来经过很久以后的学才发现堆栈完全是两个东西,也不知道为什么要将堆栈合起来一起说,栈很好理解,就是一个先进后出表,但是堆是一种数据结构。感觉栈和队列可以合起来说,但是堆明显是不能和堆合起来说的。


首先是,栈很好理解,就和它的名字一样先进后出表,先进栈的元素会相对后面出栈,如图所示
这里写图片描述
在代码实现方面可以使用数组来模拟,但是c++里面有自带的库函数很好用,用法也很简单,在这里展示一下用法就好了。

//头文件
#include <stack>

#include <stdio.h>
using namespace std;

int main() {
    //定义,数据元素可以是整形,浮点型,字符型,自定义类型都可以,这里就以整形为例
    stack <int> st;

    //向栈中放入元素
    st.push(1);
    st.push(2);

    //从栈中取出元素,只能按照顺序取出,每次取栈顶的元素
    int temp = st.top();

    //从栈顶删除元素,每次也只能删除栈顶元素
    st.pop();

    //获得栈的大小
    int Size = st.size();

    //可以打表看一下栈的放入和取出顺序
    stack <int> st2;
    for(int i=1;i<=10;i++) {
        st2.push(i);
        printf("%d ",i);
    }
    printf("
");

    while(st2.size()){
        printf("%d ",st2.top());
        st2.pop();
    }
}

然后是,堆就要比栈复杂一些,堆是一种二叉树,它最重要的性质就是儿子节点的值一定比父亲节点的值更大,除此之外,树的节点是按从上到下,从左到右的顺序紧凑排列的。如图所示就是堆的结构(图片上有儿子大父亲小的,也有相反的,在这里以儿子大父亲小为例说明)
这里写图片描述

堆的操作一般就插入和删除两个。

堆的插入比较简单,就是将要插入的数据放在末尾,然后不断的向上提升,直到不能提升为止。在这里不用指针来实现,用数组,儿子编号满足
- 左儿子编号是自己编号×2+1
- 右儿子编号是自己编号×2+2

具体操作如图所示
这里写图片描述

实现插入的操作

int head[MAX_N],sz = 0;
void push(int x) {
    //自己节点的编号
    int i = sz++;

    while(i > 0) {
        //父亲节点的编号
        int p = (i-1)/2;

        //如果已经没有大小颠倒就退出
        if(head[p] <= x)
            break;

        //把父亲节点放下来自己提上去
        head[i] = head[p];
        i = p;
    }

    head[i] = x;
}

删除最小值的时候,首先把堆的最后一个节点的数值复制到根节点上,并且删除最后一个节点,然后不断交换,直到没有大小颠倒为止。在向下交换中,如果有两个儿子节点,那么选择数值较小(如果儿子节点比自己小的话)的儿子节点进行交换。

实现方法如图所示
这里写图片描述

代码实现

int head[MAX_N],sz = 0;

int pop() {
    //最小值
    int ret = head[0];

    //要提到根的数值
    int x = head[--sz];

    //从根开始往下交换
    int i = 0;
    while(i*2 + 1 < sz) {
        int a = i*2 + 1;
        int b = i*2 + 2;

        //比较儿子的值
        if(b < sz && head[a] > head[b]) a = b;

        //没有大小交换就退出
        if(head[a] > x) break;

        //把儿子的值提上来
        head[i] = head[a];
        i = a;
    }

    head[i] = x;
    return  ret;
}

其实优先队列的实现就是用的堆。每次关于堆的操作(插入,删除)都能够在O(logn)的复杂度之内完成。所以在平时不会手写堆,一般都用优先队列来实现。

原文地址:https://www.cnblogs.com/GoldenFingers/p/9107161.html