Abstact
数据结构与算法分析:C语言描述介绍了一种数据结构:d-堆。通常的堆是二叉堆:也就是完全二叉树。d-堆是每个结点有d个儿子。这篇blog来实现d-heap.
d-heap
在二叉堆里:如果一个结点的下标是i,那么它的父亲下标是i/2,它的左儿子结点下标是2i,右儿子结点下标是2i+1。 正因为这种特殊的规律,所以二叉堆的实现非常优美(自我感觉的)
但是在d-heap里有这些规律吗?
d-heap中父亲和儿子的关系
child(i,j) = d*(i-1)+2+j (i是父亲结点的下标,j是第几个儿子,范围是0~d-1)
parent(i) = (i-2+d)/d
last_have_leaf = (size()+1)/d (这是d-heap最后一个有叶子的结点。在heap里是size()/2)
上面就是d-heap中父亲和儿子的关系。
下面是我举个小栗子:
implement
d-heap的ADT有
void clear(); //清空堆
unsigned size()const; // 返回堆大小
void insert(int x); //插入元素
int findmin()const; //返回堆顶元素
void deletemin(); //删除堆顶元素
bool isempty()const; //堆是否为空
/*
这两个函数是以O(n)构建堆。
把输入的N个元素随意放在树中,在执行percplate(i),从结点i下滤。(percplate其实和堆排序里辅助函数是一样的,我就不详细写了)
我在构造函数里使用这两个函数。dheap(int D,const std::vector<int>& data);
*/
void buildheap();
void percplate(int);
d-heap的实现和二叉堆差不多:我就懒的写了。
#pragma once
#include<vector>
#include<initializer_list>
#include<climits>
#define MIN INT_MIN
using std::initializer_list;
class dheap
{
public:
dheap(int D) :d(D) {
_root.push_back(MIN);
}
dheap(int D,const std::vector<int>& data);
~dheap()=default;
void clear();
unsigned size()const;
void insert(int x);
int findmin()const;
void deletemin();
bool isempty()const;
private:
int parent(int son) {
return (son - 2 + d) / d;
}
int child(int parent, int time) { //time is 0 ~ d-1
return (time >= this->d )?-1:d * (parent - 1) + 2 + time;
}
void buildheap();
void percplate(int);
std::vector<int> _root;
int d;
};
#include "dheap.h"
#include<algorithm>
#include<iostream>
dheap::dheap(int D, const std::vector<int>& data):d(D)
{
_root.push_back(MIN);
for (auto x : data)
_root.push_back(x);
buildheap();
}
void dheap::clear()
{
_root.erase(_root.begin()+1,_root.end());
}
unsigned dheap::size() const
{
return _root.size() - 1;
}
void dheap::insert(int x)
{
_root.push_back(x);
int i;
for (i = size(); x < _root[this->parent(i)]; i = parent(i)) { // 如果x的值大于父亲的值,则父亲下,
_root[i] = _root[parent(i)];
}
_root[i] = x;
}
int dheap::findmin() const
{
return isempty() ? _root[0]:_root[1] ;
}
void dheap::deletemin()
{
if (!isempty()) {
int minvalue = findmin(), lastvalue = _root.back(), i,_child;
_root.pop_back();
for (i = 1; this->child(i,0) <= this->size(); i = _child) { // child(i,0) i的第一个孩子 ,第一个孩子小于size(),证明i有孩子
_child = this->child(i, 0); //找最小的孩子
if (_child + d - 1 <= size()) //有d个儿子
_child =std::distance(_root.begin(),std::min_element(_root.begin()+_child,_root.begin()+_child+d));
else //没有d个儿子
_child = std::distance(_root.begin(), std::min_element(_root.begin() + _child, _root.end()));
if (lastvalue > _root[_child])
_root[i] = _root[_child];
else
break;
}
if(this->size()!=0)
_root[i] = lastvalue;
}
else
return;
}
bool dheap::isempty() const
{
return size() == 0 ? true: false;
}
void dheap::buildheap()
{
for (int i = (this->size()+1)/this->d; i > 0; i--)
this->percplate(i);
}
void dheap::percplate(int i)
{
int temp = _root[i], _child; // i always is father
for (_child = this->child(i,0); _child < this->size(); _child = this->child(i,0)) { // _child is i`s son,now find min`s son
if (_child + d - 1 <= size()) //有d个儿子
_child = std::distance(_root.begin(), std::min_element(_root.begin() + _child, _root.begin() + _child + d));
else //没有d个儿子
_child = std::distance(_root.begin(), std::min_element(_root.begin() + _child, _root.end()));
if (temp > _root[_child])
_root[i] = _root[_child];
else
break;
i = _child;
}
_root[i] = temp;
}