基本数据结构 —— 堆以及堆排序(C++实现)

目录

  • 什么是堆
  • 堆的存储
  • 堆的操作
    • 结构体定义
    • 判断是否为空
    • 往堆中插入元素
    • 从堆中删除元素
    • 取出堆中最大的元素
  • 堆排序
  • 测试代码
  • 例题
  • 参考资料

什么是堆

堆(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

通常将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的存储

堆一般使用数组存储。当堆中有n个元素的时,可以将这些元素存放在数组array的前n个单元里,其中堆的根节点中元素存放在array[1]中。结点之间的关系有两种情况:

  • 如果根节点在数组中的位置是1,那么第i个位置的左右节点下标分别为2i、2i+1,父节点下标为i/2。
  • 如果根节点在数组中的位置是0,那么第i个位置的左右节点下标分别为2i+1、2i+2,父节点下标为?(i-1) /2?。

堆的操作

以大根堆为例,给出堆支持的一些操作。

结构体定义

struct Heap
{
    int size;   // number of elements in array
    int *array;
    Heap()  //init
    {
        size = 0;
        array = new int[maxn];
    }
    Heap(int n) //init
    {
        size = 0;
        array = new int[n];
    }
    ~Heap() //free memory
    {
        delete array;
    }
};

判断是否为空

    bool empty()
    {
        if(size != 0) return false;
        return true;
    } 

往堆中插入元素

    void insert(int value)
    {
        array[++size] = value; // 数组的最末尾插入新节点
        int index = size;
        while(index > 1)    // 自下而上地调整子节点与父节点的位置
        {
            // 如果大于父节点的值,根据最大堆的特点,子节点上升,而父节点要下降
            if(array[index] > array[index/2]) swap(array[index],array[index/2]);
            index /= 2; // 继续向上搜索
        }
    }

从堆中删除元素

    void del()
    {
        if(empty()) return; // 删除前不能为空
        swap(array[1],array[size--]); //用数组最末尾节点覆盖被删节点
        int index = 1;
        while(2*index <= size) // 从上到下调整二叉堆
        {
            int next = 2*index;
            // 选取子节点中最大的
            if(next < size && array[next+1] > array[next]) next++;
            // 与子节点中最大的比较,如果小于则当前结点下降
            if(array[index] < array[next])
            {
                swap(array[index],array[next]);
                index = next;
            }
            else break;
        }
    }

取出堆中最大的元素

    int max() {
        if(empty()) return -1;
        return array[1];
    }

堆排序

给定一个有size个元素的数组array,可用下面的算法buildHeap(array,size)O(n) 时间内将数组array调整为一个堆。

void buildHeap(int array[],int size)
{
    int i,tmp,index;
    for(i = size/2; i >= 1; i--)
    {
        tmp = array[i];
        index = 2*i;
        while(index <= size)
        {
            if(index < size && array[index+1] > array[index]) index++;
            if(array[index] < tmp) break;
            array[index/2]  = array[index];
            index *= 2;
        }
        array[index/2] = tmp;
    }
}

测试代码

#include<iostream>
#include<algorithm>
#define maxn 1001   //heap's size

using namespace std;

struct Heap {
    int size;   // number of elements in array
    int *array;
    Heap() {    //init
        size = 0;
        array = new int[maxn];
    }
    Heap(int n) {   //init
        size = 0;
        array = new int[n];
    }
    ~Heap() {   //free memory
        delete array;
    }
    bool empty() {
        if(size != 0) return false;
        return true;
    }
    void insert(int value) {
        array[++size] = value;
        int index = size;
        while(index > 1) {
            if(array[index] > array[index/2]) swap(array[index],array[index/2]);
            index /= 2;
        }
    }
    void del()
    {
        if(empty()) return;
        swap(array[1],array[size--]);
        int index = 1;
        while(2*index <= size)
        {
            int next = 2*index;
            if(next < size && array[next+1] > array[next]) next++;
            if(array[index] < array[next])
            {
                swap(array[index],array[next]);
                index = next;
            } else break;
        }
    }
    int max() {
        if(empty()) return -1;
        return array[1];
    }
};
void buildHeap(int array[],int size) {
    int i,tmp,index;
    for(i = size/2; i >= 1; i--) {
        tmp = array[i];
        index = 2*i;
        while(index <= size) {
            if(index < size && array[index+1] > array[index]) index++;
            if(array[index] < tmp) break;
            array[index/2]  = array[index];
            index *= 2;
        }
        array[index/2] = tmp;
    }
}
int main() {
    int n,i,j,k;
    cout << "input heap's size:";
    cin >> n;
    Heap H = Heap(n);
    int* array = new int[n];
    for(i = 1; i <= n; i++) {
        int tmp;
        cin >> tmp;
        array[i] = tmp;
        H.insert(tmp);
    }
    buildHeap(array,n);
    for(i = 1; i <= n; i++) {
        cout << array[i] << " ";
    }
    cout << endl;
    while(!H.empty()) {
        cout << H.max() << endl;
        H.del();
    }
    return 0;
};

结果:

例题

最小的K个数 —— 剑指offer

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。

class Solution {
public:
    struct Heap {
        int size;   // number of elements in array
        int *array;
        Heap() {    //init
            size = 0;
            array = new int[1001];
        }
        Heap(int n) {   //init
            size = 0;
            array = new int[n];
        }
        ~Heap() {   //free memory
            delete array;
        }
        bool empty() {
            if(size != 0) return false;
            return true;
        }
        void insert(int value) {
            array[++size] = value;
            int index = size;
            while(index > 1) {
                if(array[index] < array[index/2]) swap(array[index],array[index/2]);
                index /= 2;
            }
        }
        void del()
        {
            if(empty()) return;
            swap(array[1],array[size--]);
            int index = 1;
            while(2*index <= size)
            {
                int next = 2*index;
                if(next < size && array[next+1] < array[next]) next++;
                if(array[index] > array[next])
                {
                    swap(array[index],array[next]);
                    index = next;
                } else break;
            }
        }
        int min() {
            if(empty()) return -1;
            return array[1];
        }
    };
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> ret;
        int i,n = input.size();
        if(n < k) return ret;
        Heap H = Heap(n);
        for(i = 0;i < n;i++)
        {
            H.insert(input[i]);
        }
        while(k)
        {
            ret.push_back(H.min());
            H.del();
            k--;
        }
        return ret;
    }
};

参考资料

原文地址:https://www.cnblogs.com/multhree/p/10507994.html

时间: 2024-10-30 11:09:54

基本数据结构 —— 堆以及堆排序(C++实现)的相关文章

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

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

数据结构与算法之美-堆和堆排序

堆和堆排序 如何理解堆 堆是一种特殊的树,只要满足以下两点,这个树就是一个堆. ①完全二叉树,完全二叉树要求除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列. ②树中每一个结点的值都必须大于等于(或小于等于)其子树中每个节点的值.大于等于的情况称为大顶堆,小于等于的情况称为小顶堆. 如何实现堆 如何存储一个堆 完全二叉树适合用数组来存储,因为数组中对于下标从1开始的情况,下标为i的节点的左子节点就是下标为i*2的节点,右子节点就是i下标为i*2+1的节点,其父节点时下标为i/2的

白话经典算法系列之七 堆与堆排序

堆排序与高速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先解说下什么是数据结构中的二叉堆. 二叉堆的定义 二叉堆是全然二叉树或者是近似全然二叉树. 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)不论什么一个子节点的键值. 2.每一个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆). 当父结点的键值总是大于或等于不论什么一个子节点的键值时为最大堆.当父结点的键值总是小于或等于不论什么一个子节点的键值时为最小堆.下图展示一个最小堆

利用堆实现堆排序&amp;优先队列

数据结构之(二叉)堆 一文末尾提到"利用堆可以实现:堆排序.优先队列".本文代码实现之. 1.堆排序 假设要将无序数组按非递减(递增)排序,则应使用大(小)顶堆.这里涉及到大堆排序涉及到三种操作:(1).MaxHeapify操作(自顶向下即SiftDown操作):(2).BuildMaxHeap操作(线性时间内将无序数组构造成一个最大堆):(3)将堆顶元素和堆的最后一个元素交换,并将堆元素大小减去1,对堆顶元素调用MaxHeapify操作重新调整为大顶堆,重复直到数组有序.下面是详细的

堆、二叉堆、堆排序

堆.二叉堆.堆排序 堆的概念: n个元素序列 { k1, k2, k3, k4, k5, k6 -. kn } 当且仅当满足以下关系时才会被称为堆: ki <= k2i,ki <= k2i+1 或者 ki >= k2i,ki >= k2i+1 (i = 1,2,3,4 .. n/2) 如果数组的下表是从0开始,那么需要满足 ki <= k2i+1,ki <= k2i+2 或者 ki >= k2i+1,ki >= k2i+2 (i = 0,1,2,3 .. n

白话经典算法系列之七 堆与堆排序(转)

堆排序与快速排序,归并排序一样都是时间复杂度为O(N*logN)的几种常见排序方法.学习堆排序前,先讲解下什么是数据结构中的二叉堆. 二叉堆的定义 二叉堆是完全二叉树或者是近似完全二叉树. 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值. 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆). 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆.当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆.下图展示一个最小堆: 由于其它几

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

基本数据结构――堆的基本概念及其操作 小广告:福建安溪一中在线评测系统 Online Judge 在我刚听到堆这个名词的时候,我认为它是一堆东西的集合... 但其实吧它是利用完全二叉树的结构来维护一组数据,然后进行相关操作,一般的操作进行一次的时间复杂度在 O(1)~O(logn)之间. 可谓是相当的引领时尚潮流啊(我不信学信息学的你看到log和1的时间复杂度不会激动一下下)!. 什么是完全二叉树呢?别急着去百度啊,要百度我帮你百度: 若设二叉树的深度为h,除第 h 层外,其它各层 (1-h-1

【算法与数据结构】图说堆排序

1.堆   一棵完全二叉树 大顶堆:所有非叶子节点元素均不小于其左右子树根节点的值 小顶堆:所有非叶子节点元素均不大于其左右子树根节点的值 2. 初始化堆 ①一组无序元素R[0, 1, ..., n - 1], 先按照顺序将该组无序元素构造为一棵完全二叉树 ②从该二叉树的第一个非叶子结点开始调整,然后调整前一个结点(一定是非叶子结点),依次直到调整完根节点 ③上一步一遍完成后,再来一遍,直到该完全二叉树符合一个堆的定义为止 测试数据:R[] = {16, 7, 3, 20, 17, 8}, 本组

【C/C++学院】0828-STL入门与简介/STL容器概念/容器迭代器仿函数算法STL概念例子/栈队列双端队列优先队列/数据结构堆的概念/红黑树容器

STL入门与简介 #include<iostream> #include <vector>//容器 #include<array>//数组 #include <algorithm>//算法 using namespace std; //实现一个类模板,专门实现打印的功能 template<class T> //类模板实现了方法 class myvectorprint { public: void operator ()(const T &