关闭

[算法导论读书笔记]二项堆

标签: 读书算法nullinsertstructmerge
1400人阅读 评论(0) 收藏 举报
分类:

二项树的定义:

二项树Bk是一种递归定义的有序树,如下图所示。二项树B0只包含一个节点。二项树Bk由两棵二项树Bk-1连接而成。其中一棵树的根是另一棵树的根的最左孩子。下图所示的是二项堆,二项堆链接了三个二项树(B0 B2 B4 )。



二项树的性质:

1.共有2k个节点。

2.树的高度为k

4.根的度数为k,它大于任何其他节点的度数;并且,如果根的子女从左到右编号为k-1k-1……0,子女i是子树Bi的根。

推论:在一颗包含n个节点的二项树中,任意节点的最大度数为lgn


二项堆的定义:

1.H中的每个二项树遵循最小堆性质:节点的关键字大于或等于其父节点的关键字。我们说这种树是最小堆有序的。

2.对任意非负整数k,在H中至多有一棵二项树的根具有度数k

    由上图可知,二项堆中每个节点都有至少3个指针域(指向父亲,孩子,兄弟),一个degree,标识有几个孩子,一个key,用于存储数据,还可以包含其他卫星数据。


创建一个新的二项堆:

    为了构造一个空的二项堆,过程MAKE_BINOMIAL_HEAP分配并返回一个对象H,且head[H]=NIL。该过程的运行时间复杂度为O(1)。

寻找最小关键字:

    过程BINOMIAL_HEAP_MINIMUM(H)返回一个指针,它指向包含n个节点的二项堆H中具有最小关键子的节点。因为一个二项堆是几个最小堆链接起来的,所以,最小关键字必在根节点中。伪代码如下:


    因为至多要检查|_lgn_| + 1 个根,故BINOMIAL_HEAP_MINIMUM的运行时间为O(lgn)。


合并两个二项堆:

    合并两个二项堆的操作可用作后面大部分操作的一个子程序。过程BINOMIAL_HEAP_UNION反复链接根节点的度数相同的各二项树。在下面的过程中,将以节点y为根的Bk-1树与节点z为根的Bk-1树连接起来;亦即,它使得z是y的父节点,并成为一颗Bk树的根。



    下面的过程合并二项堆H1和H2,并返回结果堆。在合并过程中,它同时破坏了H1,H2的表示。除了BINOMIAL——LINK之外,这个过程还使用了一个辅助过程BINOMIAL_HEAP_MERGE,来将H1和H2的根表合并成一个按度数的单调递增次序排列的链表。伪代码如下:


合并过程中会遇到4中情况:

case1,正是我们所期望的那样,继续往后遍历。

case2,连续三个度数相同的二项树,转换成case3、4

case3,合并两个Bk-1Bk 其中key[x]<= key[next_x]

case4,如case3,不过有key[next_x] > key[x],且需要注意prev_x=NIL的情况。

下面是合并H1和H2的一个图形化示例:




插入一个节点:


    这个过程先在O(1)的时间内,构造一个包含一个节点的二项堆H‘,再在O(lgn)时间内,将其与包含n个节点的二项堆H合并。对BINOMIAL_HEAP_UNION的调用还负责释放临时二项堆H‘。


抽取具有最小关键字的节点:


    这个过程的工作如下图所示。因为如果H有n个节点,则第1——4行每次需要时间O(lgn)。所以,BINOMIAL_HEAP_EXTRACT_MIN的运行时间为O(lgn)。

减小关键字的值:

    首相将关键字的值减少为新的值,然后调整二项树(向上调),使其满足而项树的要求。


删除一个关键字:

    很容易在O(lgn)时间内从二项堆H中删除一个节点x。先将要删除的关键字的值改为最小的关键字。然后提取最小关键字节点。这样就很轻松的删除了一个节点。易知,过程BINOMIAL_HEAP_DELETE的时间为O(lgn).


代码示例:

#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
const int neg_inf = -1000000;//negative infinity
const int pos_inf = 1000000;//postive infinity

struct _node
{
	int key; //键
	int degree;//度数,也就是孩子的个数
	struct _node *p;//指向父亲的指针
	struct _node *child;//指向孩子的指针
	struct _node *sibling;//指向兄弟的指针
};
	
typedef struct _node node;
typedef struct _node * pnode;

// find the least element's value
pnode BINOMIAL_HEAP_MININUM( pnode H )
{
	pnode y = NULL;
	pnode x = H;
	int min = pos_inf;
	while( x != NULL )
	{
		if( x->key < min )
		{
			min = x->key;
			y = x;
		}
		x = x->sibling;
	}
	return y;
}

// new a node
pnode MAKE_BINOMIAL_HEAP()
{
	pnode temp = (pnode)malloc(sizeof(node));
	temp->key = 0;
	temp->degree = 0;
	temp->p = NULL;
	temp->child = NULL;
	temp->sibling = NULL;
	return temp;
}

// link y to z as left child
bool BINOMIAL_LINK( pnode y, pnode z)
{
	y->p = z;
	y->sibling = z->child;
	z->child = y;
	z->degree++;
	return true;
}

//union two linked list
pnode BINOMIAL_HEAP_MERGE( pnode H1, pnode H2)
{
	//assert( H1 && H2 );
	if( H1 == NULL )
	{
		return H2;
	}
	if( H2 == NULL )
	{
		return H1;
	}
	pnode H = NULL;
	pnode r = NULL;
	pnode p = H1, q = H2;

	if( p->degree < q->degree)
	{
		H = p;
		p = p->sibling;
	}
	else
	{
		H = q;
		q = q->sibling;
	}

	r = H;

	while( p != NULL && q != NULL )
	{
		if( p->degree <= q->degree)
		{
			r->sibling = p;
			r = p;
			p = p->sibling;
		}	
		else
		{
			r->sibling = q;
			r = q;
			q = q->sibling;
		}				
	}

	while( p != NULL )
	{
		r->sibling = p;
		r = p;
		p = p->sibling;
	}

	while( q != NULL )
	{
		r->sibling = q;
		r = q;
		q = q->sibling;
	}
	return H;
}


//Union two binary heap
pnode BINOMIAL_HEAP_UNION(pnode H1, pnode H2)
{
	pnode H;
	H = BINOMIAL_HEAP_MERGE( H1, H2);
	if( H == NULL )
	{
		return NULL;
	}

	pnode prev_x = NULL;
	pnode x = H;
	pnode next_x = x->sibling;

	while( next_x != NULL )
	{
		if(( x->degree != next_x->degree ) || (next_x->sibling != NULL && next_x->sibling->degree == x->degree ) )//case1, 2
		{
			prev_x = x;
			x = next_x;
		}
		else if( x->key <= next_x->key)//case3
		{
			x->sibling = next_x->sibling;
			BINOMIAL_LINK(next_x, x);
		}
		else//case4
		{
			if( prev_x == NULL )
			{
				H = next_x;
			}
			else
			{
				prev_x->sibling = next_x;
			}
			BINOMIAL_LINK(x, next_x);
			x = next_x;	
		}
		next_x = x->sibling;	
	}
	return H;
}


//insert a element to head
pnode BINOMIAL_HEAP_INSERT( pnode H, int x)
{
	pnode HH = MAKE_BINOMIAL_HEAP();
	HH->degree = 0;
	HH->key = x;
	HH->sibling = NULL;
	HH->p = NULL;
	HH->child = NULL;
	
	return BINOMIAL_HEAP_UNION( H, HH);
}

//reverse a linked list
pnode reverse( pnode H )
{
	if( H == NULL )
	{
		return NULL;
	}
	
	pnode p = H;
	pnode q = H->sibling;
	pnode r;
	p->sibling = NULL;
	while( q != NULL )
	{
		r = q->sibling;
		q->sibling = p;
		p = q;
		q = r;
	}
	return p;	
}


//extract the least element , and use the second argument to storage the element.
pnode BINOMIAL_HEAP_EXTRACT_MIN( pnode H, struct _node **p)
{
	if( H == NULL )
	{
		return NULL;
	}
	pnode y = NULL;
	pnode prev_y = NULL;
	pnode possible_prev_y = NULL;
	pnode x = H;

	pnode H1 = NULL;
	int min = pos_inf;
	while( x != NULL )
	{
		if( x->key < min )
		{
			min = x->key;
			prev_y = possible_prev_y;
			y = x;
		}
		possible_prev_y = x;
		x = x->sibling;
	}

	if( prev_y == NULL )
	{
		H = y->sibling;
	}
	else
	{
		prev_y->sibling = y->sibling;
	}

	H1 = y->child;

	H1 = reverse( H1 ); 
	*p = y;
	return  BINOMIAL_HEAP_UNION(H, H1);	
}

//change the goal element to negative infinity, then, extract the least element.
pnode BINOMIAL_HEAP_DELETE(pnode H, pnode x)
{
	H = BINMIAL_HEAP_DECREASE_KEY( H, x, neg_inf);
	H = BINOMIAL_HEAP_EXTRACT_MIN(H, &x);
	free(x);
	x = NULL;
	return H;
}

//decreast x'value to key
pnode BINOMIAL_HEAP_DECREASE_KEY(pnode H, pnode x, int k)
{
	if( k > x->key )
	{
		cout << "new key is greater than current key" << endl;
		return H;
	}
	
	x->key = k;
	pnode y = x;
	pnode z = y->p;	
	while( z != NULL && y->key < z->key )
	{
		//swap y and z
		int temp = y->key;
		y->key = z->key;
		z->key = y->key;

		y = z;
		z = y->p;
	}	
	
	return H;	
}
int main(int argc, char* argv[])
{
	pnode head = NULL;
	pnode x;
	head = BINOMIAL_HEAP_INSERT(head, 9);
	head = BINOMIAL_HEAP_INSERT(head, 4);
	head = BINOMIAL_HEAP_INSERT(head, 5);
	head = BINOMIAL_HEAP_INSERT(head, 6);
	head = BINOMIAL_HEAP_INSERT(head, 7);
	head = BINOMIAL_HEAP_INSERT(head, 8);
	head = BINOMIAL_HEAP_INSERT(head, 3);
	cout << BINOMIAL_HEAP_MININUM( head )->key << endl;

	head = BINOMIAL_HEAP_EXTRACT_MIN(head, &x);
	cout << x->key << endl;
	free(x);
	x = NULL;

	head = BINOMIAL_HEAP_EXTRACT_MIN(head, &x);
	cout << x->key << endl;
	free(x);
	x = NULL;

	head = BINOMIAL_HEAP_EXTRACT_MIN(head, &x);
	cout << x->key << endl;
	free(x);
	x = NULL;

	cout << BINOMIAL_HEAP_MININUM( head )->key << endl;
	return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:708941次
    • 积分:7756
    • 等级:
    • 排名:第2683名
    • 原创:135篇
    • 转载:35篇
    • 译文:7篇
    • 评论:119条
    声明
    本博客乃学习笔记,没有纯粹无意义的转载。作者除了对自己负责,不对任何读者负责。欢迎指出文章错误,如果原意交朋友,可以通过Gmail联系我(mingxinglai#gmail.com),博客基本不再更新,欢迎访问我的独立博客http://mingxinglai.com
    文章分类
    最新评论