注:( 深度优先与广度优先的结果不唯一,本文只提供一种解答)
#include <iostream>
#include <iomanip>
using namespace std;
//队列------------------------------------
typedef int QElemType;
const int QUEUE_INIT_SIZE = 100;
const int QUEUEINCREMENT = 10;
typedef struct {
QElemType* data;
int front;
int rear;
int queuesize;
int incresize;
}SqQueue;
bool InitQueue(SqQueue& Q, int = QUEUE_INIT_SIZE, int = QUEUEINCREMENT);//初始化循环队列
int QueueLength(SqQueue Q);//返回队列长度
bool DeQueue(SqQueue& Q, QElemType& e);//将队首元素出队,用e返回
bool EnQueue(SqQueue& Q, QElemType e);//将元素e放入循环队列
bool GetHead(SqQueue Q, QElemType& e);//取队首元素,用e返回
bool incrementQueuesize(SqQueue& Q);//当循环队列空间不足时,动态扩充空间
bool QueueEmpty(SqQueue Q);//判断队列是否为空
bool InitQueue(SqQueue& Q, int maxsize, int incresize) {
Q.data = new QElemType[maxsize];
if (!Q.data)return 0;
Q.front = Q.rear = 0;
Q.queuesize = maxsize;
Q.incresize = incresize;
return 1;
}
int QueueLength(SqQueue Q) {
return (Q.rear - Q.front + Q.queuesize) % Q.queuesize;
}
bool DeQueue(SqQueue& Q, QElemType& e) {
if (Q.front == Q.rear)
return 0;
e = Q.data[Q.front];
Q.front = (Q.front + 1) % Q.queuesize;
return 1;
}
bool EnQueue(SqQueue& Q, QElemType e) {
if ((Q.rear + 1) % Q.queuesize == Q.front)
if (!incrementQueuesize(Q))
return 0;
Q.data[Q.rear] = e;
Q.rear = (Q.rear + 1) % Q.queuesize;
return 1;
}
bool GetHead(SqQueue Q, QElemType& e) {
if (Q.rear == Q.front)
return 0;
e = Q.data[Q.front];
return 1;
}
bool incrementQueuesize(SqQueue& Q) {
QElemType* newdata = new QElemType[Q.queuesize + Q.incresize];
if (!newdata)return 0;
for (int i = 0; i < Q.queuesize; i++)
newdata[i] = Q.data[(Q.front + i) % Q.queuesize];
delete[] Q.data;
Q.data = newdata;
Q.front = 0; Q.rear = Q.queuesize - 1;
Q.queuesize += Q.incresize;
return 1;
}
bool QueueEmpty(SqQueue Q) {
if (Q.front == Q.rear)
return 1;
return 0;
}
//栈--------------------------------------
typedef int SElemType;
typedef struct StackNode {
SElemType data;
struct StackNode* next;
}StackNode, * LinkStack;
bool InitStack(LinkStack& S);//初始化链栈
bool Push(LinkStack& S, SElemType e);//将元素e压入栈中
bool Pop(LinkStack& S, SElemType& e);//将首元素出栈,用元素e返回
bool StackEmpty(LinkStack S);//判断链栈是否为空
bool GetTop(LinkStack S, SElemType& e);//取链栈栈顶元素,用元素e返回
bool InitStack(LinkStack& S) {
S = NULL;
return 1;
}
bool Push(LinkStack& S, SElemType e) {
StackNode* temp = new StackNode;
if (!temp)return 0;
temp->data = e;
temp->next = S;
S = temp;
return 1;
}
bool Pop(LinkStack& S, SElemType& e) {
if (S == NULL)return 0;
StackNode* temp = S;
e = S->data;
S = S->next;
delete temp;
return 1;
}
bool StackEmpty(LinkStack S) {
if (S == NULL)
return 1;
return 0;
}
bool GetTop(LinkStack S, SElemType& e) {
if (S == NULL)return 0;
e = S->data;
return 1;
}
//图-----------------------------------
const int MAX_VERTEX_NUM = 20;
typedef char VexType;//结点类型
typedef struct ArcNode {
int adjvex; //表内结点的点域部分,存储此处的顶点值
struct ArcNode* nextarc; //表示此处顶点指向下一处顶点的弧
}ArcNode;
typedef struct VNode {//顶点表结点
VexType data; //顶点信息
ArcNode* firstarc; //指向第一个表内结点的首指针
}VNode, AdjList[MAX_VERTEX_NUM];//顶点表,按位次存储所有结点
typedef struct {
AdjList vertices;//顶点表
int vexnum, arcnum; //图的当前顶点数和弧数
}ALGraph;
bool visited[MAX_VERTEX_NUM];//记录结点是否被访问过
void CreateAG(ALGraph& G);//建立无向图
void PrintALGraph(ALGraph G);
void DFS(ALGraph G, int i);//从结点i开始进行深度优先遍历
void DFSTraverse(ALGraph G);//深度优先遍历
void BFSTraverse(ALGraph G);//广度优先遍历
int LocateVex(ALGraph G, char v);//接收结点v,将他转变为在表中的位次,便于程序计算
void CreateAG(ALGraph& G) {
char v1, v2;//接收输入顶点,在LocateVex中转为位次
ArcNode* pi, * pj;//pi指结点i指向的结点,pj指结点j指向的结点
cout << "请依次输入图G的顶点数、弧数:";
cin >> G.vexnum >> G.arcnum;
cout << "请输入各顶点信息:";
for (int i = 0; i < G.vexnum; i++) { //建立顶点表,依次输入顶点值
cin >> G.vertices[i].data; //输入顶点值
G.vertices[i].firstarc = NULL; //初始化链表头指针为空
}
cout << "请输入活动起始点、终止点:" << endl;
for (int k = 0; k < G.arcnum; k++) {//按照边数,将每条边都输入
cin >> v1 >> v2;
int i = LocateVex(G, v1);
int j = LocateVex(G, v2);
//以下插入方式类似于单链表头插法
pi = new ArcNode; pi->adjvex = j; //结点i指向的点是结点j
pi->nextarc = G.vertices[i].firstarc;//结点i指向的点的next点仍是结点i指向的点
G.vertices[i].firstarc = pi; //更新G.vertices[i]首指针
//无向图a指向b的同时b也指向a
pj = new ArcNode; pj->adjvex = i; //结点j指向的点是结点i
pj->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = pj; //更新G.vertices[j]首指针
}
}
int LocateVex(ALGraph G, char v) {
for (int i = 0; i < G.vexnum; i++)
if (G.vertices[i].data == v)
return i;
return -1;
}
void PrintALGraph(ALGraph G) {
for (int i = 0; i < G.vexnum; i++) {
cout << G.vertices[i].data << "->";
ArcNode* p = G.vertices[i].firstarc;
while (p) {
cout << p->adjvex << " ";
p = p->nextarc;
}
cout << endl;
}
}
void DFSTraverse(ALGraph G) {
int i;
for (i = 0; i < G.vexnum; i++)//将所有结点初始化为false,即未访问
visited[i] = false;
for (i = 0; i < G.vexnum; i++)
{
if (!visited[i])//从一未被访问的结点开始进行深度优先遍历
DFS(G, i);
}
}
void DFS(ALGraph G, int i) {
LinkStack S; InitStack(S); int temp;
ArcNode* p;
Push(S, i); visited[i] = true; //布置初始任务
//此处循环流程建议对照实验样例的邻接表观察,有助于理解
while (!StackEmpty(S)) { //过程为将一点的所有相连的未访问点入栈,并选择其中第一个点继续深入并重复上述操作,直到抵达
//一条路径的最后一点后退栈探索另一条路径重复上述操作直到栈空结束循环
Pop(S, i);//废物利用,让i来接收弹出的值
cout << setw(3) << G.vertices[i].data;//上述过程中,选择一点继续深入操作所提到的点就是整体深度优先遍历访问的中间点
for (p = G.vertices[i].firstarc; p; p = p->nextarc) {//将与此时p指向点相连的所有未访问点全部入栈并标为访问过
temp = p->adjvex;
if (visited[temp] == false) {
visited[temp] = true;
Push(S, temp);
}
}//for
}//while
}
void BFSTraverse(ALGraph G) {
SqQueue Q; InitQueue(Q, G.vexnum); //附设循环队列Q
ArcNode* p, q;
int temp;//用于接收临时数据
for (int i = 0; i < G.vexnum; i++) //将所有结点初始化为false,即未访问
visited[i] = false;
for (int i = 0; i < G.vexnum; i++)
if (!visited[i]) {//若已被访问过,则不执行
visited[i] = true;
EnQueue(Q, i); //i入队列
while (!QueueEmpty(Q)) {
DeQueue(Q, temp); //队头元素出队并用temp接收
cout << setw(3) << G.vertices[temp].data;
for ( ArcNode* p = G.vertices[temp].firstarc; p; p = p->nextarc) {//将一层压入队列
if (!visited[p->adjvex]) {
visited[p->adjvex] = true;
EnQueue(Q, p->adjvex);
}
}
}
}
}
int main()
{
ALGraph G;
cout << "*****构造无向图(邻接表)*****" << endl;
CreateAG(G);
cout << "*******该图的邻接表为:*******" << endl;
PrintALGraph(G);
cout << "*******深度优先搜索*******" << endl;
DFSTraverse(G);
cout << endl;
cout << "*******广度优先搜索*******" << endl;
BFSTraverse(G);
cout << endl;
return 0;
}
实验样例