鄰接矩陣實現圖的深度優先搜索和廣度優先搜索-C++代碼


一、有向圖概念:


  • 頂點:有向圖的每一個節點
  • 弧:每一條線
    • 弧頭:線的起始點
    • 弧尾:線的結束點
  • 出度/入度:
    • 出度:某一頂點發出去的弧的數量;
    • 入度:某一頂點射入的弧的數量

二、無向圖概念:


  • 鄰接點:存在一條邊連接兩個點
  • 邊:無向圖中的連線;
  • 頂點:圖中的節點;
  • 連通圖:對於圖內每一個頂點都直接或間接存在通往其他頂點的路徑;
  • 完全圖:圖中任一頂點都存在和其他所有頂點的直接連線。邊數 n ( n 1 ) / 2 n(n-1)/2
  • 生成樹:只有最小數量的邊連接每一個頂點生成連通圖。邊數 n 1 n-1 (n為頂點個數)

三、圖存儲結構:


1.存儲結構分類

  • 鄰接矩陣:數組
  • 鄰接表:鏈表-有向圖
  • 十字鏈表:鏈表-有向圖
  • 鄰接多重表:鏈表-無向圖
1.1.鄰接矩陣-數組存儲
  • 無向圖的鄰接矩陣是對稱矩陣
  • 算法實現
struct Node
{
    頂點索引;
    頂點數據;一維數組
}
struct Map
{
    頂點數組;//存儲所有頂點信息
    鄰接矩陣;//存儲頂點間連接關系。二維數組
}
1.2.鄰接表-
  • 鄰接表:
    頂點表示方法:
頂點索引 出弧鏈表頭指針 頂點數據
  • 弧的表示方法
弧頭頂點索引 下一條弧指針 弧數據
  • 鄰接表的表示結構
struct Node
{
    頂點索引
    該頂點弧鏈表頭節點;
    頂點數據;
}
struct Arc
{
    指向的頂點索引
    指向下一條弧的指針
    弧信息
}
struct Map
{
    頂點數組
}
  • 逆鄰接表
頂點索引 入弧鏈表頭指針 頂點數據
  • 弧的表示方法
弧尾頂點索引 下一條弧指針 弧數據
1.3.十字鏈表
1.4.鄰接多重表-

四、圖的遍歷:


  • 深度優先搜索
    • 類似樹的前序遍歷
  • 廣度優先搜索
    • 一層一層的搜索
  • 最小生成樹
    • 實現搜索最小值
    • 普利姆Prim算法
    • 克魯斯卡爾Kruskal算法

五、利用鄰接表實現圖的深度優先搜索和廣度優先搜索(其中深度優先搜索用遞歸方法;廣度優先搜索用隊列非遞歸方法)

PS:鄰接表方法並不合適,因為當圖比較大的時候,會需要很多的連續內存占用,所以應該探索別的存儲方法。

//Node.h
#pragma once
#include<iostream>
using namespace std;
class Node
{
public:
	Node(int d=0);
	~Node();
	int data;
	bool is_vis;
private:
};
//Node.cpp
#include"Node.h"
Node::Node(int d)
{
	data = d;
	is_vis = false;
}
Node::~Node()
{
}

//Graph.h
#pragma once
#include"Node.h"
#include<vector>
class Graph
{
public:
	Graph(int c);
	~Graph();
	bool add_node(Node *n);//增加元素,第幾個增加的元素其序號就為幾,這個要注意。
	bool reset_node();//重置所有元素為未訪問狀態
	void print_matrix();//輸出鄰接矩陣
	bool insert_edge(int row, int column, int wei=1);//增加節點連接關系
	int get_matrix_value(int row, int column);//獲得鄰接矩陣的連接
	void depth_search(int index);//深度優先搜索
	void width_search(int index);//廣度優先搜索
private:
	int capacity;
	int node_count;
	Node* node_array;
	int* node_matrix;
};

//Graph.cpp

#include"Graph.h"
#include<queue>
Graph::Graph(int c)
{
	capacity=c;
	node_count=0;
	node_array=new Node[c];//初始化node數組
	node_matrix=new int[c*c];//n個節點
	memset(node_matrix, 0, c * c * sizeof(int));//初始化
}
bool Graph::add_node(Node* n)
{
		node_array[node_count].data = n->data;//添加順序就是節點編號
		cout << node_count <<" "<< n->data << endl;
		node_count++;
		return true;	
}
void Graph::print_matrix()
{
	for (int i=0;i<capacity;i++)
	{
		for (int j=0;j<capacity;j++)
		{
			cout << node_matrix[i * capacity + j]<<" ";
		}
		cout << endl;
	}
	cout<<"================================================================"<<endl;
}
bool Graph::insert_edge(int row, int column, int wei)
{
	if (row < 0 || row >= capacity) { return false; }
	if (column < 0 || column >= capacity) { return false; }
	node_matrix[row * capacity + column] = wei;
	node_matrix[column * capacity + row] = wei;
	return true;
}
int Graph::get_matrix_value(int row, int column)
{
	if (row < 0 || row >= capacity) { return 0; }
	if (column < 0 || column >= capacity) { return 0; }
	return node_matrix[row * capacity + column];
}
bool Graph::reset_node()
{
	for (int i = 0; i < node_count; i++)
	{
		node_array[i].is_vis = false;
	}
	return true;
}
void Graph::depth_search(int index)
{
	cout << node_array[index].data << " ";
	node_array[index].is_vis = true;
	for (int i = 0; i < capacity; i++)
	{
		if (get_matrix_value(index, i)==1)
		{
			if (!node_array[i].is_vis)
			{
				depth_search(i);
			}
			else
			{
				continue;
			}
		}
	}
}

void Graph::width_search(int index)
{
	cout << node_array[index].data << "\n"<<endl;
	node_array[index].is_vis = true;//第一個節點訪問,並置為已訪問
	queue<int> q;
	q.push(index);
	int pre_q = 1;//統計第一層節點的個數,首節點當然個數為1;
	while (!q.empty())
	{
		int value = 0;
		int cur_q = 0;//記錄下一層元素的個數
		for (int i = 0; i < pre_q; i++)//注意這的截至條件是pre_q,說明每次循環都只會將上一層加入的節點取出,然后保存下一層的節點,根據先進先出原則,正好把上一層的取出完畢
		{
			int num = q.front();//得到先進入的第一個元素
			q.pop();
			for (int j = 0; j < capacity; j++)
			{
				value = node_matrix[num* capacity + j];
				if (value)
				{
					if (!node_array[j].is_vis)//判斷元素是否訪問過。
					{
						cout << node_array[j].data << endl;
						node_array[j].is_vis = true;
						cur_q++;
						q.push(j);//將下一層的節點入隊
					}
				}				
			}
		}
		pre_q = cur_q;//將本層元素個數作為下一層循環的父節點個數
		cout << endl;
	}
	return;
}
Graph::~Graph()
{
	delete[]node_array;
	delete[]node_matrix;
}
//main.cpp
#include"Graph.h"

int main()
{
	Graph g(8);
	Node* n1 = new Node(1);
	Node* n2 = new Node(2);
	Node* n3 = new Node(3);
	Node* n4 = new Node(4);
	Node* n5 = new Node(5);
	Node* n6 = new Node(6);
	Node* n7 = new Node(7);
	Node* n0 = new Node(0);

	g.add_node(n0);
	g.add_node(n1);
	g.add_node(n2);
	g.add_node(n3);
	g.add_node(n4);
	g.add_node(n5);
	g.add_node(n6);
	g.add_node(n7);
	

	//設置連接關系
	g.insert_edge(0, 1);
	g.insert_edge(2, 1);
	g.insert_edge(0, 4);
	g.insert_edge(3, 1);
	g.insert_edge(2, 3);
	g.insert_edge(4, 5);
	g.insert_edge(4, 7);
	g.insert_edge(5, 6);
	g.insert_edge(6, 7);

	g.depth_search(0);
	g.reset_node();
	cout << endl;
	g.width_search(0);
	//寬度遍歷
	return 0;
}







免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM