堆的創建及插入刪除堆頂元素等基本操作
- 用模板參數來調整大小堆
#include<stdio.h>
#include<vector>
#include<assert.h>
#include<iostream>
using namespace std;
//下面是實現的小堆,同時我們也要實現大堆(只是將交換比較的小於號都改成大於號),爲了實現代碼的複用率,我們多添加一個模板參數---比較器(容器適配器)
//容器適配器的兩種實現:模板的模板參數,模板參數
template<class T>
struct Less//小堆
{
bool operator()(const T& left,const T& right)//重載(),在裏面實現對<號的實現
{
return left<right;
}
};
template<class T>
struct Greater
{
bool operator()(const T& left,const T& right)
{
return left>right;
}
};
//直接對數據進行操作
template<class T,class Complare = Less<T> >//模板參數實現比較器,Complare是一個類(Less 或則Greater)
class heap
{
public:
heap()
:_heap(NULL)
{}
heap(const T array[],size_t size)
{
//找到倒數第一個非葉子節點,即最後一個節點(下標爲i)的雙親節點(i-1)/2
//從該節點的位置開始判斷其最小子節點是否小於雙親節點,即向下調整判斷法
//若小於,則交換位置,並且向下判斷,更新雙親節點爲子節點,重複執行上面的代碼
//若大於,則不交換,判斷上一個節點(層序遍歷倒數第二個節點),退出當前節點的遍歷
//爲什麼不能用數組???
_heap.resize(size);
for(int idx=0; idx<_heap.size(); ++idx)//初始化容器
_heap[idx] = array[idx];
//_heap.push_back(array[idx]);
int parent = (size-2)>>1;
for(; parent>=0; --parent)
{
AdjustDown(_heap,parent);
}
}
size_t Size()const
{
return _heap.size();
}
bool Empty()const
{
return _heap.empty();
}
const T& Top()const
{
return _heap[0];
}
void Insert(const T& value)//堆的任意插入
{
_heap.push_back(value);
if(_heap.size()>1)
{
AdjustUp();
}
}
void Remove()//刪除堆頂的元素
{
//刪除堆頂的元素,將堆頂的元素和最後一個節點進行交換,然後push_back最後一個元素,利用向下調整的方法調整小堆
assert(!_heap.empty());
int last = _heap.size()-1;
swap(_heap[0],_heap[last]);
_heap.pop_back();
AdjustDown(_heap,0);//因爲現在只有根節點發生改變,左右子樹還是滿足最小堆的條件的,所以我們只要調整根節點就好
//利用向下調整的方法(注意這和堆的創建是不同的,堆的創建是從倒數第一個非葉子節點開始調整)
//int parent = (_heap.size()-2)>>1;
//for(; parent>=0; --parent)
//{
// AdjustDown(_heap,parent);
//}
}
private:
void AdjustDown(vector<T>& _heap,int parent)//向下調整
{
Complare com;//比較器,當比較器是Less(默認)是小堆,當比較器是Greater是大堆
int child = parent*2+1;
while(child<_heap.size())
{
if((child+1)<_heap.size() && com(_heap[child+1],_heap[child]))//當_heap[child]>_heap[child+1]時,才進入循環,交換左右參數順序
{
child = child+1;
}
if(com(_heap[child],_heap[parent]))//當_heap[child]<_heap[parent]時,進入判斷判斷體
{
swap(_heap[parent],_heap[child]);
parent = child;
child = 2*parent+1;
}
else
{
return;
}
}
}
void AdjustUp()
{
Complare com;
size_t child = _heap.size()-1;//插入節點的下標,也是堆中最後一個節點
size_t parent = (child-1)>>1;//倒數第一個非葉子節點
while(child != 0)
{
if(com(_heap[child],_heap[parent]))//插入節點的兄弟節點一定比雙親節點大(小堆)
{
swap(_heap[child],_heap[parent]);
child = parent;
parent = (child-1)>>1;
}
else
{
return;
}
}
}
private:
vector<T> _heap;
};
- 用模板的模板參數實現大小堆
template<class T,template<class> class Complare =Less >//模板的模板參數實現比較器,Complare是一個模板類
class heap
{
public:
heap()
:_heap(NULL)
{}
heap(const T array[],size_t size)
{
//找到倒數第一個非葉子節點,即最後一個節點(下標爲i)的雙親節點(i-1)/2
//從該節點的位置開始判斷其最小子節點是否小於雙親節點,即向下調整判斷法
//若小於,則交換位置,並且向下判斷,更新雙親節點爲子節點,重複執行上面的代碼
//若大於,則不交換,判斷上一個節點(層序遍歷倒數第二個節點),退出當前節點的遍歷
//爲什麼不能用數組???
_heap.resize(size);
for(int idx=0; idx<_heap.size(); ++idx)//初始化容器
_heap[idx] = array[idx];
//_heap.push_back(array[idx]);
int parent = (size-2)>>1;
for(; parent>=0; --parent)
{
AdjustDown(_heap,parent);
}
}
size_t Size()const
{
return _heap.size();
}
bool Empty()const
{
return _heap.empty();
}
const T& Top()const
{
return _heap[0];
}
void Insert(const T& value)//堆的任意插入
{
_heap.push_back(value);
int parent = (_heap.size()-2)>>1;
//AdjustUp(_heap,parent);
AdjustUp();
}
void Remove()//刪除堆頂的元素
{
//刪除堆頂的元素,將堆頂的元素和最後一個節點進行交換,然後push_back最後一個元素,利用向下調整的方法調整小堆
int last = _heap.size()-1;
swap(_heap[0],_heap[last]);
_heap.pop_back();
AdjustDown(_heap,0);//因爲現在只有根節點發生改變,左右子樹還是滿足最小堆的條件的,所以我們只要調整根節點就好
//利用向下調整的方法(注意這和堆的創建是不同的,堆的創建是從倒數第一個非葉子節點開始調整)
//int parent = (_heap.size()-2)>>1;
//for(; parent>=0; --parent)
//{
// AdjustDown(_heap,parent);
//}
}
private:
void AdjustDown(vector<T>& _heap,int parent)//向下調整
{
int child = parent*2+1;
while(child<_heap.size())
{//建立一個類模板的無名對象調用()重載函數
if((child+1)<_heap.size() && Complare<T>()(_heap[child+1],_heap[child]))//當_heap[child]>_heap[child+1]時,才進入循環,交換左右參數順序
{
child = child+1;
}
if(Complare<T>()(_heap[child],_heap[parent]))//當_heap[child]<_heap[parent]時,進入判斷判斷體
{
swap(_heap[parent],_heap[child]);
parent = child;
child = 2*parent+1;
}
else
{
return;
}
}
}
void AdjustUp()
{
size_t child = _heap.size()-1;//插入節點的下標,也是堆中最後一個節點
size_t parent = (child-1)>>1;//倒數第一個非葉子節點
while(child != 0)
{
if(Complare<T>()(_heap[child],_heap[parent]))//插入節點的兄弟節點一定比雙親節點大(小堆)
{
swap(_heap[child],_heap[parent]);
child = parent;
parent = (child-1)>>1;
}
}
}
private:
vector<T> _heap;
};