用PairingHeap改进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;
}

本文来自博客园,作者:张朝阳讲go语言,转载请注明原文链接:https://www.cnblogs.com/zhangchaoyang/articles/2366869.html

浙公网安备 33010602011771号