template
void Heap::PercolateUp() //为了向上调整为堆,我们需要比较当前节点和其父节点的值,如果父节点的值比当前节点大,则交换它们的值。
{int p = size - 1, c = (p - 1) / 2;//`c`表示当前节点的父节点,`p`表示当前节点。
T temp = vec[p];
while (p > 0) //为什么不是c>0
//在`while`循环中,我们判断当前节点是否已经到达根节点,如果是根节点则停止循环。所以条件应该是`p > 0`,而不是`c > 0`。
{
if (vec[c] <= temp)
break;
else
{
vec[p] = vec[c];
p = c;
c = (p - 1) / 2;
}
}
vec[p] = temp; //写在while 里面还是外面? 目前结点最后会空出来
}
template
void Heap::PercolateDown(int h)// 向下调整为堆,如果父亲节点(目前结点)比孩子结点(较小值)大交换
{
int p = h, c = 2 * p + 1;// c为p的左孩子
T temp = vec[h]; //不定类型 不用写成int
while (c < size) //怎么修改? 向下控制边界,不能让它超过size
{
if (c + 1 < size && vec[c + 1] < vec[c]) //左孩子的下标小于size-1(最后一个叶子结点)&&找到左右孩子的最小值//c < size表示当前节点有左孩子,而c + 1 < size表示当前节点有右孩子。根据堆的性质,选择较小的孩子进行交换。
{
++c;
}
if (temp <= vec[c])
break;
else
{
vec[p] = vec[c];
p = c;
c = 2 * p + 1;
}
}
vec[p] = temp;
}
-
- #include
- #include
- #include
- using namespace std;
-
- template<class T>
- struct BTNode
- {
- T data;
- BTNode* left, * right;
- BTNode(const T& item = T(), BTNode* lptr = NULL, BTNode* rptr = NULL) :
- data(item), left(lptr), right(rptr) {}
- };
-
- void Gotoxy(int x, int y)
- {
- static int level = 0, indent = 0;
- if (y == 0)
- {
- indent = 0;
- level = 0;
- }
- if (level != y)
- {
- cout << endl;
- indent = 0;
- level++;
- }
- cout.width(x - indent);
- indent = x;
- }
-
- template<class T>
- BTNode
* GetBTNode(const T& item, BTNode* lp = NULL, BTNode* rp = NULL) - {
- BTNode
* p; - p = new BTNode
(item, lp, rp); - if (p == NULL)
- {
- cout << "error!" << endl;
- }
- return p;
- }
-
- struct Location
- {
- int xindent, ylevel;
- };
-
- template<class T>
- void PrintBTree(const BTNode
* t, int screenwidth) - {
- if (t == NULL)
- {
- return;
- }
- int level = 0, offset = screenwidth / 2;
- Location floc, cloc;
- queue<const BTNode
*> Q; - queue
LQ; - floc.xindent = offset;
- floc.ylevel = level;
- Q.push(t);
- LQ.push(floc);
- while (!Q.empty())
- {
- t = Q.front();
- floc = LQ.front();
- Q.pop();
- LQ.pop();
- Gotoxy(floc.xindent, floc.ylevel);
- cout << t->data;
- if (floc.ylevel != level)
- {
- level++;
- offset = offset / 2;
- }
- if (t->left)
- {
- Q.push(t->left);
- cloc.ylevel = floc.ylevel + 1;
- cloc.xindent = floc.xindent - offset / 2;
- LQ.push(cloc);
- }
- if (t->right)
- {
- Q.push(t->right);
- cloc.ylevel = floc.ylevel + 1;
- cloc.xindent = floc.xindent + offset / 2;
- LQ.push(cloc);
- }
- }
- cout << endl;
-
- }
-
- template<class T>
- class Heap //小根堆 根->叶子 小到大
- {
- vector
vec; - int size;
- void BuildHeap(void);
- void PercolateUp();
- void PercolateDown(int h);
- public:
- Heap(int max = 100) : vec(max), size(0) {}
- Heap(const vector
& vt); - int Size()
- {
- return size;
- }
- void Insert(const T& item);
- void DeleteMin(void);
- void DeleteMin(T& item);
- };
-
- template<class T>
- void Heap
::PercolateUp() //为了向上调整为堆,我们需要比较当前节点和其父节点的值,如果父节点的值比当前节点大,则交换它们的值。 - {
-
- int p = size - 1, c = (p - 1) / 2;//`c`表示当前节点的父节点,`p`表示当前节点。
- T temp = vec[p];
- while (p > 0) //为什么不是c>0
-
-
- //在`while`循环中,我们判断当前节点是否已经到达根节点,如果是根节点则停止循环。所以条件应该是`p > 0`,而不是`c > 0`。
-
-
- {
- if (vec[c] <= temp)
- break;
- else
- {
- vec[p] = vec[c];
- p = c;
- c = (p - 1) / 2;
- }
- }
- vec[p] = temp; //写在while 里面还是外面? 目前结点最后会空出来
- }
-
- template<class T>
- void Heap
::PercolateDown(int h)// 向下调整为堆,如果父亲节点(目前结点)比孩子结点(较小值)大交换 - {
- int p = h, c = 2 * p + 1;// c为p的左孩子
- T temp = vec[h];
- while (c < size) //怎么修改?
- {
- if (c + 1 < size && vec[c + 1] < vec[c]) //左孩子的下标小于size-1(最后一个叶子结点)&&找到左右孩子的最小值
- {
- ++c;
- }
- if (temp <= vec[c])
- break;
- else
- {
- vec[p] = vec[c];
- p = c;
- c = 2 * p + 1;
- }
- }
- vec[p] = temp;
- }
-
- template<class T>
- void Heap
::Insert(const T& item) - {
- if (size == vec.size())
- {
- vec.resize(vec.size() *2);
- }
- vec[size] = item;
- size++;
- PercolateUp();
-
- }
-
- template<class T>
- void Heap
::BuildHeap(void) //从最后一个非叶子结点(a)开始,size-1是最后一个叶子结点,a是它的parent - {
- for (int i = size / 2 - 1; i >= 0; i--)
- {
- PercolateDown(i);//为该结点的子树调整成堆
- }
- }
-
- template<class T>
- void Heap
::DeleteMin() - {
- if (size == 0)
- {
- return;
- }
- vec[0] = vec[size - 1];
- size--;
- PercolateDown(0);
- }
-
- template<class T>
- void Heap
::DeleteMin(T& item) - {
- if (size == 0) //删除最小值需要判断堆是否为空
- {
- return;
- }
- item = vec[0];
- vec[0] = vec[size - 1];
- size--;
- PercolateDown(0);
- }
-
- template<class T>
- Heap
::Heap(const vector& vt) : vec(vt.size() + 10), size(vt.size()) - {
- for (int i = 0; i < size; i++)
- {
- vec[i] = vt[i];
- }
- BuildHeap();
- }
-
- template<class T>
- struct HuffmanNode
- {
- BTNode
* t; - int operator<(const HuffmanNode& h)//穿入参数是哈夫曼节点 bool类型
- {
- return (t->data < h.t->data);
- }
- int operator<=(const HuffmanNode& h)//穿入参数是哈夫曼节点
- {
- return (t->data <= h.t->data);
- }
- };
-
- template<class T>
- BTNode
* MakeHuffman(T* pa, int n) - {
- BTNode
* t, * right, * left; - HuffmanNode
hf; - Heap
> HF(n); - //第一个循环将数组里的元素插入到哈夫曼堆
- for (int i = 0; i < n; i++)
- {
- t = GetBTNode<int>(pa[i]);
- hf.t = t;
- HF.Insert(hf);
- }
- //第二个循环找到最小的两个数,生成根节点后删除
- for (int i = 1; i < n; i++)
- {
- HF.DeleteMin(hf);
- left = hf.t;
- HF.DeleteMin(hf);
- right = hf.t;
- t = GetBTNode(left->data + right->data, left, right);//t的左孩子是left,右孩子是right
- hf.t = t;
- HF.Insert(hf);
- }
- HF.DeleteMin(hf);//是一个对象调用函数
- t = hf.t;
- return t;
- };
-
- int main()
- {
- int a[] = { 7,5,2,4 };
- BTNode<int>* root;
- root = MakeHuffman(a, 4);
- PrintBTree(root, 40);
- cout << endl;
- return 0;
- }