zoukankan      html  css  js  c++  java
  • 堆和栈及其实现方法

                                             关于堆和栈
    

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


    首先是,栈很好理解,就和它的名字一样先进后出表,先进栈的元素会相对后面出栈,如图所示
    这里写图片描述
    在代码实现方面可以使用数组来模拟,但是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)的复杂度之内完成。所以在平时不会手写堆,一般都用优先队列来实现。

  • 相关阅读:
    Django学习之路
    Bootstrap插件及其应用方法网址
    BOM和DOM
    jQuery学习
    初识JS之数据类型
    前端学习之路CSS基础学习二
    前端学习之路CSS基础学习一
    前端学习之路
    ORM
    Python Twisted 学习系列4(转载stulife最棒的Twisted入门教程)
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107161.html
Copyright © 2011-2022 走看看