使用平台:vs2013
基础概念部分
堆:堆数据结构是一种数组对象,通过数组实现堆数据结构,可以看做是一颗完全二叉树结构。
堆分为大堆和小堆
大堆:每个父节点都大于子节点;
小堆:每个父节点都小于孩子节点。
堆实现过程主要用到的知识点
1>用parent代表父节点下标,chaild代表孩子节点下标,则:
chaild=parent*2+1
parent=(chaild-1)/2
2>通过仿函数实现大小堆代码的复用;
3>用vector实现Heap时,注意需要先把空间开辟出来,实现通过下标访问;
#pragma once
#include <iostream>
using namespace std;
#include <vector>
#include <assert.h>
template <class T>
struct Greater
{
bool operator()(const T& l, const T& r)
{
return l > r;
}
};
template <class T>
struct Less
{
bool operator()(const T& l, const T& r)
{
return l < r;
}
};
//默认建大堆
template <class T, class Compare = Greater<T>>
class Heap
{
public:
Heap()
{}
Heap(T* a, int n)
:_array(a, a + n)//利用迭代器实现开辟n个大小空间
{
for (int i = (_array.size() - 2) / 2; i >= 0; --i)
{
_AdjustDown(i);
}
}
void Push(const T& data)
{
_array.push_back(data);
_AdjustUp(_array.size() - 1);
}
void Pop()
{
//vector 有判空机制
swap(_array[0], _array[_array.size() - 1]);
_array.pop_back();
_AdjustDown(0);
}
size_t Size()
{
return _array.size();
}
bool Empty()
{
return _array.empty();
}
T& Top()
{
assert(!Empty());
return _array[0];
}
protected:
//向上调整
void _AdjustUp(int root)
{
int child = root;
int parent = (root - 1) / 2;
while (child >0)
{
Compare compare;
if (compare(_array[child], _array[parent]))
{
swap(_array[parent], _array[child]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
//向下调整
void _AdjustDown(int root)
{
int parent = root;
int child = parent * 2 + 1;
int size = _array.size();
//注意结束条件
while (child < size)
{
Compare compare;
if (child + 1 < size && compare(_array[child + 1], _array[child]))
{
++child;
}
if (compare(_array[child], _array[parent]))
{
swap(_array[parent], _array[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
protected:
vector<T> _array;
};
TopK问题
1>找最大的前K个数,建小堆
2>找最小的前K个数,建大堆
找最大的前K个数基本思想:
通过前K个数建立一个小堆,堆顶存放的是这K个数中最小的数,剩余的数和堆顶的数进行比较,大于堆顶数据,交换,堆顶数据进行向下调整。
//topK问题
void AdjustDown(int* arr,int root,int k)
{
int parent = root;
int child = parent * 2 + 1;
while (child < k)
{
if (child + 1 < k&&arr[child + 1] < arr[child])
++child;
if (arr[parent]>arr[child])
{
swap(arr[parent], arr[child]);
parent = child;
child = parent * 2 + 1;
}
else
{
break;
}
}
}
//1. 找最大的前K个数——建小堆
void GetTopK(int* arr,int size,int k)
{
//2.建堆——小堆
for (int i = (k-2)/2; i >=0; --i)
{
AdjustDown(arr,i,k);
}
//3.剩余数和堆顶数进行比较,大于堆顶数,和堆顶数进行交换,向下调整
int cur = k;
while (cur < size)
{
if (arr[0] < arr[cur])
{
swap(arr[0], arr[cur]);
AdjustDown(arr, 0, k);
++cur;
}
else
{
++cur;
}
}
//4.打印前K个数
for (int i = 0; i < k; ++i)
cout << arr[i] << " ";
cout << endl;
}
优先级队列:在库中优先级队列是通过堆来实现的
template <class T,class Compare=Greater<T>>
class PriorityQueque
{
public:
void Push(const T& data)
{
_hp.Push()
}
void Pop()
{
_hp.Pop();
}
bool Empty()
{
return _hp.Empty();
}
T& Top()
{
return _hp.Top();
}
protected:
Heap<T, Compare> _hp;
};
堆排序大致思路:
以降序为例,建小堆,堆顶数据为最小值,和最后一个数据进行交换,数组的可视范围减一,堆顶数据向下调整,直到数组大小减到0。
//降序——建小堆
void HeapSort(int* arr,int n)
{
assert(n>0);
//建堆
for (int i = (n - 2) / 2; i >= 0; --i)
{
AdjustDown(arr, i, n);
}
//调整顺序
int end = n - 1;
while (end > 0)
{
swap(arr[0], arr[end]);
AdjustDown(arr, 0, end);
--end;
}
for (int i = 0; i < n; ++i)
{
cout << arr[i] << " ";
}
cout << endl;
}
测试函数:
void TestHeap()
{
int arr[9] = { 1, 2, 5, 0, 7, 3, 8, 4, 6 };
Heap<int,Less<int>> hp(arr, sizeof(arr) / sizeof(arr[0]));
hp.Pop();
hp.Push(10);
//topk
int arr2[] = { 1, 2, 4, 3, 6, 5, 4, 9, 7, 8, 0 };
int size = sizeof(arr2) / sizeof(arr2[0]);
int k = 5;
GetTopK(arr2, size,k);
HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
}