什么是堆
堆(英語: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;
};
結果:
例題
輸入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;
}
};
參考資料
- 數據結構圖文解析之:二叉堆詳解及C++模板實現
- 《數據結構(C語言描述)(修訂版)》電子工業出版社