二项堆

二项树是一颗递归定义的树。B0只有一个节点。二项树Bk由两棵二项树B(k-1)组成的,其中一棵树是另一棵树根的最左孩子。
二项树性质:
1. Bk共有2^k个节点。
2. Bk的高度为k。
3. Bk在深度i处恰好有C(k,i)个节点,其中i=0,1,2,...,k。
4. 根的度数为k,它大于任何其它节点的度数。把孩子编号从左到右为k-1,k-2,...,0。则孩子i为子树Bi的根。


二项堆:
1. 每个结点只有一个关键字。
2. 每棵二项树都满足最小堆性质。
3. 对非负整数k,H中最多有一个二项树的根的度数为k。
4. 结点数为n的二项堆最多只有  [lg(n)]+1  棵二项树(  [lg(n)]向下取整  )

template<class T>
struct Node
{
	T data;
	int degree;
	Node<T>* left;
	Node<T>* parent;
	Node<T>* next;
	Node(T k)
	{
		left = nullptr;
		parent = nullptr;
		next = nullptr;
		degree = 0;
		data = k;
	}
	Node()
	{
		left = nullptr;
		parent = nullptr;
		next = nullptr;
		degree = 0;
	}
};


template<class T>
class HeapTwo
{
private:
	Node<T>* head;
public:
	HeapTwo(Node<T>* s)
	{
		head = s;
	}
	HeapTwo()
	{
		head = nullptr;
	}
	~HeapTwo();
	void Destory(Node<T>* q);
	//c变成heap的左孩子
	friend void Link(Node<T>* c, Node<T>* heap);
	//将两个堆的根结点按度数大小排序
	friend Node<T>* SortMerge(Node<T>* h1,Node<T>* h2);
	//合并
	friend Node<T>* Union_F(Node<T>*& h1, Node<T>*& h2);
	void Union(HeapTwo<T>& h);
	//插入
	void Insert(T key);
	//搜索
	Node<T>* Search_(Node<T>* q,T key);
	Node<T>* Search(T key);

	//删除
	void Delete(T key);
	Node<T>* reverse(Node<T>* root);//分离出单个二项堆并反转  因为一个根节点下最左孩子度数最大(堆要求根结点度数从小到大排序)
	//打印堆
	void Out_(Node<T>* q);
	void Out();
	void top(Node<T>*& x,Node<T>*& pre);
	T min();
	T pop();
	void Decrease(Node<T>* q, T key);
	void Crease(Node<T>* q, T key);
};
template<class T>
void HeapTwo<T>::Destory(Node<T>* q)
{
	if (!q)
		return;
	Node<T>* p = q->left;
	while (p != nullptr)
	{
		p = p->next;
	}
	Destory(q->next);
	delete q;//递归到边界,开始delete
}
template<class T>
HeapTwo<T>::~HeapTwo()//析构
{
	Destory(head);
}
template<class T>//递归打印堆
void HeapTwo<T>::Out_(Node<T>* q)
{
	if (!q)
		return;
	cout << q->data << " -> ( ";
	Out_(q->left);
	cout << " )";
	Out_(q->next);
}
template<class T>
void HeapTwo<T>::Out()
{
	Out_(head);
	cout << endl;
}
template<class T>
void Link(Node<T>* c, Node<T>* heap)//c作为heap的left孩子
{
	c->parent = heap;
	c->next = heap->left;
	heap->left = c;
	heap->degree += 1;
}
//将两个堆的根结点按度数大小排序
template<class T>
Node<T>* SortMerge(Node<T>* h1, Node<T>* h2)
{
	Node<T>* q1 = h1;
	Node<T>* q2 = h2;
	Node<T>* head = nullptr;
	Node<T>** q = &head;//指向指针的指针,便于直接修改next值
	while (q1&&q2)
	{
		if (q1->degree < q2->degree)//度数小的在前
		{
			*q = q1;
			q1 = q1->next;
		}
		else
		{
			*q = q2;
			q2 = q2->next;
		}
		q = &((*q)->next);//q指向原q的next值,便于在 *q=q1/q2 时直接更新next
	}
	if (q1)
		*q = q1;
	else
		*q = q2;
	return head;
}

template<class T>
Node<T>* Union_F(Node<T>*& h1, Node<T>*& h2)
{
	Node<T>* q = SortMerge(h1, h2);
	Node<T>* root = q;
	if (q == nullptr)
		return nullptr;
	//度数相同的二项树最多有两个
	//当只有两个相同时直接将两个合并
	//当有三个子树的度数都相同,合并后两个(第三个子树是在合并过程中产生的)
	//维护三个指针,为当前结点,前一个结点和下一个结点
	Node<T>* next = q->next;
	Node<T>* pre = nullptr;
	while (next != nullptr)
	{
		if (q->degree != next->degree)//不必合并
		{
			pre = q;
			q = next;
			next = q->next;
		}
		else if (next->next != nullptr&&q->degree == next->degree&&
			next->degree == next->next->degree)//三个都相同,暂时不做操作,下一步合并后两个
		{
			pre = q;
			q = next;
			next = q->next;
		}
		//合并
		else if (q->data <= next->data)//q不移动,q的度数变化可能和后边的子树冲突
		{
			q->next = next->next;
			Link(next, q);//next作为孩子,更新next值
			next = q->next;
		}
		else
		{
			if (pre == nullptr)//q作为孩子,若q为head节点,更新head;否则由于q消失,更新pre->next
			{
				root = next;
			}
			else
			{
				pre->next = next;
			}
			Link(q, next);
			q = next;
			next = q->next;
		}
	}
	//原堆失效
	//防止原堆析构时破坏新的堆
	h1 = nullptr;
	h2 = nullptr;
	return root;
}
template<class T>
void HeapTwo<T>::Union(HeapTwo<T>& h)
{
	head = Union_F((*this).head, h.head);
}
//产生一个新的堆,合并到原来的堆
template<class T>
void HeapTwo<T>::Insert(T key)
{
	Node<T>* q = new Node<T>(key);
	HeapTwo<T> Q(q);
	Union(Q);
}

template<class T>
Node<T>* HeapTwo<T>::Search_(Node<T>* q, T key)
{
	Node<T>* p = q;
	Node<T>* ans;
	while (p != nullptr)
	{
		if (p->data > key)
		{
			p = p->next;
			continue;
		}
		if (p->data == key)
			return p;
		else
		{
			if (ans = Search_(p->left, key))//递归
				return ans;
		}
		p = p->next;
	}
	return nullptr;
}
template<class T>
Node<T>* HeapTwo<T>::Search(T key)
{
	return Search_(head, key);
}
template<class T>
Node<T>* HeapTwo<T>::reverse(Node<T>* root)
{
	Node<T>* pre = nullptr;//q的前一个,便于反转next值
	Node<T>* q=root;
	Node<T>* next;
	if (!q)
		return root;
	while (q->next)
	{
		next = q->next;
		q->next = pre;
		q->parent = nullptr;
		pre = q;
		q = next;  
	}
	q->parent = nullptr;
	q->next = pre;
	return q;
}
//从要删除的结点开始一路替换至一个根结点,代替的删除根结点
template<class T>
void HeapTwo<T>::Delete(T key)
{
	Node<T>* x = Search(head, key);
	if (x == nullptr)
		return;
	Node<T>* p = x->parent;
	while (p)
	{
		T t = x->data;
		x->data = p->data;
		p->data = t;
		x = p;
		p = p->parent;
	}
	//找x前一个子树的根
	Node<T>* pre = nullptr;
	Node<T>* n = head;
	while (n != x)
	{
		pre = n;
		n = n->next;
	}
	if (pre)
		pre->next = x->next;
	else
		head = x->next;
	//删除x,x子树变成一个堆,合并到原堆上
	HeapTwo<T> Q(reverse(x->left));
	Union(Q);
	delete x;
}

template<class T>
void HeapTwo<T>::top(Node<T>*& x, Node<T>*& pre)
{
	if (head == nullptr)
		throw "No Heap is empty! Can't pop! -1\n";
	pre = nullptr;
	x = head;
	Node<T>* q = head->next;
	Node<T>* qpre = head;
	while (q)
	{
		if (q->data < x->data)
		{
			x = q;
			pre = qpre;
		}
		qpre = q;
		q = q->next;
	}
}
template<class T>
T HeapTwo<T>::min()
{
	Node<T>* min, *pre;
	try
	{
		top(min, pre);
	}
	catch (const char* a)
	{
		cerr << a;
		return -1;
	}
	return min->data;
}
template<class T>
T HeapTwo<T>::pop()
{
	Node<T>* min, *pre;
	try
	{
		top(min, pre);
	}
	catch (const char* a)
	{
		cerr << a;
		return -1;
	}
	if (pre == nullptr)
		head = head->next;
	else
		pre->next = min->next;
	Node<T>* child = reverse(min->left);
	HeapTwo Q(child);
	Union(Q);
	T ans = min->data;
	delete min;
	return ans;
}

template<class T>
void HeapTwo<T>::Decrease(Node<T>* q, T key)
{
	if (key > q->data)
	{
		cerr << "Can't decrease to a less key!\n";
		return;
	}
	q->data = key;
	Node<T>* pre = q->parent;
	while (pre&&q->data < pre->data)
	{
		T t = q->data;
		q->data = pre->data;
		pre->data = t;
		q = pre;
		pre = q->parent;
	}
}
template<class T>
void HeapTwo<T>::Crease(Node<T>* q, T key)
{
	if (q->data > key)
	{
		cerr<< "Can't crease to a greater key!\n";
	}
	q->data = key;
	Node<T>* child = q->left;
	Node<T>* min;
	while (child)
	{
		if (q->data > child->data)
		{
			min = child;
			child = child->next;
			while (child)
			{
				if (min->data > child->data)
					min = child;
				child = child->next;
			}
			T t = q->data;
			q->data = min->data;
			min->data = t;
			q = min;
			child = q->left;
		}
		else
		{
			child = child->next;
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40510553/article/details/80322800