用PairingHeap改进Dijkstra算法

先提供几个链接

  1. PairingHeap算法讲得不错
  2. PairingHeap的C语言实现
  3. BinaryHeap, FibHeap, PairHeap对改进Dijkstra的性能比较

Dijkstra的计算过程就是在维护一张表,形如:

v known d p
v1 T 0 0
v2 F 2 v1
v3 F 3 v4
v4 T 1 v1
v5 F 3 v4
v6 F 9 v4
v7 F 5 v4

每一次循环要从d中找出最小者,于是PairHeap、FibHeap、BinaryHeap等等就派上用场了。本文我们采用PariHeap,至于为什么请看链接3。当需要更改(减小)d的值时,需要从PairHeap上找到相应的节点再执行DecreaseKey操作,于是我在链接2的基础之上为PairHeap增加了Find操作。

base.h

#ifndef _BASE_H
#define _BASE_H

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define VERTEXNUM 7
#define FALSE (0)
#define TRUE (1)
#define MAXSIBLINGS ((VERTEXNUM)+1)

typedef int BOOL;
typedef double ValueType;

typedef struct {
	int vindex;
	ValueType dist;
} Item;

#endif

list.h

#ifndef _LIST_H
#define _LIST_H

#include"base.h"

/*单向链表节点*/
typedef struct ltnode {
	Item item;
	struct ltnode *next;
} LTNode;
/*单向链表定义*/
typedef struct linkedList {
	LTNode *head;
	int size;
} *LinkedList;

/*创建并初始化单向链表*/
BOOL Initialize_L(LinkedList * const llh);

/*确定一个单向链表是否为空*/
BOOL IsEmpty_L(const LinkedList * const llh);

/*向单向链表末尾添加一个元素*/
BOOL Insert_L(const LinkedList * const lln, const Item item);

/*释放单向链表占用的空间*/
void Release_L(LinkedList * const llh);

#endif

list.c

#include"list.h"

static LTNode *makeNode(const Item item)
{
	LTNode *newNode;
	newNode = (LTNode *) malloc(sizeof(struct ltnode));
	newNode->item = item;
	newNode->next = NULL;
	return newNode;
}

static void releaseNode(LTNode * const p)
{
	if (p != NULL) {
		releaseNode(p->next);
		free(p);
	}
}

/*创建并初始化单向链表*/
BOOL Initialize_L(LinkedList * const llh)
{
	(*llh) = (struct linkedList *) malloc(sizeof(struct linkedList));
	(*llh)->head = NULL;
	(*llh)->size = 0;
	return TRUE;
}

/*确定一个单向链表是否为空*/
BOOL IsEmpty_L(const LinkedList * const llh)
{
	if ((*llh)->size == 0)
		return TRUE;
	else
		return FALSE;
}

/*向单向链表头部添加一个元素*/
BOOL Insert_L(const LinkedList * const llh, const Item item)
{
	LTNode *newNode = makeNode(item);
	if ((*llh)->size == 0)
		(*llh)->head = newNode;
	else {
		newNode->next = (*llh)->head;
		(*llh)->head = newNode;
	}
	(*llh)->size++;
	return TRUE;
}

/*释放单向链表占用的空间*/
void Release_L(LinkedList * const llh)
{
	releaseNode((*llh)->head);
	free(*llh);
}

pairheap.h

#ifndef _PAIRHEAP_H
#define _PAIRHEAP_H

#include"base.h"

typedef struct phnode {
	Item item;
	struct phnode *left, *previous, *nextSibling;
} PHNode;

typedef struct pairingHeap {
	PHNode *root;
	int current;
} *PairingHeap;

/*创建并初始化配对堆*/
BOOL Initialize_P(PairingHeap * const pph);

/*确定一个配对堆是否为空*/
BOOL IsEmpty_P(const PairingHeap * const pph);

/*向配对堆中插入一个数据为指定数据的结点.localizer用来传递回新节点的地址*/
BOOL Insert_P(const PairingHeap * const pph, const Item item);

/*在配对堆上查找数据点*/
PHNode* Find_P(const PairingHeap * const pph, const Item item);

/*将配对堆中指定节点的数据降低delta*/
BOOL DecreaseKey_P(const PairingHeap * const pph, PHNode * const position,
		   const ValueType delta);

/*删除配对堆中数据域最小的节点,并通过pmin将其携带回调用该函数的函数*/
BOOL DeleteMin_P(const PairingHeap * const pph, Item * const pmin);

/*打印堆*/
void Print_P(const PairingHeap * const pph);

/*释放配对堆占用的空间*/
void Release_P(PairingHeap * const pph);

#endif

pairheap.c

#include"pairheap.h"

/*全局变量声明*/
static PHNode *NullNode = NULL;

/*局部函数声明*/
static PHNode *compareAndLink_P(PHNode * const first, PHNode * const second);
static PHNode *makeNode_P(const Item item);
static PHNode *combineSiblings_P(PHNode * firstSibling);
static void release_P(PHNode * const pn);
static PHNode *find(PHNode * const root, const Item item);
static void printNode(const PHNode * const root);

/*局部函数定义*/
static PHNode *compareAndLink_P(PHNode * const first, PHNode * const second)
{
	if (second == NullNode)
		return first;
	if (second->item.dist < first->item.dist) {	/*把first作为second的最左子孩子 */
		second->previous = first->previous;
		first->previous = second;
		first->nextSibling = second->left;
		first->nextSibling->previous = first;
		second->left = first;
		return second;
	} else {		/*把second作为first的最左孩子 */
		second->previous = first;
		first->nextSibling = second->nextSibling;
		first->nextSibling->previous = first;
		second->nextSibling = first->left;
		second->nextSibling->previous = second;
		first->left = second;
		return first;
	}
}

static PHNode *makeNode_P(const Item item)
{
	PHNode *newNode;
	newNode = (PHNode *) malloc(sizeof(PHNode));
	if (NULL == newNode)
		return NULL;
	newNode->item = item;
	newNode->left = newNode->nextSibling = newNode->previous = NullNode;
	return newNode;
}

static PHNode *combineSiblings_P(PHNode * firstSibling)
{
	static PHNode *treeArray[MAXSIBLINGS];	/*treeArray是个一维数组,每个元素是Node*类型。静态成员在编译时就要初始化,所以数组长度必须是已知的。给treeArray分配一个足够大的长度,再定义为静态的(全局生命周期),每次调用函数时都使用这一个treeArray,省去过多的重复初始化 */
	int i, j, numSiblings;
	/*如果只有一个孩子,则直接返回它 */
	if (firstSibling->nextSibling == NullNode)
		return firstSibling;
	/*把所有兄弟放在treeArray中 */
	for (numSiblings = 0; firstSibling != NullNode; numSiblings++) {
		treeArray[numSiblings] = firstSibling;
		/*打断双向链表中每个节点向后的指针 */
		firstSibling->previous->nextSibling = NullNode;
		firstSibling = firstSibling->nextSibling;
	}
	treeArray[numSiblings] = NullNode;	//一定要把最后一个设为NullNode,因为treeArray的总长度为MAXSIBLINGS,NullNode之前的才是有效元素
	/*从左向右两两合并子树 */
	//printf("第一趟合并: ");
	for (i = 0; i + 1 < numSiblings; i += 2){
		treeArray[i] = compareAndLink_P(treeArray[i], treeArray[i + 1]);
		//printf("一次");
		//printNode(treeArray[i]);
	}
	j = i - 2;
	if (j == numSiblings - 3){	/*兄弟有奇数个 */
		treeArray[j] = compareAndLink_P(treeArray[j], treeArray[j + 2]);
		//printf("合并最一个奇数项");
		//printNode(treeArray[j]);
	}
	/*进行第二趟合并 */
	/*从右向左逐个合并 */
	//printf("第二趟合并: ");
	while (j >= 2) {
		treeArray[j - 2] =
		    compareAndLink_P(treeArray[j - 2], treeArray[j]);
		//printf("一次");
		//printNode(treeArray[j-2]);
		j -= 2;
	}
	return treeArray[0];
}

static void release_P(PHNode * const pn)
{
	if (pn != NullNode) {
		release_P(pn->left);
		release_P(pn->nextSibling);
		free(pn);
	}
}

static PHNode *find(PHNode * const root, const Item item)
{
	//printf("开始查找vindex=%d\tdist=%d\n",root->item.vindex,(int)root->item.dist);
	if(root==NullNode)
		return NullNode;
	else if(root->item.vindex==item.vindex)
		return root;
	else if(item.dist<root->item.dist)
		return find(root->nextSibling,item);
	else{
		PHNode *rect;
		return ((rect=find(root->nextSibling,item))==NullNode)?find(root->left,item):rect;/*先搜兄弟节点;如果找不到,再搜孩子节点;如果还找不到则返回NullNode*/
	}
}

static void printNode(const PHNode * const root)
{
	if(root==NullNode){
		printf("\t");
		return;
	}
	else{
		printf("%d(%d)\t",root->item.vindex,(int)root->item.dist);
		printf("%d's next:",root->item.vindex);printNode(root->nextSibling);
		printf("%d's left:",root->item.vindex);printNode(root->left);
	}
}

/*************************************接口函数定义********************************/
BOOL Initialize_P(PairingHeap * const pph)
{
	if (NullNode == NULL) {
		NullNode = (PHNode *) malloc(sizeof(PHNode));
		if (NullNode == NULL) {
			puts("Out of space.");
			return FALSE;
		}
		*pph = (struct pairingHeap *)malloc(sizeof(struct pairingHeap));
		if (*pph == NULL) {
			puts("Out of space");
			free(NullNode);
			NullNode == NULL;
			return FALSE;
		}
		NullNode->left = NullNode->previous = NullNode->nextSibling = NullNode;
		(*pph)->root = NullNode;
		(*pph)->current = 0;
	}
	return TRUE;
}

BOOL IsEmpty_P(const PairingHeap * const pph)
{
	switch ((*pph)->current) {
	case 0:
		return TRUE;
	default:
		return FALSE;
	}
}

BOOL Insert_P(const PairingHeap * const pph, const Item item)
{
	PHNode *newNode;
	newNode = makeNode_P(item);
	if (newNode == NULL) {
		puts("out of space.");
		return FALSE;
	}
	//*localizer = newNode;
	if (IsEmpty_P(pph) == TRUE)
		(*pph)->root = newNode;
	else
		(*pph)->root = compareAndLink_P((*pph)->root, newNode);
	(*pph)->current++;
	return TRUE;
}

PHNode *Find_P(const PairingHeap * const pph, const Item item)
{
	//printf("调用Find_P\n");
	PHNode * rect=find((*pph)->root,item);
	if(rect==NullNode)
		return NULL;
	else{
		return rect;
	}
}

BOOL DecreaseKey_P(const PairingHeap * const pph, PHNode * const position,
		   const ValueType delta)
{
	if (delta <= 0)
		return FALSE;
	//printf("要把%d降低%d\n",position->item.vindex,(int)delta);
	position->item.dist -= delta;
	//printf("降低节点值以后:vindex=%d\tdist=%d\n",position->item.vindex,(int)position->item.dist);
	if (position == (*pph)->root)
		return TRUE;	/*如果减小的是根节点的值,可以直接返回 */
	/*把position从堆上(双向链表中)取下来 */
	position->nextSibling->previous = position->previous;
	if (position->previous->left == position)	/*position是最左孩子 */
		position->previous->left = position->nextSibling;
	else
		position->previous->nextSibling = position->nextSibling;
	position->nextSibling = NullNode;
	/*再把position合并到堆的根节点上去*/
	(*pph) -> root = compareAndLink_P ((*pph) -> root, position) ;
	return TRUE;
}

BOOL DeleteMin_P(const PairingHeap * pph, Item * const pmin)
{
	PHNode *newRoot;
	if (IsEmpty_P(pph))
		return FALSE;
	else {
		newRoot = NullNode;
		*pmin = (*pph)->root->item;
		if ((*pph)->root->left != NullNode)
			newRoot = combineSiblings_P((*pph)->root->left);
		free((*pph)->root);
		(*pph)->root = newRoot;
		(*pph)->current--;
		return TRUE;
	}
}

void Print_P(const PairingHeap * const pph)
{
	if((*pph)->root==NullNode)
		return;
	else
		printNode((*pph)->root);
	printf("\n");
}

void Release_P(PairingHeap * const pph)
{
	release_P((*pph)->root);
	free(*pph);
	free(NullNode);
	NullNode = NULL;
}

dijkstra.c

#include"list.h"
#include"pairheap.h"
#include<time.h>
#include<limits.h>

typedef struct  {
	int vindex;
	BOOL known;
	ValueType dist;
	int preindex;
}TableLine;

typedef struct {
	int vindex;
	LinkedList neighbours;
} Adjancent;

char *vertexName[] = { "V1", "V2", "V3", "V4", "V5", "V6", "V7" };

void InitResultTable(TableLine resultTable[],int len){
	int i;
	for(i=0;i<len;i++){
		resultTable[i].vindex=i;
		resultTable[i].known=FALSE;
		resultTable[i].dist=INT_MAX;
		resultTable[i].preindex=-1;
	}
}

/*根据最终的TableLine打印到各节点的最短路径*/
void printShortWay(TableLine resultTable[],int len){
	int i;
	for(i=0;i<len;i++){
		printf("%s: ",vertexName[resultTable[i].vindex]);
		double way=resultTable[i].dist;
		int curline=i;
		do{
			int p=resultTable[curline].preindex;
			if(p!=-1)
				printf("%s\t",vertexName[p]);
			//else
				//printf("END\t");
		}while((curline=resultTable[curline].preindex)!=-1);
		printf("总路程:%d\n",(int)way);
	}
}

/*初始化带权有向图*/
void InitGraph(Adjancent **graph)
{
	LinkedList *list0;list0=(LinkedList *)malloc(sizeof(LinkedList));Initialize_L(list0);
	Item item1;item1.vindex=1;item1.dist=2;Insert_L(list0, item1);
	Item item2;item2.vindex=3;item2.dist=1;Insert_L(list0, item2);
	Adjancent *adj0;adj0=(Adjancent *)malloc(sizeof(Adjancent));adj0->vindex = 0;adj0->neighbours = *list0;graph[0]=adj0;
	
	LinkedList *list1;list1=(LinkedList *)malloc(sizeof(LinkedList));Initialize_L(list1);
	Item item3;item3.vindex=3;item3.dist=3;Insert_L(list1, item3);
	Item item4;item4.vindex=4;item4.dist=10;Insert_L(list1, item4);
	Adjancent *adj1;adj1=(Adjancent *)malloc(sizeof(Adjancent));adj1->vindex = 1;adj1->neighbours = *list1;graph[1]=adj1;
	
	LinkedList *list2;list2=(LinkedList *)malloc(sizeof(LinkedList));Initialize_L(list2);
	Item item5;item5.vindex=0;item5.dist=4;Insert_L(list2, item5);
	Item item6;item6.vindex=5;item6.dist=5;Insert_L(list2, item6);
	Adjancent *adj2;adj2=(Adjancent *)malloc(sizeof(Adjancent));adj2->vindex = 2;adj2->neighbours = *list2;graph[2]=adj2;
	
	LinkedList *list3;list3=(LinkedList *)malloc(sizeof(LinkedList));Initialize_L(list3);
	Item item7;item7.vindex=2;item7.dist=2;Insert_L(list3, item7);
	Item item8;item8.vindex=4;item8.dist=2;Insert_L(list3, item8);
	Item item9;item9.vindex=5;item9.dist=8;Insert_L(list3, item9);
	Item item10;item10.vindex=6;item10.dist=4;Insert_L(list3, item10);
	Adjancent *adj3;adj3=(Adjancent *)malloc(sizeof(Adjancent));adj3->vindex = 3;adj3->neighbours = *list3;graph[3]=adj3;
	
	LinkedList *list4;list4=(LinkedList *)malloc(sizeof(LinkedList));Initialize_L(list4);
	Item item11;item11.vindex=6;item11.dist=6;Insert_L(list4, item11);
	Adjancent *adj4;adj4=(Adjancent *)malloc(sizeof(Adjancent));adj4->vindex = 4;adj4->neighbours = *list4;graph[4]=adj4;
	
	LinkedList *list5;list5=(LinkedList *)malloc(sizeof(LinkedList));Initialize_L(list5);
	Adjancent *adj5;adj5=(Adjancent *)malloc(sizeof(Adjancent));adj5->vindex = 5;adj5->neighbours = *list5;graph[5]=adj5;
	
	LinkedList *list6;list6=(LinkedList *)malloc(sizeof(LinkedList));Initialize_L(list6);
	Item item12;item12.vindex=5;item12.dist=1;Insert_L(list6, item12);
	Adjancent *adj6;adj6=(Adjancent *)malloc(sizeof(Adjancent));adj6->vindex = 6;adj6->neighbours = *list6;graph[6]=adj6;
}

/*以领接表的形式打开带权有向图*/
void printGraph(Adjancent **graph){
	int i, j;
	LTNode *neighbour;
	for (i = 0; i < VERTEXNUM; i++) {
		printf("%s\t", vertexName[graph[i]->vindex]);
		neighbour = graph[i]->neighbours->head;
		int len = graph[i]->neighbours->size;
		while (len-- > 0) {
			printf("%s(%d)\t", vertexName[neighbour->item.vindex],
			       (int)(neighbour->item.dist));
			neighbour = neighbour->next;
		}
		printf("\n");
	}
}

int main()
{
	Adjancent **graph;
	graph = (Adjancent **) malloc(sizeof(Adjancent *) * VERTEXNUM);
	InitGraph(graph);
	printGraph(graph);
	
	TableLine resultTable[VERTEXNUM];
	InitResultTable(resultTable,VERTEXNUM);
	
	PairingHeap * pph;
	pph=(PairingHeap *)malloc(sizeof(PairingHeap));
	Initialize_P(pph);
	
	int startindex=0;		/*指定起点*/
	resultTable[startindex].dist=0;
	
	int i;
	for(i=0;i<VERTEXNUM;++i){
		Item item;
		item.vindex=i;
		if(i!=startindex)
			item.dist=INT_MAX;
		else
			item.dist=0;
		Insert_P(pph,item);
	}
	//printf("初始化堆后: ");
	//Print_P(pph);
	
	while(1){
		Item *pmin;
		pmin=(Item*)malloc(sizeof(Item));
		if(DeleteMin_P(pph,pmin)==FALSE){		/*从配对堆上取下最小元素*/
			break;
		}
		//printf("取下最小元素后: ");
		//Print_P(pph);
		int index=pmin->vindex;
		resultTable[index].known=TRUE;
		double cvw=resultTable[index].dist;
		LTNode *neighbour= graph[index]->neighbours->head;
		int len = graph[index]->neighbours->size;
		while (len-- > 0) {
			int ind=neighbour->item.vindex;
			if(resultTable[ind].known==FALSE){
				double d=neighbour->item.dist;
				if(d+cvw<resultTable[ind].dist){
					Item fi;
					fi.vindex=ind;
					fi.dist=resultTable[ind].dist;
					PHNode *change=Find_P(pph,fi);
					if(change==NULL){
						fprintf(stderr,"在配对堆上找不到要找的项.vindex=%d\tdist=%d\n",fi.vindex,(int)fi.dist);
						free(change);
						exit(1);
					}
					//printf("change:vindex=%d\tdist=%d\n",change->item.vindex,(int)change->item.dist);
					DecreaseKey_P(pph,change,resultTable[ind].dist-d-cvw);
					//printf("降低元素值后: ");
					//Print_P(pph);
					resultTable[ind].dist=d+cvw;
					resultTable[ind].preindex=index;
				}
			}
			neighbour = neighbour->next;
		}
	}
	
	printShortWay(resultTable,VERTEXNUM);
	Release_P(pph);
	for(i=0;i<VERTEXNUM;++i){
		Release_L(&(graph[i]->neighbours));
	}
	return 0;
}

posted @ 2012-02-24 16:03  高性能golang  阅读(2250)  评论(0编辑  收藏  举报