堆实现及常见面试题

一、堆的概念:
关键码的集合按完全二叉树的顺序存储方式存储在一维数组中,并满足:对于所有节点它的父节点关键码都大于子节点(或都小于它的子节点),这样的堆称为最大堆(或最小堆)。
二、堆相关的问题
1.简单实现一个堆 堆的建立、放入数据、删除数据、判断是否为堆
2.TopK问题,求数组中最大的K个元素
3.堆排序(实质是一个选择排序),一个数组的升序、降序 
三、下面例子中,博主是以建最大堆的方式实现的堆,在实现TopK中需要建小堆,博主又另写了一个建小堆的函数。
***Autually***, 这是一种较为笨的方法,可以实现一个仿函数,增加函数的复用性,这样建小堆建大堆就不用建不同的堆了。
代码如下:
#pragma once

#include <iostream>
#include <vector>
#define N 10000
using namespace std;

template<class T>
class Heap
{
public:
    Heap()
    {}

    Heap(T* a, size_t n)
    {
        _a.reserve(n);
        for (size_t i = 0; i < n; i++)
        {
            _a.push_back(a[i]);
        }
        //建堆
        for (int i = (_a.size() - 2) / 2; i >= 0; --i)//从倒数第一个非叶节点开始
        {
            AdjustDown(i);
        }

    }


    HeapT(T* a, size_t k)//实现TopK建堆方式
    {
        _a.reserve(k);

        for (size_t i = 0; i < k; i++)
        {
            _a.push_back(a[i]);
        }

        for (int i = (_a.size() - 2) / 2; i >= 0; --i)//建小堆
        {
            AdjustDownL(i);
        }
    }
    void TopK(T* a)
    {
        for (size_t i = 100; i < N;)
        {
            if (_a[0] < a[i])
            {
                _a[0] = a[i];
                AdjustDownL(0);
                ++i;
            }
            else
            {
                ++i;
            }
        }
    }

    void HeapRiseSort(T* a, size_t k)//升序建大堆 降序降序建小堆
    {
        _a.reserve(k);
        int end = k - 1;
        Heap(a, k);//建堆
        while (end > 0)
        {
            swap(_a[0], _a[end]);
            end--;
            AdjustDown(0);
            //堆排序(升序),每次把堆顶数据放到数组后面,再利用前end个元素重新建大堆
        }

    }


    void Print()
    {
        for (size_t i = 0; i < _a.size(); i++)
        {
            cout << _a[i] << " ";
        }
        cout << endl;
    }
        void Push(const T& x)
        {
            _a.push_back(x);

            AdjustUp(_a.size()-1);
        }

        void AdjustUp(int child)
        {
            int parent = (child - 1) >> 1;
            while (child != 0)
            {
                if (_a[child] > _a[parent])
                {
                    swap(_a[child], _a[parent]);
                    child = parent;
                    parent = (child - 1) >> 1;
                }
                else
                {
                    break;
                }
            }
        }

        void Pop()
        {
            swap(_a[0], _a[_a.size() - 1]);
            _a.pop_back();
            AdjustDown(0);
        }

        void AdjustDown(int root)
        {
            int parent = root;
            int child = parent * 2 + 1;
            while (child < _a.size())
            {
                if (child + 1 < _a.size() && _a[child + 1] > _a[child])//选出大的孩子(存在右孩子)
                {
                    ++child;
                }
                if (_a[child] > _a[parent])
                {
                    swap(_a[child], _a[parent]);
                    parent = child;
                    child = child * 2 + 1;
                }
                else
                {
                    break;
                }
            }
        }

        void AdjustDownL(int root)
        {
            int parent = root;
            int child = parent * 2 + 1;
            while (child < _a.size())
            {
                if (child + 1 < _a.size() && _a[child + 1] < _a[child])//选出大的孩子(存在右孩子)
                {
                    ++child;
                }
                if (_a[child] < _a[parent])//建最小堆
                {
                    swap(_a[child], _a[parent]);
                    parent = child;
                    child = child * 2 + 1;
                }
                else
                {
                    break;
                }
            }
        }

        int IsBHeap()
        {
            for (int i = _a.size() - 1; i >= 0; i++)
            {
                return _IsBHeap(i)==true;//为真返回1,假0
            }
        }


protected:
    bool _IsBHeap(int root)
    {
        int child = root;
        int parent = (child - 1) >> 1;
        while (child<_a.size())
        {
            int large = child;
            if (child + 1<_a.size() && _a[child + 1]>_a[child])
            {
                large = child + 1;
            }
            if (_a[large] < _a[parent])
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        return false;
    }

    vector<T> _a;
};    

测试用例:

#pragma once

#include "Heap.h"


void Heaptest()
{
    int arr[] = { 10, 11, 13, 12, 16, 18, 15, 17, 14, 19 };
    Heap<int>h1(arr, sizeof(arr)/sizeof(arr[0]));
    h1.Print();
    h1.Pop();
    h1.Print();
    h1.Push(20);
    h1.Print();

    h1.Push(2);
    cout << h1.IsBHeap() << endl;
}

void topKTest()
{
    int arr[N] = { 0 };
    for (size_t i = 0; i < N; i++)
    {
        arr[i] = rand() % N;
    }
    arr[100] = 12000;
    arr[999] = 11145;
    arr[888] = 10008;
    arr[118] = 19999;
    arr[365] = 19880;
    arr[254] = 13444;
    arr[4579] = 14555;
    arr[1000] = 47839;
    arr[9992] = 19875;
    arr[1723] = 98345;
    HeapT<int>h1(arr, 10);
    h1.TopK(arr);
    h1.Print();
}

//堆排序实质上是一种选择排序,选出最大的与尾部数据交换,然后堆元素个数--,重新建堆,相当于没把刚刚选出的最大的数算在重新建的堆中
void Heaptest()
{
    int arr[] = { 10, 11, 13, 12, 16, 18, 15, 17, 14, 19 };
    Heap<int>h1(arr, 10);
    h1.HeapRiseSort(arr,10);
    h1.Print();
}

堆就讲到这里啦,之后会给大家补充仿函数和堆的相关知识,拜拜~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值