算法與數據結構(13): 圖(1)——圖的存儲及遍歷

在這裏插入圖片描述

注:轉載請標明原文出處鏈接:https://xiongyiming.blog.csdn.net/article/details/100918881


1 圖簡介

圖 (Graph) 結構是一種非線性的數據結構,圖在實際生活中有很多例子,比如交通運輸網,地鐵網絡,社交網絡,計算機中的狀態執行(自動機)等等都可以抽象成圖結構。圖結構比樹結構複雜的非線性結構。
圖分爲 有向圖無向圖,如下圖所示:

在這裏插入圖片描述

有向圖,如下圖所示,對於頂點V1:初度=2,入度=1.
弧:有向圖中頂點和頂點之間的連線。

在這裏插入圖片描述


無向圖,如下圖所示:
邊:無向圖中,頂點和頂點之間的連線。

在這裏插入圖片描述


在這裏插入圖片描述


在這裏插入圖片描述


在這裏插入圖片描述


在這裏插入圖片描述



2 圖的存儲

要想使用圖去解決實際問題,那麼就需要知道,圖是如何進行存儲的。
在存儲有向圖和無向圖有一定的差別。

在這裏插入圖片描述


如下圖所示,圖的存儲結構有:鄰接矩陣、鄰接表、十字鏈表和鄰接多重表。其中,鄰接矩陣使用數組表示,主要表達無向圖和有向圖;而鄰接表和十字鏈表使用鏈表進行表示,主要表達有向圖。鄰接多重表使用鏈表進行表示,主要表達無向圖。

在這裏插入圖片描述


在這裏插入圖片描述



2.1 鄰接矩陣——數組

鄰接矩陣由數組進行存儲.

在這裏插入圖片描述

對於有向圖:

在這裏插入圖片描述



對於無向圖:

在這裏插入圖片描述


在這裏插入圖片描述

在這裏插入圖片描述




2.2 鄰接表——鏈表

鄰接表由鏈表進行存儲.

在這裏插入圖片描述


在這裏插入圖片描述

在這裏插入圖片描述




2.3 十字鏈表——鏈表

十字鏈表由鏈表進行存儲.

在這裏插入圖片描述


在這裏插入圖片描述




2.4 鄰接多重表——鏈表

在這裏插入圖片描述


在這裏插入圖片描述

在這裏插入圖片描述



2.5 圖的遍歷

圖的遍歷分爲:深度優先搜索 和 廣度優先搜索


(1) 深度優先搜索

相當於前序遍歷

在這裏插入圖片描述



(2) 廣度優先搜索

在這裏插入圖片描述



(3) 代碼示例

要求

圖的遍歷
深度優先遍歷

廣度優先遍歷
在這裏插入圖片描述


Node.h

#pragma once

class Node
{
public:
	Node(char data = 0);
	char m_cData;
	bool m_bIsVisited;
};

Node.cpp

#include<iostream>
#include"Node.h"
using namespace std;

Node::Node(char data)
{
	m_cData = data;
	m_bIsVisited = false;
}

CMap.h

#pragma once
#include<iostream>
#include<vector>
#include"Node.h"
using namespace std;

class CMap
{
public:
	CMap(int capacity);
	~CMap();
	bool addNote(Node *pNode);
	void resetNode();
	bool setValueToMatrixForDirectedGraph(int row, int col, int val = 1);//爲有向圖設置鄰接矩陣
	bool setValueToMatrixForUndirectedGraph(int row, int col, int val = 1);//爲無向圖設置鄰接矩陣

	void printMatrix();//打印鄰接矩陣

	void depthFristTraverse(int nodeIndex);//深度優先遍歷
	void breadthFirstTraverse(int nodeIndex);//廣度優先遍歷

private:
	bool getValueFromMatrix(int row, int col, int &val);//從矩陣中獲取權值
	void breadthFirstTraverseImpl(vector<int>preVec);//廣度優先遍歷函數

private:
	int m_iCapacity;//圖中最多可以容納的頂點數
	int m_iNodeCount;//已經添加的頂點(結點)個數
	Node *m_pNodeArray;//用來存放頂點數組
	int *m_pMatrix;//用來存放鄰接矩陣
};

CMap.cpp

#include<iostream>
#include<vector>
#include"CMap.h"
using namespace std;

CMap::CMap(int capacity)
{
	m_iCapacity = capacity;
	m_iNodeCount = 0;
	m_pNodeArray = new Node[m_iCapacity];
	m_pMatrix = new int[m_iCapacity*m_iCapacity];
	memset(m_pMatrix, 0, m_iCapacity*m_iCapacity * sizeof(int));

}

CMap::~CMap()
{
	delete[]m_pNodeArray;
	delete[]m_pMatrix;
}

bool CMap::addNote(Node *pNode)
{
	if (pNode == NULL)
	{
		return false;
	}

	m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
	m_iNodeCount++;
	return true;
}

void CMap::resetNode()
{
	for (int i = 0; i < m_iNodeCount; i++)
	{
		m_pNodeArray[i].m_bIsVisited = false;
	}
}

bool CMap::setValueToMatrixForDirectedGraph(int row, int col, int val)
{
	if (row < 0 || row >= m_iCapacity)
	{
		return false;
	}
	if (col < 0 || col >= m_iCapacity)
	{
		return false;
	}
	
	m_pMatrix[row*m_iCapacity + col] = val;
	return true;
}


bool CMap::setValueToMatrixForUndirectedGraph(int row, int col, int val)
{
	if (row < 0 || row >= m_iCapacity)
	{
		return false;
	}
	if (col < 0 || col >= m_iCapacity)
	{
		return false;
	}

	m_pMatrix[row*m_iCapacity + col] = val;
	m_pMatrix[col*m_iCapacity + row] = val;
	return true;
}



bool CMap::getValueFromMatrix(int row, int col, int &val)//從矩陣中獲取權值
{
	if (row < 0 || row >= m_iCapacity)
	{
		return false;
	}
	if (col < 0 || col >= m_iCapacity)
	{
		return false;
	}

	val = m_pMatrix[row*m_iCapacity + col];
	return true;
}

void CMap::printMatrix()//打印鄰接矩陣
{
	for (int i = 0; i < m_iCapacity; i++)
	{
		for (int k = 0; k < m_iCapacity; k++)
		{
			cout << m_pMatrix[i*m_iCapacity + k] << " ";
		}
		cout << endl;
	}
}

//深度優先遍歷
void CMap::depthFristTraverse(int nodeIndex)
{
	int value = 0;
	cout << m_pNodeArray[nodeIndex].m_cData << " ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;

	//通過鄰接矩陣判斷是否與其他的頂點有連接
	for (int i = 0; i < m_iCapacity; i++)
	{
		getValueFromMatrix(nodeIndex, i, value);
		if (value != 0)
		{
			//再判斷該點是否被訪問過
			if (m_pNodeArray[i].m_bIsVisited)
			{
				continue;
			}
			else
			{
				depthFristTraverse(i);//遞歸
			}
		}

	}


}

//廣度優先遍歷
void CMap::breadthFirstTraverse(int nodeIndex)
{
	cout << m_pNodeArray[nodeIndex].m_cData << " ";
	m_pNodeArray[nodeIndex].m_bIsVisited = true;

	vector<int>curVec;
	curVec.push_back(nodeIndex);

	breadthFirstTraverseImpl(curVec);
}



//廣度優先遍歷函數
void CMap::breadthFirstTraverseImpl(vector<int>preVec)
{
	int value = 0;
	vector<int>curVec;
	for (int j = 0; j < (int)preVec.size(); j++)
	{
		for (int i = 0; i <= m_iCapacity; i++)
		{
			getValueFromMatrix(preVec[j], i, value);
			if (value != 0)
			{
				//再判斷該點是否被訪問過
				if (m_pNodeArray[i].m_bIsVisited)
				{
					continue;
				}
				else
				{
					cout << m_pNodeArray[i].m_cData << " ";
					m_pNodeArray[i].m_bIsVisited = true;

					curVec.push_back(i);
				}
			}
			

		}
	}

	if (curVec.size() == 0)
	{
		return;
	}
	else
	{
		breadthFirstTraverseImpl(curVec);
	}

}

main.cpp

#include<iostream>
#include<vector>
#include"CMap.h"
#include"Node.h"
using namespace std;

/*******************************************
圖的遍歷
深度優先遍歷

廣度優先遍歷

      A
      / \
    B   D
    /\   /\
  C  F  G H
    \ /
    E



**********************************************/

int main()
{
	CMap *pMap = new CMap(8);

	Node *pNodeA = new Node('A');
	Node *pNodeB = new Node('B');
	Node *pNodeC = new Node('C');
	Node *pNodeD = new Node('D');
	Node *pNodeE = new Node('E');
	Node *pNodeF = new Node('F');
	Node *pNodeG = new Node('G');
	Node *pNodeH = new Node('H');

	pMap->addNote(pNodeA);
	pMap->addNote(pNodeB);
	pMap->addNote(pNodeC);
	pMap->addNote(pNodeD);
	pMap->addNote(pNodeE);
	pMap->addNote(pNodeF);
	pMap->addNote(pNodeG);
	pMap->addNote(pNodeH);

	pMap->setValueToMatrixForUndirectedGraph(0, 1);
	pMap->setValueToMatrixForUndirectedGraph(0, 3);
	pMap->setValueToMatrixForUndirectedGraph(1, 2);
	pMap->setValueToMatrixForUndirectedGraph(1, 5);
	pMap->setValueToMatrixForUndirectedGraph(3, 6);
	pMap->setValueToMatrixForUndirectedGraph(3, 7);
	pMap->setValueToMatrixForUndirectedGraph(6, 7);
	pMap->setValueToMatrixForUndirectedGraph(2, 4);
	pMap->setValueToMatrixForUndirectedGraph(4, 5);

	pMap->printMatrix();
	cout << endl;


	//深度優先遍歷
	pMap->resetNode();
	cout << "深度優先遍歷: " ;
	pMap->depthFristTraverse(0);
	cout << endl;

	cout << endl;


	//廣度優先遍歷
	pMap->resetNode();
	cout << "廣度優先遍歷: " ;
	pMap->breadthFirstTraverse(0);
	cout << endl;


	cin.get();
	return 0;
}

運行結果

在這裏插入圖片描述



3 最小生成樹




參考資料

[1] 數據結構探險之圖篇

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章