前言:BFS廣度優先遍歷-尋找最短路徑學習和實現筆記
dijkstra是bfs的升級版,就是說如果求最短路徑,當圖從無權值變成有權值時,bfs不再適用了,於是我們用dijkstra方法。換句話說,對於無權值圖,dijkstra方法跟bfs是一致的。你可以畫個無權圖,用dijkstra走一遍,發現其實這就是bfs。
這里舉個例子,就比如如下圖所示,如果是從G港開始走的話,那么想要求到R城的最短路徑,如果是BFS的話那么直接就是G-R之間最短,但是實際上在有權圖中的話,G-P-R才是最短的,當用dijkstra算法來尋找的時候,dijkstra算法能夠算出帶有有權值的圖的最短路徑!
其實之前已經實現過關於圖的BFS廣度優先遍歷算法了,其中在尋找最短路徑實現,只需要加以修改一點內容即可
這里需要多創建一個結構體來記錄每次遍歷完當前頂點的鄰接矩陣,然后需要從一個頂點到另外一個頂點之間的路徑距離
其實就是只需要在每次在判斷當前頂點的鄰接頂點的時候,通過結構體來判斷與當前頂點之間的距離即可,然后再每次頂點與原頂點的基礎上再加上指定頂點到當前頂點的距離
typedef struct _VexPath{
int pathValue; // 路徑長度
int preVex; // 前驅節點
}VexPath;
這樣說可以不太好理解,這里通過一個圖來進行觀察演示,初始狀態如下,如下圖所示,因為這里找的是從頂點2出發,頂點2和自身的距離是0,所以這里距離就設置為0
-
這里要找的是從頂點2出發,來找無權圖之間各個頂點之間的最短路徑
-
首先與頂點2相鄰的頂點有頂點1和頂點6,那么就會將頂點1和頂點6對應的距離+1,並且將頂點1和頂點6的前驅節點設置為頂點2的下標,這里通過隊列來進行存儲頂點1和頂點6
- 接着第二次的時候,隊列中取出頂點1來進行上述一樣的操作,直到隊列中的元素為空
比如BFS優先遍歷和尋找最短路徑的區別代碼如下所示:
BFS尋找最短路徑實現
最終的實現代碼如下
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define OK 1
#define ERROR 0
#define MAX 32676
typedef int ElemType;
typedef int Status;
typedef char VexType;
typedef struct _Graph
{
int vexNum;
int arcNum;
int** arcs;
char* vexs;
}Graph, *PGraph;
typedef struct _SQueue{
ElemType* pQueue;
int rear;
int front;
int currentLength;
int initLength;
}SQueue, *PSQueue;
Status initQueue(SQueue* psQueue, int iSize)
{
if (psQueue == NULL)
return ERROR;
psQueue->pQueue = (ElemType*)malloc(iSize*sizeof(int));
psQueue->front = 0;
psQueue->rear = 0;
psQueue->currentLength = 0;
psQueue->initLength = iSize;
return OK;
}
Status insertQueueElement(SQueue* psQueue, ElemType elem)
{
if (psQueue->currentLength == psQueue->initLength)
return ERROR;
psQueue->pQueue[(psQueue->rear) % psQueue->initLength] = elem;
psQueue->currentLength++;
psQueue->rear = (psQueue->rear + 1) % psQueue->initLength;
return OK;
}
int getQueueCurrentLength(SQueue* psQueue)
{
return psQueue->currentLength;
}
ElemType deleteQueueElement(SQueue* psQueue)
{
ElemType elem;
if (getQueueCurrentLength(psQueue) == 0)
return ERROR;
elem = psQueue->pQueue[psQueue->front];
psQueue->currentLength--;
psQueue->front = (psQueue->front + 1) % psQueue->initLength;
return elem;
}
ElemType getHeadQueueElement(SQueue* psQueue)
{
if (psQueue->currentLength != psQueue->initLength)
return ERROR;
return psQueue->pQueue[psQueue->front];
}
void travelQueueElement(SQueue* psQueue)
{
while (psQueue->currentLength != 0)
{
printf("current elem -> %d\n", deleteQueueElement(psQueue));
}
}
Status isQueueEmpty(SQueue* psQueue)
{
if (psQueue->front == psQueue->rear)
return OK;
return ERROR;
}
Graph* initGraph(int vexNum)
{
Graph* pGraph = NULL;
if (pGraph == NULL)
{
pGraph = (Graph*)malloc(sizeof(Graph));
memset(pGraph, 0, sizeof(Graph));
if (pGraph == NULL)
return NULL;
pGraph->vexNum = vexNum; //
pGraph->vexs = (char*)malloc(sizeof(pGraph->vexNum));
memset(pGraph->vexs, 0, sizeof(pGraph->vexNum));
pGraph->arcNum = 0; //
pGraph->arcs = (int**)malloc(sizeof(int*)* pGraph->vexNum);
memset(pGraph->arcs, sizeof(int*)* pGraph->vexNum, 0);
for (int i = 0; i < pGraph->vexNum; i++)
{
pGraph->arcs[i] = (int*)malloc(sizeof(int)* pGraph->vexNum);
memset(pGraph->arcs[i], 0, sizeof(int)*pGraph->vexNum);
}
}
return pGraph;
}
Status createGraph(Graph** pGraph, char* vexs, int* arcs)
{
if (*pGraph == NULL)
return ERROR;
for (int i = 0; i<(*pGraph)->vexNum; i++)
{
*((*pGraph)->vexs + i) = *(vexs + i);
for (int j = 0; j<(*pGraph)->vexNum; j++)
{
(*pGraph)->arcs[i][j] = *(arcs + i*((*pGraph)->vexNum) + j);
printf("%d ", (*pGraph)->arcs[i][j]);
if ((*pGraph)->arcs[i][j] == 1)
(*pGraph)->arcNum++;
}
printf("\n");
}
(*pGraph)->arcNum /= 2;
return OK;
}
// BFS廣度優先遍歷算法的實現
// 實現的思路其實跟樹的層序遍歷是一樣的
// 當遍歷的一個點之后
Status BFS(Graph* pGraph, int* iVisitedArray, int visitedIndex)
{
SQueue sQueue;
if (pGraph == NULL)
return ERROR;
initQueue(&sQueue, 10);
iVisitedArray[visitedIndex] = 1;
insertQueueElement(&sQueue, pGraph->vexs[visitedIndex]);
while (!isQueueEmpty(&sQueue))
{
ElemType elem = deleteQueueElement(&sQueue);
printf("%c ", elem);
for (int i = 0;i<pGraph->vexNum;i++)
{
for (int j = 0;j<pGraph->vexNum;j++)
{
if (pGraph->arcs[i][j] == 1 && !iVisitedArray[j])
{
iVisitedArray[j] = 1;
insertQueueElement(&sQueue, pGraph->vexs[j]);
}
}
}
}
return OK;
}
typedef struct _VexPath{
int preVex;
int pathValue;
}VexPath;
VexPath* initVexPath(Graph* pGraph)
{
VexPath* pVexPath = (VexPath*)malloc(sizeof(VexPath) * pGraph->vexNum);
for(int i=0;i<pGraph->vexNum;i++)
{
pVexPath[i].preVex = MAX;
pVexPath[i].pathValue = -1;
}
return pVexPath;
}
void getShort(Graph* pGraph, VexPath* pVexPath, int* iVisitedArray, int visitedIndex)
{
SQueue sQueue;
initQueue(&sQueue, 10);
iVisitedArray[visitedIndex] = 1;
pVexPath[visitedIndex].pathValue = 0;
insertQueueElement(&sQueue, visitedIndex);
while (!isQueueEmpty(&sQueue))
{
visitedIndex = deleteQueueElement(&sQueue);
for (int i = 0;i<pGraph->vexNum;i++)
{
if (pGraph->arcs[visitedIndex][i] == 1 && !iVisitedArray[i])
{
pVexPath[i].pathValue = pVexPath[visitedIndex].pathValue+1;
pVexPath[i].preVex = visitedIndex;
iVisitedArray[i] = 1;
insertQueueElement(&sQueue, i);
}
}
}
printf("vexs -- pathValue -- preVex\n");
for(int i=0;i<pGraph->vexNum;i++)
printf("%c -- %d -- %c\n", pGraph->vexs[i], pVexPath[i].pathValue, pGraph->vexs[pVexPath[i].preVex]);
}
// get vex1 how to go vex2
void getVexShortPath(Graph* pGraph, VexPath* pVexPath, int vexIndex1, int vexIndex2)
{
int iPreVex;
int vexIndex1Value = pVexPath[vexIndex1].pathValue;
printf("the shortest path %c - %c is --------- %c <- ", pGraph->vexs[vexIndex1], pGraph->vexs[vexIndex2], pGraph->vexs[vexIndex2]);
iPreVex = pVexPath[vexIndex2].preVex;
for (int i = 0;i<8;i++)
{
printf("%c <- ", pGraph->vexs[iPreVex]);
iPreVex = pVexPath[iPreVex].preVex;
if (pVexPath[iPreVex].pathValue == vexIndex1Value)
break;
}
printf("%c\n", pGraph->vexs[vexIndex1]);
}
int main()
{
int visited[8] = { 0 };
int initArcs[8][8] =
{
0, 1, 0, 0, 1, 0, 0, 0,
1, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 1, 0, 1, 1, 0,
0, 0, 1, 0, 0, 0, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 0, 0, 1, 0,
0, 0, 1, 1, 0, 1, 0, 1,
0, 0, 0, 1, 0, 0, 1, 0,
};
char initVexs[9] = "12345678";
Graph* pGraph = initGraph(8);
createGraph(&pGraph, initVexs, (int*)initArcs);
VexPath* pVexPath = initVexPath(pGraph);
getShort(pGraph, pVexPath, visited, 1);
printf("\n");
getVexShortPath(pGraph,pVexPath, 1, 7 );
return 0;
}