1. 程式人生 > >找出無向圖中所有的環的演算法

找出無向圖中所有的環的演算法

本文給出了一個找到無向圖中所有的環的遞迴演算法,該演算法是基於DFS(深度優先搜尋)的,大概的思路是:在深度優先搜尋無向圖的過程中,當遇到起始點的時候,會認定為出現環(在本文中只是找出了無向圖中所有的長度大於等於3的環(長度為1和2的環沒有意思),所以在深搜的過程中,當遇到的是起始點的時候,還需要進行判斷是否是環),當確定是出現了環之後,根據是否在遇到環之前的那個點還有其他的路徑,來決定是進一步的進行深度優先搜尋還是進行回退,在進行深度優先搜尋的過程中,將訪問過的節點標記,若當前的節點無路可走(不能進行深度優先搜尋了),在回退的過程中,將標記取消。演算法的過程就下圖做簡單的介紹:


假設以1為起點進行深度優先搜尋,經過訪問2,3,4,5,6會得到一個環,因為節點6還有下一條路徑可走,此時程式會進入7,8,9,10這些點進行深度優先搜尋,但是都再沒有回到節點1,於是程式會一層一層的在從7,8,9,10(不一定是這樣的順序)這些點退出來。退至節點6,5,4直到3節點(將6,5,4的標記全部取消)找到了下一條路徑5,在走到6,此時又發現了另一條環1->2->3->5->6->1.以此類推。

主要程式碼如下:

<span style="font-family:Courier New;font-size:12px;">void DFS(int startVertax)
{
	setVisitedFlag(startVertax, 1);
	int nextVertax;
	push_stack(&loop_stack, startVertax);
	nextVertax = firstAdjacentVertax(startVertax);
	innerStep++;
	for( ; ; )
	{
		if( nextVertax != -1 )
		{
			if( visitedFlag[nextVertax] == 1 && nextVertax == heap && innerStep == 2 ) //從1到2,又從2到1,這不算是一個環
			{
				nextVertax = nextAdjacentVertax(startVertax, nextVertax);
				continue;
			}
			else if( visitedFlag[nextVertax] == 1 && nextVertax == heap && innerStep != 2 ) //找到了一個環
			{
				printf("loop length: %d\t", innerStep);
				print_stack(loop_stack);
				nextVertax = nextAdjacentVertax(startVertax, nextVertax);
				continue;
			}
			else if( visitedFlag[nextVertax] == 0 )<span style="white-space:pre">	</span>//進行遞迴
			{
				DFS(nextVertax);
			}
			if( isRecall == 1 ) //進行回退
			{
				innerStep--;
				temp = nextVertax;
				nextVertax = nextAdjacentVertax(startVertax, nextVertax);
				pop_stack(&loop_stack, &pop_value);
				setVisitedFlag(temp, 0);
				isRecall = 0;
				continue;
			}
			nextVertax = nextAdjacentVertax(startVertax, nextVertax);
		}
		else if( nextVertax == -1 )
		{
			isRecall = 1;
			break;
		}
	}
}
void DFSTraverse()
{
	initialVisitedFlagArray();
	initializeSequenceStack(&loop_stack);
	int i;
	for( heap = 1; heap <= vertax_size; heap++ )
	{
		for( i = 1; i <= vertax_size; i++ )
		{
			visitedFlag[i] = 0;
		}
		/*
		printf("print the visitedFlag array: ");
		for( i = 1; i <= vertax_size; i++ )
		{
			printf("%d ", visitedFlag[i]);
		}
		printf("\n");
		*/
		if( visitedFlag[heap] == 0 )
		{
			printf("\n-------------------the loop start and end with %d----------------\n", heap);
			clear_stack(&loop_stack);
			innerStep = 0;
			isRecall = 0;
			DFS(heap);
		}
	}
}</span>

對於上圖的程式的執行結果為:(需要注意的是:對於無向圖中的每一條環會出現兩次,因為是有方向的:順時針和逆時針)。



完整程式碼

<span style="font-family:Courier New;">#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

int eage_size;
int vertax_size;
char filename_eage[200];
char filename_vertax[200];

int** eage_set;
char** vertax_set;
int** adjacentMatrix;
int* visitedFlag;

typedef struct SequenceStack
{
	int* base;
	int* top;
	int stackSize;
}SequenceStack;

void readEageDataFromFile();
void readVertaxDataFromFile();
void createAdjacentMatrix();
void DFS(int); 
void DFSTraverse();
void initialVisitedFlagArray();
void printVisitedVertax(int); 
void setVisitedFlag(int,int); 
int firstAdjacentVertax(int); 
int nextAdjacentVertax(int,int);

void initializeSequenceStack(SequenceStack*);
void pop_stack(SequenceStack*, int*);
void push_stack(SequenceStack*, int);
void print_stack(SequenceStack);
int empty_stack(SequenceStack);
void clear_stack(SequenceStack*);
void test_stack();

int main(int argc, char* argv[])
{
	if( argc != 5 )
	{
		printf("\tThis algorithm require 3 parameters"
				"\n\t\t1:the size of eage"
				"\n\t\t2:the filename contain eage-data"
				"\n\t\t3:the size of vertax"
				"\n\t\t4:the filename contain vertax-data");
		exit(0);
	}
	eage_size = atoi(argv[1]);
	strcat(filename_eage, argv[2]);
	vertax_size = atoi(argv[3]);
	strcat(filename_vertax, argv[4]);
	printf("eage_size : %d, vertax_size : %d, filename-eage : %s, filename-vertax : %s\n", eage_size, vertax_size, filename_eage, filename_vertax);
	readEageDataFromFile();
	readVertaxDataFromFile();
	createAdjacentMatrix();
	DFSTraverse();
	//test_stack(); 
	return 0; 
}

void readEageDataFromFile()
{
	FILE* f_read;
	if( NULL == (f_read = fopen(filename_eage, "r")))
	{
		printf("open file(%s) error!\n", filename_eage);
		exit(0);
	}
	//create dynamic array for storing original data form file @filename
	eage_set = (int**)malloc(sizeof(int*) * (eage_size + 1));
	if( !eage_set )
	{
		printf("malloc error: eage_set**\n");
		exit(0);
	}
	int i;
	for( i = 1; i <= eage_size; i++ )
	{
		eage_set[i] = (int*)malloc(sizeof(int) * (2 + 1));
		if( !eage_set[i] )
		{
			printf("eage_set[%d] malloc error", i);
			exit(0);
		}
	}
	//read original data from file
	for( i = 1; i <= eage_size; i++ )
	{
		if( 2 != fscanf(f_read, "%d %d", &eage_set[i][1], &eage_set[i][2]))
		{
			printf("fscanf error: %d\n", i);
			exit(0);
		}
	}
	//test
	printf("\n show the origin data from file\n");
	for( i = 1; i <= eage_size; i++ )
	{
		printf("%d\t%d\n", eage_set[i][1], eage_set[i][2]);
	}
	printf("\n");
	//test END
}

void readVertaxDataFromFile()
{
	//create the dynamic array for saving vertax-set information
	vertax_set = (char**)malloc(sizeof(char*) * (vertax_size + 1));
	if( !vertax_set )
	{
		printf("vertax_set malloc error");
		exit(0);
	}
	int i;
	for( i = 1; i <= vertax_size; i++ )
	{
		vertax_set[i] = (char*)malloc(sizeof(char) * (20 + 1));
		if( !vertax_set[i] )
		{
			printf("vertax_set[%d] malloc error");
			exit(0);
		}
	}

	//open file
	FILE* f_read;
	if( NULL == (f_read = fopen(filename_vertax, "r")))
	{
		printf("open file(%s) error", filename_vertax);
		exit(0);
	}

	//read vertax-set information
	for( i = 1; i <= vertax_size; i++ )
	{
		if( 1 != fscanf(f_read, "%s ", vertax_set[i]) )
		{
			printf("fscanf vertax_set[%d] error", i);
			exit(0);
		}
	}

	//test
	for( i = 1; i <= vertax_size; i++ )
	{
		printf("%s\n", vertax_set[i]);
	}
	printf("\n");
	//test END
}

void createAdjacentMatrix()
{
	//create the dynamic array for saving adjcaent matrix
	adjacentMatrix = (int**)malloc(sizeof(int*) * (vertax_size + 1));
	if( !adjacentMatrix )
	{
		printf("adjacentMatrix** malloc error");
		exit(0);
	}
	int i;
	for( i = 1; i <= vertax_size; i++ )
	{
		adjacentMatrix[i] = (int*)malloc(sizeof(int) * (vertax_size + 1));
		if( !adjacentMatrix[i] )
		{
			printf("adjacentMatrix[%d] malloc error");
			exit(0);
		}
	}
	//initial the value of adjacentMatrix
	int j;
	for( i = 1; i <= vertax_size; i++ )
	{
		for( j = 1; j <= vertax_size; j++ )
		{
			adjacentMatrix[i][j] = 0;
		}
	}

	//set the value for adjacentMatrix 
	for( i = 1; i <= eage_size; i++ )
	{
		adjacentMatrix[eage_set[i][1]][eage_set[i][2]] = 1;
		adjacentMatrix[eage_set[i][2]][eage_set[i][1]] = 1;
	}

	//test
	printf("\n show the information about adjacent matrix: \n");
	for( i = 1; i <= vertax_size; i++ )
	{
		for( j = 1; j <= vertax_size; j++ )
		{
			printf("%d ", adjacentMatrix[i][j]);
		}
		printf("\n");
	}
	//test END
}

int loop_count;
int heap;
int innerStep = 0;
int temp;
int isRecall;
SequenceStack loop_stack;
int pop_value;
void DFS(int startVertax)
{
	setVisitedFlag(startVertax, 1);
	int nextVertax;
	push_stack(&loop_stack, startVertax);
	nextVertax = firstAdjacentVertax(startVertax);
	innerStep++;
	for( ; ; )
	{
		if( nextVertax != -1 )
		{
			if( visitedFlag[nextVertax] == 1 && nextVertax == heap && innerStep == 2 )
			{
				nextVertax = nextAdjacentVertax(startVertax, nextVertax);
				continue;
			}
			else if( visitedFlag[nextVertax] == 1 && nextVertax == heap && innerStep != 2 )
			{
				print_stack(loop_stack);
				nextVertax = nextAdjacentVertax(startVertax, nextVertax);
				continue;
			}
			else if( visitedFlag[nextVertax] == 0 )
			{
				DFS(nextVertax);
			}
			if( isRecall == 1 )
			{
				innerStep--;
				temp = nextVertax;
				nextVertax = nextAdjacentVertax(startVertax, nextVertax);
				pop_stack(&loop_stack, &pop_value);
				setVisitedFlag(temp, 0);
				isRecall = 0;
				continue;
			}
			nextVertax = nextAdjacentVertax(startVertax, nextVertax);
		}
		else if( nextVertax == -1 )
		{
			isRecall = 1;
			break;
		}
	}
}
void DFSTraverse()
{
	initialVisitedFlagArray();
	initializeSequenceStack(&loop_stack);
	int i;
	for( heap = 1; heap <= vertax_size; heap++ )
	{
		for( i = 1; i <= vertax_size; i++ )
		{
			visitedFlag[i] = 0;
		}
		/*
		printf("print the visitedFlag array: ");
		for( i = 1; i <= vertax_size; i++ )
		{
			printf("%d ", visitedFlag[i]);
		}
		printf("\n");
		*/
		if( visitedFlag[heap] == 0 )
		{
			printf("\n-------------------the loop start and end with %d----------------\n", heap);
			clear_stack(&loop_stack);
			innerStep = 0;
			//printf("isRecall : %d, findLoop : %d, hasOthers : %d\n", isRecall, findLoop, hasOthers);
			isRecall = 0;
			DFS(heap);
		}
	}
}
void initialVisitedFlagArray()
{
	visitedFlag = (int*)malloc(sizeof(int) * (vertax_size + 1));
	if( !visitedFlag )
	{
		printf("visitedFlag* malloc error");
		exit(0);
	}
	int i;
	for( i = 1; i <= vertax_size; i++ )
		visitedFlag[i] = 0;
}
void printVisitedVertax(int vertaxID)
{
	printf("visited: %d \n", vertaxID);
}
void setVisitedFlag(int vertaxID, int value)
{
	visitedFlag[vertaxID] = value;
}
int firstAdjacentVertax(int vertaxID)
{
	int i;
	for( i = 1; i <= vertax_size; i++ )
	{
		if( adjacentMatrix[vertaxID][i] == 1 )
			return i;
	}
	return -1;
}
int nextAdjacentVertax(int vertaxID, int nextVertaxID)
{
	int i;
	for( i = nextVertaxID + 1; i <= vertax_size; i++ )
	{
		if( adjacentMatrix[vertaxID][i] == 1 )
			return i;
	}
	return -1;
}
void initializeSequenceStack(SequenceStack* stack)
{
	stack->base = (int*)malloc(sizeof(int) * (vertax_size + 1));
	if( !stack->base )
	{
		printf("Sequence stack malloc error!\n");
		exit(0);
	}
	stack->top = stack->base;
	stack->stackSize = vertax_size;
}
void pop_stack(SequenceStack* stack, int* value)
{
	if( empty_stack(*stack) == 1 )
	{
		printf("stack is empty , can not to pop!\n");
		exit(0);
	}
	*value = *(--(stack->top));
}
void push_stack(SequenceStack* stack, int value)
{
	*(stack->top) = value;
	(stack->top)++;
}
int empty_stack(SequenceStack stack)
{
	return stack.top == stack.base ? 1 : 0;
}
void print_stack(SequenceStack stack)
{
	int temp = *(stack.base);
	while( stack.top != stack.base )
	{
		printf("%d->", *((stack.base)++));
	}
	printf("%d\n", temp);
}
void clear_stack(SequenceStack* stack)
{
	stack->top = stack->base;
}</span>